aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorXiaotian Feng <dfeng@redhat.com>2010-10-27 18:34:08 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-27 21:03:12 -0400
commit1b0d300bd0f047e2edaf9d4b6784189e6c67c3d1 (patch)
treece3777527c949add56658e4d5b2ab02781590931 /fs
parent9b1bf12d5d51bca178dea21b04a0805e29d60cf1 (diff)
core_pattern: fix truncation by core_pattern handler with long parameters
We met a parameter truncated issue, consider following: > echo "|/root/core_pattern_pipe_test %p /usr/libexec/blah-blah-blah \ %s %c %p %u %g 11 12345678901234567890123456789012345678 %t" > \ /proc/sys/kernel/core_pattern This is okay because the strings is less than CORENAME_MAX_SIZE. "cat /proc/sys/kernel/core_pattern" shows the whole string. but after we run core_pattern_pipe_test in man page, we found last parameter was truncated like below: argc[10]=<12807486> The root cause is core_pattern allows % specifiers, which need to be replaced during parse time, but the replace may expand the strings to larger than CORENAME_MAX_SIZE. So if the last parameter is % specifiers, the replace code is using snprintf(out_ptr, out_end - out_ptr, ...), this will write out of corename array. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Xiaotian Feng <dfeng@redhat.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Oleg Nesterov <oleg@redhat.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Reviewed-by: Neil Horman <nhorman@tuxdriver.com> Cc: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/exec.c155
1 files changed, 95 insertions, 60 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 9722909c4d88..ca01d2d0a6d4 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -66,6 +66,12 @@ char core_pattern[CORENAME_MAX_SIZE] = "core";
66unsigned int core_pipe_limit; 66unsigned int core_pipe_limit;
67int suid_dumpable = 0; 67int suid_dumpable = 0;
68 68
69struct core_name {
70 char *corename;
71 int used, size;
72};
73static atomic_t call_count = ATOMIC_INIT(1);
74
69/* The maximal length of core_pattern is also specified in sysctl.c */ 75/* The maximal length of core_pattern is also specified in sysctl.c */
70 76
71static LIST_HEAD(formats); 77static LIST_HEAD(formats);
@@ -1459,127 +1465,148 @@ void set_binfmt(struct linux_binfmt *new)
1459 1465
1460EXPORT_SYMBOL(set_binfmt); 1466EXPORT_SYMBOL(set_binfmt);
1461 1467
1468static int expand_corename(struct core_name *cn)
1469{
1470 char *old_corename = cn->corename;
1471
1472 cn->size = CORENAME_MAX_SIZE * atomic_inc_return(&call_count);
1473 cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL);
1474
1475 if (!cn->corename) {
1476 kfree(old_corename);
1477 return -ENOMEM;
1478 }
1479
1480 return 0;
1481}
1482
1483static int cn_printf(struct core_name *cn, const char *fmt, ...)
1484{
1485 char *cur;
1486 int need;
1487 int ret;
1488 va_list arg;
1489
1490 va_start(arg, fmt);
1491 need = vsnprintf(NULL, 0, fmt, arg);
1492 va_end(arg);
1493
1494 if (likely(need < cn->size - cn->used - 1))
1495 goto out_printf;
1496
1497 ret = expand_corename(cn);
1498 if (ret)
1499 goto expand_fail;
1500
1501out_printf:
1502 cur = cn->corename + cn->used;
1503 va_start(arg, fmt);
1504 vsnprintf(cur, need + 1, fmt, arg);
1505 va_end(arg);
1506 cn->used += need;
1507 return 0;
1508
1509expand_fail:
1510 return ret;
1511}
1512
1462/* format_corename will inspect the pattern parameter, and output a 1513/* format_corename will inspect the pattern parameter, and output a
1463 * name into corename, which must have space for at least 1514 * name into corename, which must have space for at least
1464 * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. 1515 * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
1465 */ 1516 */
1466static int format_corename(char *corename, long signr) 1517static int format_corename(struct core_name *cn, long signr)
1467{ 1518{
1468 const struct cred *cred = current_cred(); 1519 const struct cred *cred = current_cred();
1469 const char *pat_ptr = core_pattern; 1520 const char *pat_ptr = core_pattern;
1470 int ispipe = (*pat_ptr == '|'); 1521 int ispipe = (*pat_ptr == '|');
1471 char *out_ptr = corename;
1472 char *const out_end = corename + CORENAME_MAX_SIZE;
1473 int rc;
1474 int pid_in_pattern = 0; 1522 int pid_in_pattern = 0;
1523 int err = 0;
1524
1525 cn->size = CORENAME_MAX_SIZE * atomic_read(&call_count);
1526 cn->corename = kmalloc(cn->size, GFP_KERNEL);
1527 cn->used = 0;
1528
1529 if (!cn->corename)
1530 return -ENOMEM;
1475 1531
1476 /* Repeat as long as we have more pattern to process and more output 1532 /* Repeat as long as we have more pattern to process and more output
1477 space */ 1533 space */
1478 while (*pat_ptr) { 1534 while (*pat_ptr) {
1479 if (*pat_ptr != '%') { 1535 if (*pat_ptr != '%') {
1480 if (out_ptr == out_end) 1536 if (*pat_ptr == 0)
1481 goto out; 1537 goto out;
1482 *out_ptr++ = *pat_ptr++; 1538 err = cn_printf(cn, "%c", *pat_ptr++);
1483 } else { 1539 } else {
1484 switch (*++pat_ptr) { 1540 switch (*++pat_ptr) {
1541 /* single % at the end, drop that */
1485 case 0: 1542 case 0:
1486 goto out; 1543 goto out;
1487 /* Double percent, output one percent */ 1544 /* Double percent, output one percent */
1488 case '%': 1545 case '%':
1489 if (out_ptr == out_end) 1546 err = cn_printf(cn, "%c", '%');
1490 goto out;
1491 *out_ptr++ = '%';
1492 break; 1547 break;
1493 /* pid */ 1548 /* pid */
1494 case 'p': 1549 case 'p':
1495 pid_in_pattern = 1; 1550 pid_in_pattern = 1;
1496 rc = snprintf(out_ptr, out_end - out_ptr, 1551 err = cn_printf(cn, "%d",
1497 "%d", task_tgid_vnr(current)); 1552 task_tgid_vnr(current));
1498 if (rc > out_end - out_ptr)
1499 goto out;
1500 out_ptr += rc;
1501 break; 1553 break;
1502 /* uid */ 1554 /* uid */
1503 case 'u': 1555 case 'u':
1504 rc = snprintf(out_ptr, out_end - out_ptr, 1556 err = cn_printf(cn, "%d", cred->uid);
1505 "%d", cred->uid);
1506 if (rc > out_end - out_ptr)
1507 goto out;
1508 out_ptr += rc;
1509 break; 1557 break;
1510 /* gid */ 1558 /* gid */
1511 case 'g': 1559 case 'g':
1512 rc = snprintf(out_ptr, out_end - out_ptr, 1560 err = cn_printf(cn, "%d", cred->gid);
1513 "%d", cred->gid);
1514 if (rc > out_end - out_ptr)
1515 goto out;
1516 out_ptr += rc;
1517 break; 1561 break;
1518 /* signal that caused the coredump */ 1562 /* signal that caused the coredump */
1519 case 's': 1563 case 's':
1520 rc = snprintf(out_ptr, out_end - out_ptr, 1564 err = cn_printf(cn, "%ld", signr);
1521 "%ld", signr);
1522 if (rc > out_end - out_ptr)
1523 goto out;
1524 out_ptr += rc;
1525 break; 1565 break;
1526 /* UNIX time of coredump */ 1566 /* UNIX time of coredump */
1527 case 't': { 1567 case 't': {
1528 struct timeval tv; 1568 struct timeval tv;
1529 do_gettimeofday(&tv); 1569 do_gettimeofday(&tv);
1530 rc = snprintf(out_ptr, out_end - out_ptr, 1570 err = cn_printf(cn, "%lu", tv.tv_sec);
1531 "%lu", tv.tv_sec);
1532 if (rc > out_end - out_ptr)
1533 goto out;
1534 out_ptr += rc;
1535 break; 1571 break;
1536 } 1572 }
1537 /* hostname */ 1573 /* hostname */
1538 case 'h': 1574 case 'h':
1539 down_read(&uts_sem); 1575 down_read(&uts_sem);
1540 rc = snprintf(out_ptr, out_end - out_ptr, 1576 err = cn_printf(cn, "%s",
1541 "%s", utsname()->nodename); 1577 utsname()->nodename);
1542 up_read(&uts_sem); 1578 up_read(&uts_sem);
1543 if (rc > out_end - out_ptr)
1544 goto out;
1545 out_ptr += rc;
1546 break; 1579 break;
1547 /* executable */ 1580 /* executable */
1548 case 'e': 1581 case 'e':
1549 rc = snprintf(out_ptr, out_end - out_ptr, 1582 err = cn_printf(cn, "%s", current->comm);
1550 "%s", current->comm);
1551 if (rc > out_end - out_ptr)
1552 goto out;
1553 out_ptr += rc;
1554 break; 1583 break;
1555 /* core limit size */ 1584 /* core limit size */
1556 case 'c': 1585 case 'c':
1557 rc = snprintf(out_ptr, out_end - out_ptr, 1586 err = cn_printf(cn, "%lu",
1558 "%lu", rlimit(RLIMIT_CORE)); 1587 rlimit(RLIMIT_CORE));
1559 if (rc > out_end - out_ptr)
1560 goto out;
1561 out_ptr += rc;
1562 break; 1588 break;
1563 default: 1589 default:
1564 break; 1590 break;
1565 } 1591 }
1566 ++pat_ptr; 1592 ++pat_ptr;
1567 } 1593 }
1594
1595 if (err)
1596 return err;
1568 } 1597 }
1598
1569 /* Backward compatibility with core_uses_pid: 1599 /* Backward compatibility with core_uses_pid:
1570 * 1600 *
1571 * If core_pattern does not include a %p (as is the default) 1601 * If core_pattern does not include a %p (as is the default)
1572 * and core_uses_pid is set, then .%pid will be appended to 1602 * and core_uses_pid is set, then .%pid will be appended to
1573 * the filename. Do not do this for piped commands. */ 1603 * the filename. Do not do this for piped commands. */
1574 if (!ispipe && !pid_in_pattern && core_uses_pid) { 1604 if (!ispipe && !pid_in_pattern && core_uses_pid) {
1575 rc = snprintf(out_ptr, out_end - out_ptr, 1605 err = cn_printf(cn, ".%d", task_tgid_vnr(current));
1576 ".%d", task_tgid_vnr(current)); 1606 if (err)
1577 if (rc > out_end - out_ptr) 1607 return err;
1578 goto out;
1579 out_ptr += rc;
1580 } 1608 }
1581out: 1609out:
1582 *out_ptr = 0;
1583 return ispipe; 1610 return ispipe;
1584} 1611}
1585 1612
@@ -1856,7 +1883,7 @@ static int umh_pipe_setup(struct subprocess_info *info)
1856void do_coredump(long signr, int exit_code, struct pt_regs *regs) 1883void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1857{ 1884{
1858 struct core_state core_state; 1885 struct core_state core_state;
1859 char corename[CORENAME_MAX_SIZE + 1]; 1886 struct core_name cn;
1860 struct mm_struct *mm = current->mm; 1887 struct mm_struct *mm = current->mm;
1861 struct linux_binfmt * binfmt; 1888 struct linux_binfmt * binfmt;
1862 const struct cred *old_cred; 1889 const struct cred *old_cred;
@@ -1911,7 +1938,13 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1911 */ 1938 */
1912 clear_thread_flag(TIF_SIGPENDING); 1939 clear_thread_flag(TIF_SIGPENDING);
1913 1940
1914 ispipe = format_corename(corename, signr); 1941 ispipe = format_corename(&cn, signr);
1942
1943 if (ispipe == -ENOMEM) {
1944 printk(KERN_WARNING "format_corename failed\n");
1945 printk(KERN_WARNING "Aborting core\n");
1946 goto fail_corename;
1947 }
1915 1948
1916 if (ispipe) { 1949 if (ispipe) {
1917 int dump_count; 1950 int dump_count;
@@ -1948,7 +1981,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1948 goto fail_dropcount; 1981 goto fail_dropcount;
1949 } 1982 }
1950 1983
1951 helper_argv = argv_split(GFP_KERNEL, corename+1, NULL); 1984 helper_argv = argv_split(GFP_KERNEL, cn.corename+1, NULL);
1952 if (!helper_argv) { 1985 if (!helper_argv) {
1953 printk(KERN_WARNING "%s failed to allocate memory\n", 1986 printk(KERN_WARNING "%s failed to allocate memory\n",
1954 __func__); 1987 __func__);
@@ -1961,7 +1994,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1961 argv_free(helper_argv); 1994 argv_free(helper_argv);
1962 if (retval) { 1995 if (retval) {
1963 printk(KERN_INFO "Core dump to %s pipe failed\n", 1996 printk(KERN_INFO "Core dump to %s pipe failed\n",
1964 corename); 1997 cn.corename);
1965 goto close_fail; 1998 goto close_fail;
1966 } 1999 }
1967 } else { 2000 } else {
@@ -1970,7 +2003,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1970 if (cprm.limit < binfmt->min_coredump) 2003 if (cprm.limit < binfmt->min_coredump)
1971 goto fail_unlock; 2004 goto fail_unlock;
1972 2005
1973 cprm.file = filp_open(corename, 2006 cprm.file = filp_open(cn.corename,
1974 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 2007 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
1975 0600); 2008 0600);
1976 if (IS_ERR(cprm.file)) 2009 if (IS_ERR(cprm.file))
@@ -2012,6 +2045,8 @@ fail_dropcount:
2012 if (ispipe) 2045 if (ispipe)
2013 atomic_dec(&core_dump_count); 2046 atomic_dec(&core_dump_count);
2014fail_unlock: 2047fail_unlock:
2048 kfree(cn.corename);
2049fail_corename:
2015 coredump_finish(mm); 2050 coredump_finish(mm);
2016 revert_creds(old_cred); 2051 revert_creds(old_cred);
2017fail_creds: 2052fail_creds: