aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-23 11:28:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-23 11:28:34 -0400
commit4d9dec4db2efbd7edb549bd02373995b67496983 (patch)
treea0ddbecea4823a7f3e20ab6eacb37a086a72dc36 /fs
parent34b064569eba3bec65bf98efe057b0578fe13297 (diff)
parentae6b585eeb74670a2dec1fe4394bdfbdb9395cc2 (diff)
Merge branch 'exec_rm_compat' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc
* 'exec_rm_compat' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc: exec: document acct_arg_size() exec: unify do_execve/compat_do_execve code exec: introduce struct user_arg_ptr exec: introduce get_user_arg_ptr() helper
Diffstat (limited to 'fs')
-rw-r--r--fs/compat.c235
-rw-r--r--fs/exec.c125
2 files changed, 100 insertions, 260 deletions
diff --git a/fs/compat.c b/fs/compat.c
index 72fe6cda9108..0ea00832de23 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1306,241 +1306,6 @@ compat_sys_openat(unsigned int dfd, const char __user *filename, int flags, int
1306 return do_sys_open(dfd, filename, flags, mode); 1306 return do_sys_open(dfd, filename, flags, mode);
1307} 1307}
1308 1308
1309/*
1310 * compat_count() counts the number of arguments/envelopes. It is basically
1311 * a copy of count() from fs/exec.c, except that it works with 32 bit argv
1312 * and envp pointers.
1313 */
1314static int compat_count(compat_uptr_t __user *argv, int max)
1315{
1316 int i = 0;
1317
1318 if (argv != NULL) {
1319 for (;;) {
1320 compat_uptr_t p;
1321
1322 if (get_user(p, argv))
1323 return -EFAULT;
1324 if (!p)
1325 break;
1326 argv++;
1327 if (i++ >= max)
1328 return -E2BIG;
1329
1330 if (fatal_signal_pending(current))
1331 return -ERESTARTNOHAND;
1332 cond_resched();
1333 }
1334 }
1335 return i;
1336}
1337
1338/*
1339 * compat_copy_strings() is basically a copy of copy_strings() from fs/exec.c
1340 * except that it works with 32 bit argv and envp pointers.
1341 */
1342static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
1343 struct linux_binprm *bprm)
1344{
1345 struct page *kmapped_page = NULL;
1346 char *kaddr = NULL;
1347 unsigned long kpos = 0;
1348 int ret;
1349
1350 while (argc-- > 0) {
1351 compat_uptr_t str;
1352 int len;
1353 unsigned long pos;
1354
1355 if (get_user(str, argv+argc) ||
1356 !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
1357 ret = -EFAULT;
1358 goto out;
1359 }
1360
1361 if (len > MAX_ARG_STRLEN) {
1362 ret = -E2BIG;
1363 goto out;
1364 }
1365
1366 /* We're going to work our way backwords. */
1367 pos = bprm->p;
1368 str += len;
1369 bprm->p -= len;
1370
1371 while (len > 0) {
1372 int offset, bytes_to_copy;
1373
1374 if (fatal_signal_pending(current)) {
1375 ret = -ERESTARTNOHAND;
1376 goto out;
1377 }
1378 cond_resched();
1379
1380 offset = pos % PAGE_SIZE;
1381 if (offset == 0)
1382 offset = PAGE_SIZE;
1383
1384 bytes_to_copy = offset;
1385 if (bytes_to_copy > len)
1386 bytes_to_copy = len;
1387
1388 offset -= bytes_to_copy;
1389 pos -= bytes_to_copy;
1390 str -= bytes_to_copy;
1391 len -= bytes_to_copy;
1392
1393 if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
1394 struct page *page;
1395
1396 page = get_arg_page(bprm, pos, 1);
1397 if (!page) {
1398 ret = -E2BIG;
1399 goto out;
1400 }
1401
1402 if (kmapped_page) {
1403 flush_kernel_dcache_page(kmapped_page);
1404 kunmap(kmapped_page);
1405 put_page(kmapped_page);
1406 }
1407 kmapped_page = page;
1408 kaddr = kmap(kmapped_page);
1409 kpos = pos & PAGE_MASK;
1410 flush_cache_page(bprm->vma, kpos,
1411 page_to_pfn(kmapped_page));
1412 }
1413 if (copy_from_user(kaddr+offset, compat_ptr(str),
1414 bytes_to_copy)) {
1415 ret = -EFAULT;
1416 goto out;
1417 }
1418 }
1419 }
1420 ret = 0;
1421out:
1422 if (kmapped_page) {
1423 flush_kernel_dcache_page(kmapped_page);
1424 kunmap(kmapped_page);
1425 put_page(kmapped_page);
1426 }
1427 return ret;
1428}
1429
1430/*
1431 * compat_do_execve() is mostly a copy of do_execve(), with the exception
1432 * that it processes 32 bit argv and envp pointers.
1433 */
1434int compat_do_execve(char * filename,
1435 compat_uptr_t __user *argv,
1436 compat_uptr_t __user *envp,
1437 struct pt_regs * regs)
1438{
1439 struct linux_binprm *bprm;
1440 struct file *file;
1441 struct files_struct *displaced;
1442 bool clear_in_exec;
1443 int retval;
1444
1445 retval = unshare_files(&displaced);
1446 if (retval)
1447 goto out_ret;
1448
1449 retval = -ENOMEM;
1450 bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
1451 if (!bprm)
1452 goto out_files;
1453
1454 retval = prepare_bprm_creds(bprm);
1455 if (retval)
1456 goto out_free;
1457
1458 retval = check_unsafe_exec(bprm);
1459 if (retval < 0)
1460 goto out_free;
1461 clear_in_exec = retval;
1462 current->in_execve = 1;
1463
1464 file = open_exec(filename);
1465 retval = PTR_ERR(file);
1466 if (IS_ERR(file))
1467 goto out_unmark;
1468
1469 sched_exec();
1470
1471 bprm->file = file;
1472 bprm->filename = filename;
1473 bprm->interp = filename;
1474
1475 retval = bprm_mm_init(bprm);
1476 if (retval)
1477 goto out_file;
1478
1479 bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
1480 if ((retval = bprm->argc) < 0)
1481 goto out;
1482
1483 bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
1484 if ((retval = bprm->envc) < 0)
1485 goto out;
1486
1487 retval = prepare_binprm(bprm);
1488 if (retval < 0)
1489 goto out;
1490
1491 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1492 if (retval < 0)
1493 goto out;
1494
1495 bprm->exec = bprm->p;
1496 retval = compat_copy_strings(bprm->envc, envp, bprm);
1497 if (retval < 0)
1498 goto out;
1499
1500 retval = compat_copy_strings(bprm->argc, argv, bprm);
1501 if (retval < 0)
1502 goto out;
1503
1504 retval = search_binary_handler(bprm, regs);
1505 if (retval < 0)
1506 goto out;
1507
1508 /* execve succeeded */
1509 current->fs->in_exec = 0;
1510 current->in_execve = 0;
1511 acct_update_integrals(current);
1512 free_bprm(bprm);
1513 if (displaced)
1514 put_files_struct(displaced);
1515 return retval;
1516
1517out:
1518 if (bprm->mm) {
1519 acct_arg_size(bprm, 0);
1520 mmput(bprm->mm);
1521 }
1522
1523out_file:
1524 if (bprm->file) {
1525 allow_write_access(bprm->file);
1526 fput(bprm->file);
1527 }
1528
1529out_unmark:
1530 if (clear_in_exec)
1531 current->fs->in_exec = 0;
1532 current->in_execve = 0;
1533
1534out_free:
1535 free_bprm(bprm);
1536
1537out_files:
1538 if (displaced)
1539 reset_files_struct(displaced);
1540out_ret:
1541 return retval;
1542}
1543
1544#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t)) 1309#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))
1545 1310
1546static int poll_select_copy_remaining(struct timespec *end_time, void __user *p, 1311static int poll_select_copy_remaining(struct timespec *end_time, void __user *p,
diff --git a/fs/exec.c b/fs/exec.c
index 8328beb9016f..c016896dcbb2 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -55,6 +55,7 @@
55#include <linux/fs_struct.h> 55#include <linux/fs_struct.h>
56#include <linux/pipe_fs_i.h> 56#include <linux/pipe_fs_i.h>
57#include <linux/oom.h> 57#include <linux/oom.h>
58#include <linux/compat.h>
58 59
59#include <asm/uaccess.h> 60#include <asm/uaccess.h>
60#include <asm/mmu_context.h> 61#include <asm/mmu_context.h>
@@ -166,8 +167,13 @@ out:
166} 167}
167 168
168#ifdef CONFIG_MMU 169#ifdef CONFIG_MMU
169 170/*
170void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) 171 * The nascent bprm->mm is not visible until exec_mmap() but it can
172 * use a lot of memory, account these pages in current->mm temporary
173 * for oom_badness()->get_mm_rss(). Once exec succeeds or fails, we
174 * change the counter back via acct_arg_size(0).
175 */
176static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
171{ 177{
172 struct mm_struct *mm = current->mm; 178 struct mm_struct *mm = current->mm;
173 long diff = (long)(pages - bprm->vma_pages); 179 long diff = (long)(pages - bprm->vma_pages);
@@ -186,7 +192,7 @@ void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
186#endif 192#endif
187} 193}
188 194
189struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, 195static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
190 int write) 196 int write)
191{ 197{
192 struct page *page; 198 struct page *page;
@@ -305,11 +311,11 @@ static bool valid_arg_len(struct linux_binprm *bprm, long len)
305 311
306#else 312#else
307 313
308void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) 314static inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
309{ 315{
310} 316}
311 317
312struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, 318static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
313 int write) 319 int write)
314{ 320{
315 struct page *page; 321 struct page *page;
@@ -398,22 +404,56 @@ err:
398 return err; 404 return err;
399} 405}
400 406
407struct user_arg_ptr {
408#ifdef CONFIG_COMPAT
409 bool is_compat;
410#endif
411 union {
412 const char __user *const __user *native;
413#ifdef CONFIG_COMPAT
414 compat_uptr_t __user *compat;
415#endif
416 } ptr;
417};
418
419static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
420{
421 const char __user *native;
422
423#ifdef CONFIG_COMPAT
424 if (unlikely(argv.is_compat)) {
425 compat_uptr_t compat;
426
427 if (get_user(compat, argv.ptr.compat + nr))
428 return ERR_PTR(-EFAULT);
429
430 return compat_ptr(compat);
431 }
432#endif
433
434 if (get_user(native, argv.ptr.native + nr))
435 return ERR_PTR(-EFAULT);
436
437 return native;
438}
439
401/* 440/*
402 * count() counts the number of strings in array ARGV. 441 * count() counts the number of strings in array ARGV.
403 */ 442 */
404static int count(const char __user * const __user * argv, int max) 443static int count(struct user_arg_ptr argv, int max)
405{ 444{
406 int i = 0; 445 int i = 0;
407 446
408 if (argv != NULL) { 447 if (argv.ptr.native != NULL) {
409 for (;;) { 448 for (;;) {
410 const char __user * p; 449 const char __user *p = get_user_arg_ptr(argv, i);
411 450
412 if (get_user(p, argv))
413 return -EFAULT;
414 if (!p) 451 if (!p)
415 break; 452 break;
416 argv++; 453
454 if (IS_ERR(p))
455 return -EFAULT;
456
417 if (i++ >= max) 457 if (i++ >= max)
418 return -E2BIG; 458 return -E2BIG;
419 459
@@ -430,7 +470,7 @@ static int count(const char __user * const __user * argv, int max)
430 * processes's memory to the new process's stack. The call to get_user_pages() 470 * processes's memory to the new process's stack. The call to get_user_pages()
431 * ensures the destination page is created and not swapped out. 471 * ensures the destination page is created and not swapped out.
432 */ 472 */
433static int copy_strings(int argc, const char __user *const __user *argv, 473static int copy_strings(int argc, struct user_arg_ptr argv,
434 struct linux_binprm *bprm) 474 struct linux_binprm *bprm)
435{ 475{
436 struct page *kmapped_page = NULL; 476 struct page *kmapped_page = NULL;
@@ -443,16 +483,18 @@ static int copy_strings(int argc, const char __user *const __user *argv,
443 int len; 483 int len;
444 unsigned long pos; 484 unsigned long pos;
445 485
446 if (get_user(str, argv+argc) || 486 ret = -EFAULT;
447 !(len = strnlen_user(str, MAX_ARG_STRLEN))) { 487 str = get_user_arg_ptr(argv, argc);
448 ret = -EFAULT; 488 if (IS_ERR(str))
449 goto out; 489 goto out;
450 }
451 490
452 if (!valid_arg_len(bprm, len)) { 491 len = strnlen_user(str, MAX_ARG_STRLEN);
453 ret = -E2BIG; 492 if (!len)
493 goto out;
494
495 ret = -E2BIG;
496 if (!valid_arg_len(bprm, len))
454 goto out; 497 goto out;
455 }
456 498
457 /* We're going to work our way backwords. */ 499 /* We're going to work our way backwords. */
458 pos = bprm->p; 500 pos = bprm->p;
@@ -519,14 +561,19 @@ out:
519/* 561/*
520 * Like copy_strings, but get argv and its values from kernel memory. 562 * Like copy_strings, but get argv and its values from kernel memory.
521 */ 563 */
522int copy_strings_kernel(int argc, const char *const *argv, 564int copy_strings_kernel(int argc, const char *const *__argv,
523 struct linux_binprm *bprm) 565 struct linux_binprm *bprm)
524{ 566{
525 int r; 567 int r;
526 mm_segment_t oldfs = get_fs(); 568 mm_segment_t oldfs = get_fs();
569 struct user_arg_ptr argv = {
570 .ptr.native = (const char __user *const __user *)__argv,
571 };
572
527 set_fs(KERNEL_DS); 573 set_fs(KERNEL_DS);
528 r = copy_strings(argc, (const char __user *const __user *)argv, bprm); 574 r = copy_strings(argc, argv, bprm);
529 set_fs(oldfs); 575 set_fs(oldfs);
576
530 return r; 577 return r;
531} 578}
532EXPORT_SYMBOL(copy_strings_kernel); 579EXPORT_SYMBOL(copy_strings_kernel);
@@ -1379,10 +1426,10 @@ EXPORT_SYMBOL(search_binary_handler);
1379/* 1426/*
1380 * sys_execve() executes a new program. 1427 * sys_execve() executes a new program.
1381 */ 1428 */
1382int do_execve(const char * filename, 1429static int do_execve_common(const char *filename,
1383 const char __user *const __user *argv, 1430 struct user_arg_ptr argv,
1384 const char __user *const __user *envp, 1431 struct user_arg_ptr envp,
1385 struct pt_regs * regs) 1432 struct pt_regs *regs)
1386{ 1433{
1387 struct linux_binprm *bprm; 1434 struct linux_binprm *bprm;
1388 struct file *file; 1435 struct file *file;
@@ -1489,6 +1536,34 @@ out_ret:
1489 return retval; 1536 return retval;
1490} 1537}
1491 1538
1539int do_execve(const char *filename,
1540 const char __user *const __user *__argv,
1541 const char __user *const __user *__envp,
1542 struct pt_regs *regs)
1543{
1544 struct user_arg_ptr argv = { .ptr.native = __argv };
1545 struct user_arg_ptr envp = { .ptr.native = __envp };
1546 return do_execve_common(filename, argv, envp, regs);
1547}
1548
1549#ifdef CONFIG_COMPAT
1550int compat_do_execve(char *filename,
1551 compat_uptr_t __user *__argv,
1552 compat_uptr_t __user *__envp,
1553 struct pt_regs *regs)
1554{
1555 struct user_arg_ptr argv = {
1556 .is_compat = true,
1557 .ptr.compat = __argv,
1558 };
1559 struct user_arg_ptr envp = {
1560 .is_compat = true,
1561 .ptr.compat = __envp,
1562 };
1563 return do_execve_common(filename, argv, envp, regs);
1564}
1565#endif
1566
1492void set_binfmt(struct linux_binfmt *new) 1567void set_binfmt(struct linux_binfmt *new)
1493{ 1568{
1494 struct mm_struct *mm = current->mm; 1569 struct mm_struct *mm = current->mm;