Commit 114279be2120a916e8a04feeb2ac976a10016f2f

Authored by Oleg Nesterov
Committed by Linus Torvalds
1 parent 3c77f84572

exec: copy-and-paste the fixes into compat_do_execve() paths

Note: this patch targets 2.6.37 and tries to be as simple as possible.
That is why it adds more copy-and-paste horror into fs/compat.c and
uglifies fs/exec.c, this will be cleanuped later.

compat_copy_strings() plays with bprm->vma/mm directly and thus has
two problems: it lacks the RLIMIT_STACK check and argv/envp memory
is not visible to oom killer.

Export acct_arg_size() and get_arg_page(), change compat_copy_strings()
to use get_arg_page(), change compat_do_execve() to do acct_arg_size(0)
as do_execve() does.

Add the fatal_signal_pending/cond_resched checks into compat_count() and
compat_copy_strings(), this matches the code in fs/exec.c and certainly
makes sense.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: stable@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 23 additions and 17 deletions Side-by-side Diff

... ... @@ -1350,6 +1350,10 @@
1350 1350 argv++;
1351 1351 if (i++ >= max)
1352 1352 return -E2BIG;
  1353 +
  1354 + if (fatal_signal_pending(current))
  1355 + return -ERESTARTNOHAND;
  1356 + cond_resched();
1353 1357 }
1354 1358 }
1355 1359 return i;
... ... @@ -1391,6 +1395,12 @@
1391 1395 while (len > 0) {
1392 1396 int offset, bytes_to_copy;
1393 1397  
  1398 + if (fatal_signal_pending(current)) {
  1399 + ret = -ERESTARTNOHAND;
  1400 + goto out;
  1401 + }
  1402 + cond_resched();
  1403 +
1394 1404 offset = pos % PAGE_SIZE;
1395 1405 if (offset == 0)
1396 1406 offset = PAGE_SIZE;
1397 1407  
... ... @@ -1407,21 +1417,11 @@
1407 1417 if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
1408 1418 struct page *page;
1409 1419  
1410   -#ifdef CONFIG_STACK_GROWSUP
1411   - ret = expand_stack_downwards(bprm->vma, pos);
1412   - if (ret < 0) {
1413   - /* We've exceed the stack rlimit. */
  1420 + page = get_arg_page(bprm, pos, 1);
  1421 + if (!page) {
1414 1422 ret = -E2BIG;
1415 1423 goto out;
1416 1424 }
1417   -#endif
1418   - ret = get_user_pages(current, bprm->mm, pos,
1419   - 1, 1, 1, &page, NULL);
1420   - if (ret <= 0) {
1421   - /* We've exceed the stack rlimit. */
1422   - ret = -E2BIG;
1423   - goto out;
1424   - }
1425 1425  
1426 1426 if (kmapped_page) {
1427 1427 flush_kernel_dcache_page(kmapped_page);
1428 1428  
... ... @@ -1539,8 +1539,10 @@
1539 1539 return retval;
1540 1540  
1541 1541 out:
1542   - if (bprm->mm)
  1542 + if (bprm->mm) {
  1543 + acct_arg_size(bprm, 0);
1543 1544 mmput(bprm->mm);
  1545 + }
1544 1546  
1545 1547 out_file:
1546 1548 if (bprm->file) {
... ... @@ -164,7 +164,7 @@
164 164  
165 165 #ifdef CONFIG_MMU
166 166  
167   -static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
  167 +void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
168 168 {
169 169 struct mm_struct *mm = current->mm;
170 170 long diff = (long)(pages - bprm->vma_pages);
... ... @@ -183,7 +183,7 @@
183 183 #endif
184 184 }
185 185  
186   -static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
  186 +struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
187 187 int write)
188 188 {
189 189 struct page *page;
190 190  
... ... @@ -297,11 +297,11 @@
297 297  
298 298 #else
299 299  
300   -static inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
  300 +void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
301 301 {
302 302 }
303 303  
304   -static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
  304 +struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
305 305 int write)
306 306 {
307 307 struct page *page;
include/linux/binfmts.h
... ... @@ -60,6 +60,10 @@
60 60 unsigned long loader, exec;
61 61 };
62 62  
  63 +extern void acct_arg_size(struct linux_binprm *bprm, unsigned long pages);
  64 +extern struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
  65 + int write);
  66 +
63 67 #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
64 68 #define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)
65 69