linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: md@Linux.IT (Marco d'Itri)
To: linux-hotplug@vger.kernel.org
Subject: Bug#524940: module-init-tools: modprobe starts fork-bombing on
Date: Wed, 23 Sep 2009 15:30:59 +0000	[thread overview]
Message-ID: <20090923153059.GA17526@bongo.bofh.it> (raw)

[-- Attachment #1: Type: text/plain, Size: 16 bytes --]

-- 
ciao,
Marco

[-- Attachment #2: Type: message/rfc822, Size: 11854 bytes --]

[-- Attachment #2.1.1.1: Type: Text/Plain, Size: 1446 bytes --]

tags 524940 - help
tags 524940 patch
thanks

Hello,

On trečiadienis 05 Rugpjūtis 2009 03:05:06 Marco d'Itri wrote:
> On Aug 05, Eli Mackenzie <eli.mackenzie@gmail.com> wrote:
> > With this bug marked "important", apt-listbugs didn't notify me that
> > there was anything wrong with this package. A failure to boot seems to
> > fit the "makes unrelated software on the system (or the whole system)
> > break" description of "critical" more than "important".
> 
> It only affects a small number of users.
> BTW, the upstream maintainer does not appear to have time to investigate
> this. Feel free to send patches.

The bug can only be reproduced with kernel 2.6.19 or earlier (i.e. the kernel 
in etch). If /sys/module/*/initstate (added in 2.6.20) is not present, current 
modprobe assumes that the module is not loaded. This triggers recursive "fork 
bomb" as modprobe keeps trying to load snd-pcm (i.e. keeps executing that 
custom install command of snd-pcm) again and again. More detailed info about 
this can be found in the patch headers.

To reproduce, either install oss-compat under <= 2.6.19 kernel or reboot to <= 
2.6.19 with oss-compat installed (init=/bin/bash may be helpful to get system 
bootable in this case).

Actually, you need 0002 patch to fix this bug, 0001 is just a safety 
precaution. Please submit both these patches to upstream. Thanks.

-- 
Modestas Vainius <modestas@vainius.eu>

[-- Attachment #2.1.1.2: 0002-Get-module-initstate-from-proc-modules-if-it-is-not-.patch --]
[-- Type: text/x-patch, Size: 3485 bytes --]

From 567f889a3c8d50234abef72b10e3af9312aa808f Mon Sep 17 00:00:00 2001
From: Modestas Vainius <modestas@vainius.eu>
Date: Sun, 20 Sep 2009 14:41:48 +0300
Subject: [PATCH 2/2] Get module initstate from /proc/modules if it is not supported via sysfs.

Get module state from /proc/modules if it is not supported via sysfs.
/sys/module/*/initstate is only available since Linux 2.6.20. Current code
assumes that module is not in the kernel if initstate attribute is absent.
Among other potential problems, this may trigger a "fork bomb" if certain
custom "install" sequences are used for the module and/or its dependencies.
 .
The patch adds a fallback to /proc/modules in order to get the module state if
/sys/module/*/initstate attribute is missing. The code is based on the
module_in_kernel() function from v3.4).

"Fork bombing" side effect of the bug is described in [1]. What's more,
handling of module_in_kernel() failures could still be improved in order avoid
similar problems when /sys is not mounted. Currently, if module_in_kernel()
fails with -1, modprobe assumes the module is not present in the kernel.

1. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=524940

Signed-off-by: Modestas Vainius <modestas@vainius.eu>
---
 modprobe.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/modprobe.c b/modprobe.c
index ec46e0b..06825bd 100644
--- a/modprobe.c
+++ b/modprobe.c
@@ -537,6 +537,42 @@ static int read_attribute(const char *filename, char *buf, size_t buflen)
 	return (s == NULL) ? -1 : 1;
 }
 
+/* Since /sys/module/%s/initstate is only available since 2.6.20,
+   fallback to /proc/modules to get module state on earlier kernels.
+   0 means module is not live, 1 means yes, -1 means unknown.
+ */
+static int proc_is_module_live(const char *modname)
+{
+	FILE *proc_modules;
+	char *line;
+	int i, ret;
+
+	/* Might not be mounted yet.  Don't fail. */
+	proc_modules = fopen("/proc/modules", "r");
+	if (!proc_modules)
+		return -1;
+
+	while ((line = getline_wrapped(proc_modules, NULL)) != NULL) {
+		char *entry = strtok(line, " \n");
+
+		if (entry && streq(entry, modname)) {
+			/* If it exists, initstate is the fifth entry. */
+            for (i = 1; i < 5; i++) {
+				if (!(entry = strtok(NULL, " \n")))
+					break;
+			}
+			ret = !(entry && (streq(entry, "Loading") || streq(entry, "Unloading")));
+
+			free(line);
+			fclose(proc_modules);
+			return ret;
+		}
+		free(line);
+	}
+	fclose(proc_modules);
+	return 0;
+}
+
 /* Is module in /sys/module?  If so, fill in usecount if not NULL. 
    0 means no, 1 means yes, -1 means unknown.
  */
@@ -562,10 +598,20 @@ static int module_in_kernel(const char *modname, unsigned int *usecount)
 
 	/* Wait for the existing module to either go live or disappear. */
 	nofail_asprintf(&name, "/sys/module/%s/initstate", modname);
+	ret = 1;
 	while (1) {
-		ret = read_attribute(name, attr, ATTR_LEN);
-		if (ret != 1 || streq(attr, "live\n"))
-			break;
+		/* If ret == 0 upon second and subsequent cycles,
+		   /sys/module/%s/initstate is not supported. Do not try again. */
+		if (ret != 0)
+			ret = read_attribute(name, attr, ATTR_LEN);
+		if (ret == 1) {
+			if (streq(attr, "live\n"))
+				break;
+		} else {
+			ret = proc_is_module_live(modname);
+			if (ret != 0)
+				break;
+		}
 
 		usleep(100000);
 	}
-- 
1.6.4.3


[-- Attachment #2.1.1.3: 0001-Ignore-custom-install-commands-if-failed-to-find-whe.patch --]
[-- Type: text/x-patch, Size: 2073 bytes --]

From 47a0c951d41f586f4e8dfeef3e770449a0fb2570 Mon Sep 17 00:00:00 2001
From: Modestas Vainius <modestas@vainius.eu>
Date: Sun, 20 Sep 2009 16:15:44 +0300
Subject: [PATCH 1/2] Ignore custom install commands if failed to find whether module is loaded.

This should protect from disastrous consequences like in [1] if for some
reason module_in_kernel() status cannot be determined.

1. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=524940

Signed-off-by: Modestas Vainius <modestas@vainius.eu>
---
 modprobe.c |   16 +++++++++++-----
 1 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/modprobe.c b/modprobe.c
index 21a3111..ec46e0b 100644
--- a/modprobe.c
+++ b/modprobe.c
@@ -1095,6 +1095,7 @@ static int insmod(struct list_head *list,
 	const char *command;
 	struct module *mod = list_entry(list->next, struct module, list);
 	int rc = 0;
+	int isloaded = 0;
 
 	/* Take us off the list. */
 	list_del(&mod->list);
@@ -1122,7 +1123,7 @@ static int insmod(struct list_head *list,
 
 	/* Don't do ANYTHING if already in kernel. */
 	if (!(flags & mit_ignore_loaded)
-	    && module_in_kernel(newname ?: mod->modname, NULL) == 1) {
+	    && (isloaded = module_in_kernel(newname ?: mod->modname, NULL) == 1)) {
 		if (flags & mit_first_time)
 			error("Module %s already in kernel.\n",
 			      newname ?: mod->modname);
@@ -1131,10 +1132,15 @@ static int insmod(struct list_head *list,
 
 	command = find_command(mod->modname, commands);
 	if (command && !(flags & mit_ignore_commands)) {
-		close_file(fd);
-		do_command(mod->modname, command, flags & mit_dry_run, error,
-			   "install", cmdline_opts);
-		goto out_optstring;
+		if (isloaded == -1) {
+			error("Unable to find if module %s is loaded. Assuming --ignore-install.\n",
+			      newname ?: mod->modname);
+		} else {
+			close_file(fd);
+			do_command(mod->modname, command, flags & mit_dry_run, error,
+				   "install", cmdline_opts);
+			goto out_optstring;
+		}
 	}
 
 	module = grab_elf_file_fd(mod->filename, fd);
-- 
1.6.4.3


[-- Attachment #2.1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

             reply	other threads:[~2009-09-23 15:30 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-09-23 15:30 Marco d'Itri [this message]
2009-09-23 21:26 ` Bug#524940: module-init-tools: modprobe starts fork-bombing on Alan Jenkins
2009-09-24  8:02 ` Andreas Robinson
2009-09-24 11:10 ` Alan Jenkins

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090923153059.GA17526@bongo.bofh.it \
    --to=md@linux.it \
    --cc=linux-hotplug@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).