diff options
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 176 |
1 files changed, 97 insertions, 79 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index fd3364827ccf..d7ffdc59816a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/writeback.h> | 38 | #include <linux/writeback.h> |
39 | #include <linux/hugetlb.h> | 39 | #include <linux/hugetlb.h> |
40 | #include <linux/initrd.h> | 40 | #include <linux/initrd.h> |
41 | #include <linux/key.h> | ||
41 | #include <linux/times.h> | 42 | #include <linux/times.h> |
42 | #include <linux/limits.h> | 43 | #include <linux/limits.h> |
43 | #include <linux/dcache.h> | 44 | #include <linux/dcache.h> |
@@ -144,12 +145,6 @@ extern int no_unaligned_warning; | |||
144 | extern int max_lock_depth; | 145 | extern int max_lock_depth; |
145 | #endif | 146 | #endif |
146 | 147 | ||
147 | #ifdef CONFIG_SYSCTL_SYSCALL | ||
148 | static int parse_table(int __user *, int, void __user *, size_t __user *, | ||
149 | void __user *, size_t, struct ctl_table *); | ||
150 | #endif | ||
151 | |||
152 | |||
153 | #ifdef CONFIG_PROC_SYSCTL | 148 | #ifdef CONFIG_PROC_SYSCTL |
154 | static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp, | 149 | static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp, |
155 | void __user *buffer, size_t *lenp, loff_t *ppos); | 150 | void __user *buffer, size_t *lenp, loff_t *ppos); |
@@ -809,6 +804,14 @@ static struct ctl_table kern_table[] = { | |||
809 | .proc_handler = &proc_dostring, | 804 | .proc_handler = &proc_dostring, |
810 | .strategy = &sysctl_string, | 805 | .strategy = &sysctl_string, |
811 | }, | 806 | }, |
807 | #ifdef CONFIG_KEYS | ||
808 | { | ||
809 | .ctl_name = CTL_UNNUMBERED, | ||
810 | .procname = "keys", | ||
811 | .mode = 0555, | ||
812 | .child = key_sysctls, | ||
813 | }, | ||
814 | #endif | ||
812 | /* | 815 | /* |
813 | * NOTE: do not add new entries to this table unless you have read | 816 | * NOTE: do not add new entries to this table unless you have read |
814 | * Documentation/sysctl/ctl_unnumbered.txt | 817 | * Documentation/sysctl/ctl_unnumbered.txt |
@@ -1430,6 +1433,76 @@ void register_sysctl_root(struct ctl_table_root *root) | |||
1430 | } | 1433 | } |
1431 | 1434 | ||
1432 | #ifdef CONFIG_SYSCTL_SYSCALL | 1435 | #ifdef CONFIG_SYSCTL_SYSCALL |
1436 | /* Perform the actual read/write of a sysctl table entry. */ | ||
1437 | static int do_sysctl_strategy(struct ctl_table_root *root, | ||
1438 | struct ctl_table *table, | ||
1439 | int __user *name, int nlen, | ||
1440 | void __user *oldval, size_t __user *oldlenp, | ||
1441 | void __user *newval, size_t newlen) | ||
1442 | { | ||
1443 | int op = 0, rc; | ||
1444 | |||
1445 | if (oldval) | ||
1446 | op |= 004; | ||
1447 | if (newval) | ||
1448 | op |= 002; | ||
1449 | if (sysctl_perm(root, table, op)) | ||
1450 | return -EPERM; | ||
1451 | |||
1452 | if (table->strategy) { | ||
1453 | rc = table->strategy(table, name, nlen, oldval, oldlenp, | ||
1454 | newval, newlen); | ||
1455 | if (rc < 0) | ||
1456 | return rc; | ||
1457 | if (rc > 0) | ||
1458 | return 0; | ||
1459 | } | ||
1460 | |||
1461 | /* If there is no strategy routine, or if the strategy returns | ||
1462 | * zero, proceed with automatic r/w */ | ||
1463 | if (table->data && table->maxlen) { | ||
1464 | rc = sysctl_data(table, name, nlen, oldval, oldlenp, | ||
1465 | newval, newlen); | ||
1466 | if (rc < 0) | ||
1467 | return rc; | ||
1468 | } | ||
1469 | return 0; | ||
1470 | } | ||
1471 | |||
1472 | static int parse_table(int __user *name, int nlen, | ||
1473 | void __user *oldval, size_t __user *oldlenp, | ||
1474 | void __user *newval, size_t newlen, | ||
1475 | struct ctl_table_root *root, | ||
1476 | struct ctl_table *table) | ||
1477 | { | ||
1478 | int n; | ||
1479 | repeat: | ||
1480 | if (!nlen) | ||
1481 | return -ENOTDIR; | ||
1482 | if (get_user(n, name)) | ||
1483 | return -EFAULT; | ||
1484 | for ( ; table->ctl_name || table->procname; table++) { | ||
1485 | if (!table->ctl_name) | ||
1486 | continue; | ||
1487 | if (n == table->ctl_name) { | ||
1488 | int error; | ||
1489 | if (table->child) { | ||
1490 | if (sysctl_perm(root, table, 001)) | ||
1491 | return -EPERM; | ||
1492 | name++; | ||
1493 | nlen--; | ||
1494 | table = table->child; | ||
1495 | goto repeat; | ||
1496 | } | ||
1497 | error = do_sysctl_strategy(root, table, name, nlen, | ||
1498 | oldval, oldlenp, | ||
1499 | newval, newlen); | ||
1500 | return error; | ||
1501 | } | ||
1502 | } | ||
1503 | return -ENOTDIR; | ||
1504 | } | ||
1505 | |||
1433 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, | 1506 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, |
1434 | void __user *newval, size_t newlen) | 1507 | void __user *newval, size_t newlen) |
1435 | { | 1508 | { |
@@ -1447,7 +1520,8 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol | |||
1447 | for (head = sysctl_head_next(NULL); head; | 1520 | for (head = sysctl_head_next(NULL); head; |
1448 | head = sysctl_head_next(head)) { | 1521 | head = sysctl_head_next(head)) { |
1449 | error = parse_table(name, nlen, oldval, oldlenp, | 1522 | error = parse_table(name, nlen, oldval, oldlenp, |
1450 | newval, newlen, head->ctl_table); | 1523 | newval, newlen, |
1524 | head->root, head->ctl_table); | ||
1451 | if (error != -ENOTDIR) { | 1525 | if (error != -ENOTDIR) { |
1452 | sysctl_head_finish(head); | 1526 | sysctl_head_finish(head); |
1453 | break; | 1527 | break; |
@@ -1493,84 +1567,22 @@ static int test_perm(int mode, int op) | |||
1493 | return -EACCES; | 1567 | return -EACCES; |
1494 | } | 1568 | } |
1495 | 1569 | ||
1496 | int sysctl_perm(struct ctl_table *table, int op) | 1570 | int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op) |
1497 | { | 1571 | { |
1498 | int error; | 1572 | int error; |
1573 | int mode; | ||
1574 | |||
1499 | error = security_sysctl(table, op); | 1575 | error = security_sysctl(table, op); |
1500 | if (error) | 1576 | if (error) |
1501 | return error; | 1577 | return error; |
1502 | return test_perm(table->mode, op); | ||
1503 | } | ||
1504 | |||
1505 | #ifdef CONFIG_SYSCTL_SYSCALL | ||
1506 | static int parse_table(int __user *name, int nlen, | ||
1507 | void __user *oldval, size_t __user *oldlenp, | ||
1508 | void __user *newval, size_t newlen, | ||
1509 | struct ctl_table *table) | ||
1510 | { | ||
1511 | int n; | ||
1512 | repeat: | ||
1513 | if (!nlen) | ||
1514 | return -ENOTDIR; | ||
1515 | if (get_user(n, name)) | ||
1516 | return -EFAULT; | ||
1517 | for ( ; table->ctl_name || table->procname; table++) { | ||
1518 | if (!table->ctl_name) | ||
1519 | continue; | ||
1520 | if (n == table->ctl_name) { | ||
1521 | int error; | ||
1522 | if (table->child) { | ||
1523 | if (sysctl_perm(table, 001)) | ||
1524 | return -EPERM; | ||
1525 | name++; | ||
1526 | nlen--; | ||
1527 | table = table->child; | ||
1528 | goto repeat; | ||
1529 | } | ||
1530 | error = do_sysctl_strategy(table, name, nlen, | ||
1531 | oldval, oldlenp, | ||
1532 | newval, newlen); | ||
1533 | return error; | ||
1534 | } | ||
1535 | } | ||
1536 | return -ENOTDIR; | ||
1537 | } | ||
1538 | 1578 | ||
1539 | /* Perform the actual read/write of a sysctl table entry. */ | 1579 | if (root->permissions) |
1540 | int do_sysctl_strategy (struct ctl_table *table, | 1580 | mode = root->permissions(root, current->nsproxy, table); |
1541 | int __user *name, int nlen, | 1581 | else |
1542 | void __user *oldval, size_t __user *oldlenp, | 1582 | mode = table->mode; |
1543 | void __user *newval, size_t newlen) | ||
1544 | { | ||
1545 | int op = 0, rc; | ||
1546 | |||
1547 | if (oldval) | ||
1548 | op |= 004; | ||
1549 | if (newval) | ||
1550 | op |= 002; | ||
1551 | if (sysctl_perm(table, op)) | ||
1552 | return -EPERM; | ||
1553 | 1583 | ||
1554 | if (table->strategy) { | 1584 | return test_perm(mode, op); |
1555 | rc = table->strategy(table, name, nlen, oldval, oldlenp, | ||
1556 | newval, newlen); | ||
1557 | if (rc < 0) | ||
1558 | return rc; | ||
1559 | if (rc > 0) | ||
1560 | return 0; | ||
1561 | } | ||
1562 | |||
1563 | /* If there is no strategy routine, or if the strategy returns | ||
1564 | * zero, proceed with automatic r/w */ | ||
1565 | if (table->data && table->maxlen) { | ||
1566 | rc = sysctl_data(table, name, nlen, oldval, oldlenp, | ||
1567 | newval, newlen); | ||
1568 | if (rc < 0) | ||
1569 | return rc; | ||
1570 | } | ||
1571 | return 0; | ||
1572 | } | 1585 | } |
1573 | #endif /* CONFIG_SYSCTL_SYSCALL */ | ||
1574 | 1586 | ||
1575 | static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) | 1587 | static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) |
1576 | { | 1588 | { |
@@ -1583,9 +1595,13 @@ static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) | |||
1583 | 1595 | ||
1584 | static __init int sysctl_init(void) | 1596 | static __init int sysctl_init(void) |
1585 | { | 1597 | { |
1586 | int err; | ||
1587 | sysctl_set_parent(NULL, root_table); | 1598 | sysctl_set_parent(NULL, root_table); |
1588 | err = sysctl_check_table(current->nsproxy, root_table); | 1599 | #ifdef CONFIG_SYSCTL_SYSCALL_CHECK |
1600 | { | ||
1601 | int err; | ||
1602 | err = sysctl_check_table(current->nsproxy, root_table); | ||
1603 | } | ||
1604 | #endif | ||
1589 | return 0; | 1605 | return 0; |
1590 | } | 1606 | } |
1591 | 1607 | ||
@@ -1712,10 +1728,12 @@ struct ctl_table_header *__register_sysctl_paths( | |||
1712 | header->unregistering = NULL; | 1728 | header->unregistering = NULL; |
1713 | header->root = root; | 1729 | header->root = root; |
1714 | sysctl_set_parent(NULL, header->ctl_table); | 1730 | sysctl_set_parent(NULL, header->ctl_table); |
1731 | #ifdef CONFIG_SYSCTL_SYSCALL_CHECK | ||
1715 | if (sysctl_check_table(namespaces, header->ctl_table)) { | 1732 | if (sysctl_check_table(namespaces, header->ctl_table)) { |
1716 | kfree(header); | 1733 | kfree(header); |
1717 | return NULL; | 1734 | return NULL; |
1718 | } | 1735 | } |
1736 | #endif | ||
1719 | spin_lock(&sysctl_lock); | 1737 | spin_lock(&sysctl_lock); |
1720 | header_list = lookup_header_list(root, namespaces); | 1738 | header_list = lookup_header_list(root, namespaces); |
1721 | list_add_tail(&header->ctl_entry, header_list); | 1739 | list_add_tail(&header->ctl_entry, header_list); |