On 26 August 2026 10:19:33 BST, Greg Kroah-Hartman <[email protected]> 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 >successfully 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. > >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. >
sashiko found a couple valid concerns for 2/2 >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..d4ca8b9e3819 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 > > --- Thanks! https://lore.kernel.org/all/[email protected]/
