On Mon, Aug 31, 2026 at 12:51:47PM +0200, Greg Kroah-Hartman wrote: > The ability to add and remove devices from a driver through the sysfs > "bind" and "unbind" files was created all those decades ago as a way > that kernel developers can iterate faster, and provide a debugging way > for users to attempt to add a new device to a driver without having to > rebuild their kernel. > > This api over the years has been abused and recently come under a major > fuzzing "attack" through tools like syzbot which decided that it would > attempt to just randomly bind any driver to any type of device, causing > loads of unneeded errors and pointless kernel patches to be generated by > unsuspecting new developers. > > Handle all of this by adding a new taint flag, TAINT_FORCED_BIND, which > will be set on the driver if the bind/unbind sysfs files are ever > written to. This lets kernel developers "know" that a user is > attempting to do something that is not normal, and as such, if the > kernel breaks they get to keep the shiny pieces laying around on the > floor. > > The flag is 'Y' which was unused, and can remembered as the user is > "yeeting" the device being operated on here (thrown with force without > regard for the thing being thrown). > > Note, the taint flag gets set _BEFORE_ the bind/unbind callback happens, > as many times crashes/oops/warnings/failures happen within the callback, > and the taint flag needs to be there to show what was being attempted. > If it were to be set after the callback happens, the oops report would > not properly reflect what foolishness was being attempted. > > Fuzzing tools like syzbot, that doesn't have hand-crafted rules to keep > the tool from hitting bind/unbind, should be run with panic_on_taint > enabled so that they fall over and don't continue on, thinking that they > actually found a real issue. > > Userspace operations that rely on the bind/unbind files to work around > the lack of will to upgrade a kernel image to a newer version with > proper support for new devices, or the lack of will to submit valid > device ids to driver authors, will still work properly, but now the > kernel will be flagged in a way that will show that perhaps those users > should reconsider their behavior and work to have the drivers properly > support these devices in a "native" manner. > > Finally, the bind/unbind files can find real use-after-free issues with > some drivers by forcing the process to happen virtually without having > to rely on manual removal processes. Those real bugs should still be > worked on, but by adding this taint flag, developers can more easily > determine bug reports that are actually worth looking at. > > Reviewed-by: Johan Hovold <[email protected]> > Tested-by: Johan Hovold <[email protected]> > Signed-off-by: Greg Kroah-Hartman <[email protected]> > --- > Documentation/admin-guide/tainted-kernels.rst | 52 > ++++++++++++++------------- > drivers/base/bus.c | 3 ++ > include/linux/panic.h | 3 +- > include/trace/events/module.h | 3 +- > kernel/panic.c | 5 +-- > tools/debugging/kernel-chktaint | 8 +++++ > 6 files changed, 46 insertions(+), 28 deletions(-) > > diff --git a/Documentation/admin-guide/tainted-kernels.rst > b/Documentation/admin-guide/tainted-kernels.rst > index 9ead927a37c0..abbf5e3dd749 100644 > --- a/Documentation/admin-guide/tainted-kernels.rst > +++ b/Documentation/admin-guide/tainted-kernels.rst > @@ -79,30 +79,31 @@ which bits are set:: > Table for decoding tainted state > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > > -=== === ====== ======================================================== > -Bit Log Number Reason that got the kernel tainted > -=== === ====== ======================================================== > - 0 G/P 1 proprietary module was loaded > - 1 _/F 2 module was force loaded > - 2 _/S 4 kernel running on an out of specification system > - 3 _/R 8 module was force unloaded > - 4 _/M 16 processor reported a Machine Check Exception (MCE) > - 5 _/B 32 bad page referenced or some unexpected page flags > - 6 _/U 64 taint requested by userspace application > - 7 _/D 128 kernel died recently, i.e. there was an OOPS or BUG > - 8 _/A 256 ACPI table overridden by user > - 9 _/W 512 kernel issued warning > - 10 _/C 1024 staging driver was loaded > - 11 _/I 2048 workaround for bug in platform firmware applied > - 12 _/O 4096 externally-built ("out-of-tree") module was loaded > - 13 _/E 8192 unsigned module was loaded > - 14 _/L 16384 soft lockup occurred > - 15 _/K 32768 kernel has been live patched > - 16 _/X 65536 auxiliary taint, defined for and used by distros > - 17 _/T 131072 kernel was built with the struct randomization plugin > - 18 _/N 262144 an in-kernel test has been run > - 19 _/J 524288 userspace used a mutating debug operation in fwctl > -=== === ====== ======================================================== > +=== === ======= ======================================================== > +Bit Log Number Reason that got the kernel tainted > +=== === ======= ======================================================== > + 0 G/P 1 proprietary module was loaded > + 1 _/F 2 module was force loaded > + 2 _/S 4 kernel running on an out of specification system > + 3 _/R 8 module was force unloaded > + 4 _/M 16 processor reported a Machine Check Exception (MCE) > + 5 _/B 32 bad page referenced or some unexpected page flags > + 6 _/U 64 taint requested by userspace application > + 7 _/D 128 kernel died recently, i.e. there was an OOPS or BUG > + 8 _/A 256 ACPI table overridden by user > + 9 _/W 512 kernel issued warning > + 10 _/C 1024 staging driver was loaded > + 11 _/I 2048 workaround for bug in platform firmware applied > + 12 _/O 4096 externally-built ("out-of-tree") module was loaded > + 13 _/E 8192 unsigned module was loaded > + 14 _/L 16384 soft lockup occurred > + 15 _/K 32768 kernel has been live patched > + 16 _/X 65536 auxiliary taint, defined for and used by distros > + 17 _/T 131072 kernel was built with the struct randomization plugin > + 18 _/N 262144 an in-kernel test has been run > + 19 _/J 524288 userspace used a mutating debug operation in fwctl > + 20 _/Y 1048576 device was manually bound or unbound from a driver > +=== === ======= ======================================================== > > Note: The character ``_`` is representing a blank in this table to make > reading > easier. > @@ -189,3 +190,6 @@ More detailed explanation for tainting > 19) ``J`` if userspace opened /dev/fwctl/* and performed a > FWTCL_RPC_DEBUG_WRITE > to use the devices debugging features. Device debugging features could > cause the device to malfunction in undefined ways. > + > + 20) ``Y`` If userspace wrote to the `bind` or `unbind` sysfs files and > + successfully bound or removed a device from a driver. > diff --git a/drivers/base/bus.c b/drivers/base/bus.c > index d17bd91490ee..c51ad96d4de4 100644 > --- a/drivers/base/bus.c > +++ b/drivers/base/bus.c > @@ -19,6 +19,7 @@ > #include <linux/string.h> > #include <linux/mutex.h> > #include <linux/sysfs.h> > +#include <linux/panic.h> > #include "base.h" > #include "power/power.h" > > @@ -241,6 +242,7 @@ static ssize_t unbind_store(struct device_driver *drv, > const char *buf, > > dev = bus_find_device_by_name(bus, NULL, buf); > if (dev && dev->driver == drv) { > + add_taint_module(drv->owner, TAINT_FORCED_BIND, > LOCKDEP_STILL_OK); > device_driver_detach(dev); > err = count; > } > @@ -264,6 +266,7 @@ static ssize_t bind_store(struct device_driver *drv, > const char *buf, > > dev = bus_find_device_by_name(bus, NULL, buf); > if (dev && driver_match_device(drv, dev)) { > + add_taint_module(drv->owner, TAINT_FORCED_BIND, > LOCKDEP_STILL_OK); > err = device_driver_attach(drv, dev); > if (!err) { > /* success */ > diff --git a/include/linux/panic.h b/include/linux/panic.h > index f1dd417e54b2..8e7250b0e913 100644 > --- a/include/linux/panic.h > +++ b/include/linux/panic.h > @@ -88,7 +88,8 @@ static inline void set_arch_panic_timeout(int timeout, int > arch_default_timeout) > #define TAINT_RANDSTRUCT 17 > #define TAINT_TEST 18 > #define TAINT_FWCTL 19 > -#define TAINT_FLAGS_COUNT 20 > +#define TAINT_FORCED_BIND 20 > +#define TAINT_FLAGS_COUNT 21 > #define TAINT_FLAGS_MAX ((1UL << TAINT_FLAGS_COUNT) - 1) > > struct taint_flag { > diff --git a/include/trace/events/module.h b/include/trace/events/module.h > index e5a006be9dc6..19df3e39bba4 100644 > --- a/include/trace/events/module.h > +++ b/include/trace/events/module.h > @@ -26,7 +26,8 @@ struct module; > { (1UL << TAINT_OOT_MODULE), "O" }, \ > { (1UL << TAINT_FORCED_MODULE), "F" }, \ > { (1UL << TAINT_CRAP), "C" }, \ > - { (1UL << TAINT_UNSIGNED_MODULE), "E" }) > + { (1UL << TAINT_UNSIGNED_MODULE), "E" }, \ > + { (1UL << TAINT_FORCED_BIND), "Y" }) > > TRACE_EVENT(module_load, > > diff --git a/kernel/panic.c b/kernel/panic.c > index 213725b612aa..6bf60f9dd120 100644 > --- a/kernel/panic.c > +++ b/kernel/panic.c > @@ -826,6 +826,7 @@ const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = { > TAINT_FLAG(RANDSTRUCT, 'T', ' '), > TAINT_FLAG(TEST, 'N', ' '), > TAINT_FLAG(FWCTL, 'J', ' '), > + TAINT_FLAG(FORCED_BIND, 'Y', ' '), > }; > > #undef TAINT_FLAG > @@ -862,9 +863,9 @@ static void print_tainted_seq(struct seq_buf *s, bool > verbose) > * exact size is allocated dynamically; the initial buffer remains > * as a fallback if allocation fails. > * > - * The verbose taint string currently requires up to 327 characters. > + * The verbose taint string currently requires up to 344 characters. > */ > -#define INIT_TAINT_BUF_MAX 350 > +#define INIT_TAINT_BUF_MAX 370 > > static char init_taint_buf[INIT_TAINT_BUF_MAX] __initdata; > static char *taint_buf __refdata = init_taint_buf; > diff --git a/tools/debugging/kernel-chktaint b/tools/debugging/kernel-chktaint > index e1571c04afb5..d8628be37214 100755 > --- a/tools/debugging/kernel-chktaint > +++ b/tools/debugging/kernel-chktaint > @@ -211,6 +211,14 @@ else > addout "J" > echo " * fwctl's mutating debug interface was used (#19)" > fi > + > +T=`expr $T / 2` > +if [ `expr $T % 2` -eq 0 ]; then > + addout " " > +else > + addout "Y" > + echo " * device was manually bound or unbound from a driver (#20)" > +fi > echo "Raw taint value as int/string: $taint/'$out'" > > # report on any tainted loadable modules > > -- > 2.55.0 >
Hi Greg, After you replace the accidental comma with a space in the parameter list of add_taint_module() in module.h under !CONFIG_MODULES: Reviewed-by: Aaron Tomlin <[email protected]> Kind regards, -- Aaron Tomlin
