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]/

Reply via email to