Skip to content

Commit

Permalink
kmod: fix wait on recursive loop
Browse files Browse the repository at this point in the history
Recursive loops with module loading were previously handled in kmod by
restricting the number of modprobe calls to 50 and if that limit was
breached request_module() would return an error and a user would see the
following on their kernel dmesg:

  request_module: runaway loop modprobe binfmt-464c
  Starting init:/sbin/init exists but couldn't execute it (error -8)

This issue could happen for instance when a 64-bit kernel boots a 32-bit
userspace on some architectures and has no 32-bit binary format
hanlders.  This is visible, for instance, when a CONFIG_MODULES enabled
64-bit MIPS kernel boots a into o32 root filesystem and the binfmt
handler for o32 binaries is not built-in.

After commit 6d7964a ("kmod: throttle kmod thread limit") we now
don't have any visible signs of an error and the kernel just waits for
the loop to end somehow.

Although this *particular* recursive loop could also be addressed by
doing a sanity check on search_binary_handler() and disallowing a
modular binfmt to be required for modprobe, a generic solution for any
recursive kernel kmod issues is still needed.

This should catch these loops.  We can investigate each loop and address
each one separately as they come in, this however puts a stop gap for
them as before.

Link: http://lkml.kernel.org/r/[email protected]
Fixes: 6d7964a ("kmod: throttle kmod thread limit")
Signed-off-by: Luis R. Rodriguez <[email protected]>
Reported-by: Matt Redfearn <[email protected]>
Tested-by: Matt Redfearn <[email protected]>
Cc: "Eric W. Biederman" <[email protected]>
Cc: Colin Ian King <[email protected]>
Cc: Dan Carpenter <[email protected]>
Cc: Daniel Mentz <[email protected]>
Cc: David Binderman <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jessica Yu <[email protected]>
Cc: Josh Poimboeuf <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Michal Marek <[email protected]>
Cc: Miroslav Benes <[email protected]>
Cc: Peter Zijlstra (Intel) <[email protected]>
Cc: Petr Mladek <[email protected]>
Cc: Rusty Russell <[email protected]>
Cc: Shuah Khan <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
mcgrof authored and torvalds committed Aug 18, 2017
1 parent 8ada927 commit 2ba293c
Showing 1 changed file with 23 additions and 2 deletions.
25 changes: 23 additions & 2 deletions kernel/kmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ static DECLARE_RWSEM(umhelper_sem);
static atomic_t kmod_concurrent_max = ATOMIC_INIT(MAX_KMOD_CONCURRENT);
static DECLARE_WAIT_QUEUE_HEAD(kmod_wq);

/*
* This is a restriction on having *all* MAX_KMOD_CONCURRENT threads
* running at the same time without returning. When this happens we
* believe you've somehow ended up with a recursive module dependency
* creating a loop.
*
* We have no option but to fail.
*
* Userspace should proactively try to detect and prevent these.
*/
#define MAX_KMOD_ALL_BUSY_TIMEOUT 5

/*
modprobe_path is set via /proc/sys.
*/
Expand Down Expand Up @@ -167,8 +179,17 @@ int __request_module(bool wait, const char *fmt, ...)
pr_warn_ratelimited("request_module: kmod_concurrent_max (%u) close to 0 (max_modprobes: %u), for module %s, throttling...",
atomic_read(&kmod_concurrent_max),
MAX_KMOD_CONCURRENT, module_name);
wait_event_interruptible(kmod_wq,
atomic_dec_if_positive(&kmod_concurrent_max) >= 0);
ret = wait_event_killable_timeout(kmod_wq,
atomic_dec_if_positive(&kmod_concurrent_max) >= 0,
MAX_KMOD_ALL_BUSY_TIMEOUT * HZ);
if (!ret) {
pr_warn_ratelimited("request_module: modprobe %s cannot be processed, kmod busy with %d threads for more than %d seconds now",
module_name, MAX_KMOD_CONCURRENT, MAX_KMOD_ALL_BUSY_TIMEOUT);
return -ETIME;
} else if (ret == -ERESTARTSYS) {
pr_warn_ratelimited("request_module: sigkill sent for modprobe %s, giving up", module_name);
return ret;
}
}

trace_module_request(module_name, wait, _RET_IP_);
Expand Down

0 comments on commit 2ba293c

Please sign in to comment.