Pass correct length to strnlen_user in fs/exec.c
Subsystems (2)
PATCH 1/1 Pass correct length to strnlen_user in fs/exec.c
Mail client was still mis-behaving. Should be fixed now.
---
Replace valid_arg_len function in fs/exec.c with max_arg_len function and pass the correct length to strnlen_user.
---
fs/exec.c +8 -7
@@ -296,9 +296,9 @@ err: return err; } -static bool valid_arg_len (struct linux_binprm *bprm,long len) +static long max_arg_len (struct linux_binprm *bprm) { -return len <=MAX_ARG_STRLEN ; +return MAX_ARG_STRLEN ; }#else
@@ -354,9 +354,9 @@ static int __bprm_mm_init(struct linux_binprm *bprm) return 0; } -static bool valid_arg_len (struct linux_binprm *bprm,long len) +static long max_arg_len (struct linux_binprm *bprm) { -return len <= bprm->p; +return bprm->p; }#endif /* CONFIG_MMU */
@@ -474,18 +474,19 @@ static int copy_strings(int argc, struct user_arg_ptr argv,const char __user *str;int len;unsigned long pos; +long max_len =max_arg_len (bprm); ret = -EFAULT ; str =get_user_arg_ptr (argv, argc);if (IS_ERR (str)) goto out; - len =strnlen_user (str,MAX_ARG_STRLEN ); -if (!len || len >MAX_ARG_STRLEN ) + len =strnlen_user (str, max_len); +if (!len) goto out; ret = -E2BIG ; -if (!valid_arg_len (bprm, len)) +if (len > max_len) goto out;/* We're going to work our way backwords. */
Quoted 42 lines · On Thu, 08 Sep 2011 10:39:24 +1000 Ryan Mallon <[email protected]> wrote:
Replace
valid_arg_lenfunction infs/exec.cwithmax_arg_lenfunction and pass the correct length tostrnlen_user.fs/exec.c +5
-6@@ -296,9 +296,9 @@ err: return err; } -static bool valid_arg_len (struct linux_binprm *bprm,long len) +static long max_arg_len (struct linux_binprm *bprm) { -return len <=MAX_ARG_STRLEN ; +return MAX_ARG_STRLEN ; }#else @@ -354,9 +354,9 @@ static int __bprm_mm_init(struct linux_binprm *bprm) return 0; } -static bool valid_arg_len (struct linux_binprm *bprm,long len) +static long max_arg_len (struct linux_binprm *bprm) { -return len <= bprm->p; +return bprm->p; }#endif /* CONFIG_MMU */ @@ -474,18 +474,19 @@ static int copy_strings(int argc, struct user_arg_ptr argv,const char __user *str;int len;unsigned long pos; +long max_len =max_arg_len (bprm); ret = -EFAULT ; str =get_user_arg_ptr (argv, argc);if (IS_ERR (str)) goto out; - len =strnlen_user (str,MAX_ARG_STRLEN ); -if (!len || len >MAX_ARG_STRLEN )
fs/exec.c static int copy_strings(int argc, struct user_arg_ptr argv, · line 492
Quoted 10 lines
fs/exec.c +3
-1+ len =strnlen_user (str, max_len); +if (!len) goto out; ret = -E2BIG ; -if (!valid_arg_len (bprm, len)) +if (len > max_len) goto out;/* We're going to work our way backwords. */
I'm struggling to find a reason to merge this - it churns code around rather pointlessly?
Quoted 49 lines · Andrew Morton
Quoted 46 lines · On Thu, 08 Sep 2011 10:39:24 +1000 Ryan Mallon <[email protected]> wrote:
Replace
valid_arg_lenfunction infs/exec.cwithmax_arg_lenfunction and pass the correct length tostrnlen_user.fs/exec.c +7
-6@@ -296,9 +296,9 @@ err: return err; } -static bool valid_arg_len (struct linux_binprm *bprm,long len) +static long max_arg_len (struct linux_binprm *bprm) { -return len <=MAX_ARG_STRLEN ; +return MAX_ARG_STRLEN ; }#else @@ -354,9 +354,9 @@ static int __bprm_mm_init(struct linux_binprm *bprm) return 0; } -static bool valid_arg_len (struct linux_binprm *bprm,long len) +static long max_arg_len (struct linux_binprm *bprm) { -return len <= bprm->p; +return bprm->p; }#endif /* CONFIG_MMU */ @@ -474,18 +474,19 @@ static int copy_strings(int argc, struct user_arg_ptr argv,const char __user *str;int len;unsigned long pos; +long max_len =max_arg_len (bprm); ret = -EFAULT ; str =get_user_arg_ptr (argv, argc);if (IS_ERR (str)) goto out; - len =strnlen_user (str,MAX_ARG_STRLEN ); -if (!len || len >MAX_ARG_STRLEN ) + len =strnlen_user (str, max_len); +if (!len) goto out;
Quoted 9 lines
fs/exec.c static int copy_strings(int argc, struct user_arg_ptr argv, · line 492
Quoted 6 lines
fs/exec.c +1
-1ret = -E2BIG ; -if (!valid_arg_len (bprm, len)) +if (len > max_len) goto out;/* We're going to work our way backwords. */ I'm struggling to find a reason to merge this - it churns code around rather pointlessly?
That's fine. I originally went looking after a discussion with Mark about the weird strnlen_user semantics and this usage looked incorrect to me because it wasn't obviously checking >= MAX_ARG_STRLEN.
The rework I think makes it a bit more clear and passes the correct max length to strnlen_user. Its a bit odd to pass MAX_ARG_STRLEN and then check if it is longer than bprm->len, and I guess assumes that bprm->len is less than MAX_ARG_STRLEN.
Feel free to drop the patch if you think it is just churn.
~Ryan
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Quoted 6 lines · Ryan Mallon
Quoted 1 line
...
That's fine. I originally went looking after a discussion with Mark about the weird
strnlen_usersemantics and this usage looked incorrect to me because it wasn't obviously checking >=MAX_ARG_STRLEN.
Quoted 6 lines
The rework I think makes it a bit more clear and passes the correct max length to
strnlen_user. Its a bit odd to passMAX_ARG_STRLENand then check if it is longer thanbprm->len, and I guess assumes thatbprm->lenis less thanMAX_ARG_STRLEN.Feel free to drop the patch if you think it is just churn.
As you are already busy with fs/exec.c and strnlen_user, could you please check, if the timerace (argv/envp corruption) using strnlen_user could also be fixed within the same patch (if bug still in kernel). See
https://bugzilla.kernel.org/show_bug.cgi?id=39222
The race occurs when one thread issues exec while another one with shared memory pages is flipping char/0-bytes of the args or envptrs, causing random split (number greater maxargs - no problem, silently droped)/fusion (greater MAX_ARG_STRLEN - might harm dumb programs) or removal of all args including program name on top of new stack when calling via binfmt handlers (might have influenced old ldlinux/libc pre 2009?? when handling suid binaries)
Kind Regards,
Roman
- --
http://www.halfdog.net/
PGP: 156A AE98 B91F 0114 FE88 2BD8 C459 9386 feed a bee -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFOc3tJxFmThv7tq+4RAibwAJ9CmDTlODxFuNR4KrSh9PGjgyXxQwCfeIgo ARy24fJ6DxuKmcPNla6f0lE=
=h1TA
-----END PGP SIGNATURE-----
Quoted 16 lines · halfdog
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1Quoted 11 lines · Ryan Mallon
Quoted 1 line
...
That's fine. I originally went looking after a discussion with Mark about the weird
strnlen_usersemantics and this usage looked incorrect to me because it wasn't obviously checking >=MAX_ARG_STRLEN.The rework I think makes it a bit more clear and passes the correct max length to
strnlen_user. Its a bit odd to passMAX_ARG_STRLENand then check if it is longer thanbprm->len, and I guess assumes thatbprm->lenis less thanMAX_ARG_STRLEN.
Quoted 7 lines
Quoted 1 line
Feel free to drop the patch if you think it is just churn.
As you are already busy with
fs/exec.candstrnlen_user, could you please check, if the timerace (argv/envp corruption) usingstrnlen_usercould also be fixed within the same patch (if bug still in kernel). See
With kernel.org currently being down I cannot see that bug report unfortunately, so I don't know what the bug you are referring to is.
Quoted 7 lines
The race occurs when one thread issues exec while another one with shared memory pages is flipping char/0-bytes of the args or envptrs, causing random split (number greater maxargs - no problem, silently droped)/fusion (greater
MAX_ARG_STRLEN- might harm dumb programs) or removal of all args including program name on top of new stack when calling via binfmt handlers (might have influenced old ldlinux/libc pre 2009?? when handling suid binaries)
It doesn't sound like my patch would have fixed that. The only issue that my patch would have corrected is the case where bprm->len is greater than MAX_ARG_STRLEN. MAX_ARG_STRLEN is pretty big though (32 * PAGE_SIZE), so I don't see that being an issue very often.
~Ryan