[PATCH] argv_split: Return NULL if argument contains no non-whitespace.

From: Tetsuo Handa
Date: Sat Sep 14 2013 - 03:37:02 EST


>From 210f917f3b535bc0d4dcbb20ca4395709e913104 Mon Sep 17 00:00:00 2001
From: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
Date: Sat, 14 Sep 2013 16:24:07 +0900
Subject: [PATCH] argv_split: Return NULL if argument contains no non-whitespace.

I tried

# echo '|' > /proc/sys/kernel/core_pattern

and got

BUG: unable to handle kernel NULL pointer dereference at (null)

upon core dump because helper_argv[0] == NULL at

helper_argv = argv_split(GFP_KERNEL, cn.corename, NULL);
call_usermodehelper_setup(helper_argv[0], ...);

if cn.corename == "".

How to check this bug:

# echo '|' > /proc/sys/kernel/core_pattern
$ echo 'int main(int argc, char *argv[]) { return *(char *) 0; }' | gcc -x c - -o die
$ ulimit -c unlimited
$ ./die

This bug seems to exist since 2.6.19 (the version which core dump to pipe was
added). Depending on kernel version and config, some side effect might follow
immediately after this oops (e.g. kernel panic with 2.6.32-358.18.1.el6).

Assuming that nobody is expecting that argv_split() returns an array with
argv[0] == NULL, this patch fixes this bug by changing argv_split() to return
NULL if argument contains no non-whitespace.

Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
---
lib/argv_split.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/lib/argv_split.c b/lib/argv_split.c
index e927ed0..5b828d9 100644
--- a/lib/argv_split.c
+++ b/lib/argv_split.c
@@ -50,7 +50,7 @@ EXPORT_SYMBOL(argv_free);
* quote processing is performed. Multiple whitespace characters are
* considered to be a single argument separator. The returned array
* is always NULL-terminated. Returns NULL on memory allocation
- * failure.
+ * failure or @str being empty or @str containing only white-space.
*
* The source string at `str' may be undergoing concurrent alteration via
* userspace sysctl activity (at least). The argv_split() implementation
@@ -68,6 +68,10 @@ char **argv_split(gfp_t gfp, const char *str, int *argcp)
return NULL;

argc = count_argc(argv_str);
+ if (!argc) {
+ kfree(argv_str);
+ return NULL;
+ }
argv = kmalloc(sizeof(*argv) * (argc + 2), gfp);
if (!argv) {
kfree(argv_str);
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/