diff options
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 208 |
1 files changed, 103 insertions, 105 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index b2a2d6889bab..f6d2e57b99a0 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> |
@@ -80,6 +81,7 @@ extern int compat_log; | |||
80 | extern int maps_protect; | 81 | extern int maps_protect; |
81 | extern int sysctl_stat_interval; | 82 | extern int sysctl_stat_interval; |
82 | extern int latencytop_enabled; | 83 | extern int latencytop_enabled; |
84 | extern int sysctl_nr_open_min, sysctl_nr_open_max; | ||
83 | 85 | ||
84 | /* Constants used for minimum and maximum */ | 86 | /* Constants used for minimum and maximum */ |
85 | #if defined(CONFIG_DETECT_SOFTLOCKUP) || defined(CONFIG_HIGHMEM) | 87 | #if defined(CONFIG_DETECT_SOFTLOCKUP) || defined(CONFIG_HIGHMEM) |
@@ -130,8 +132,6 @@ extern int sysctl_userprocess_debug; | |||
130 | extern int spin_retry; | 132 | extern int spin_retry; |
131 | #endif | 133 | #endif |
132 | 134 | ||
133 | extern int sysctl_hz_timer; | ||
134 | |||
135 | #ifdef CONFIG_BSD_PROCESS_ACCT | 135 | #ifdef CONFIG_BSD_PROCESS_ACCT |
136 | extern int acct_parm[]; | 136 | extern int acct_parm[]; |
137 | #endif | 137 | #endif |
@@ -144,12 +144,6 @@ extern int no_unaligned_warning; | |||
144 | extern int max_lock_depth; | 144 | extern int max_lock_depth; |
145 | #endif | 145 | #endif |
146 | 146 | ||
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 | 147 | #ifdef CONFIG_PROC_SYSCTL |
154 | static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp, | 148 | 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); | 149 | void __user *buffer, size_t *lenp, loff_t *ppos); |
@@ -270,17 +264,6 @@ static struct ctl_table kern_table[] = { | |||
270 | }, | 264 | }, |
271 | { | 265 | { |
272 | .ctl_name = CTL_UNNUMBERED, | 266 | .ctl_name = CTL_UNNUMBERED, |
273 | .procname = "sched_batch_wakeup_granularity_ns", | ||
274 | .data = &sysctl_sched_batch_wakeup_granularity, | ||
275 | .maxlen = sizeof(unsigned int), | ||
276 | .mode = 0644, | ||
277 | .proc_handler = &proc_dointvec_minmax, | ||
278 | .strategy = &sysctl_intvec, | ||
279 | .extra1 = &min_wakeup_granularity_ns, | ||
280 | .extra2 = &max_wakeup_granularity_ns, | ||
281 | }, | ||
282 | { | ||
283 | .ctl_name = CTL_UNNUMBERED, | ||
284 | .procname = "sched_child_runs_first", | 267 | .procname = "sched_child_runs_first", |
285 | .data = &sysctl_sched_child_runs_first, | 268 | .data = &sysctl_sched_child_runs_first, |
286 | .maxlen = sizeof(unsigned int), | 269 | .maxlen = sizeof(unsigned int), |
@@ -318,7 +301,7 @@ static struct ctl_table kern_table[] = { | |||
318 | .data = &sysctl_sched_rt_period, | 301 | .data = &sysctl_sched_rt_period, |
319 | .maxlen = sizeof(unsigned int), | 302 | .maxlen = sizeof(unsigned int), |
320 | .mode = 0644, | 303 | .mode = 0644, |
321 | .proc_handler = &proc_dointvec, | 304 | .proc_handler = &sched_rt_handler, |
322 | }, | 305 | }, |
323 | { | 306 | { |
324 | .ctl_name = CTL_UNNUMBERED, | 307 | .ctl_name = CTL_UNNUMBERED, |
@@ -326,7 +309,7 @@ static struct ctl_table kern_table[] = { | |||
326 | .data = &sysctl_sched_rt_runtime, | 309 | .data = &sysctl_sched_rt_runtime, |
327 | .maxlen = sizeof(int), | 310 | .maxlen = sizeof(int), |
328 | .mode = 0644, | 311 | .mode = 0644, |
329 | .proc_handler = &proc_dointvec, | 312 | .proc_handler = &sched_rt_handler, |
330 | }, | 313 | }, |
331 | { | 314 | { |
332 | .ctl_name = CTL_UNNUMBERED, | 315 | .ctl_name = CTL_UNNUMBERED, |
@@ -578,16 +561,6 @@ static struct ctl_table kern_table[] = { | |||
578 | .proc_handler = &proc_dointvec, | 561 | .proc_handler = &proc_dointvec, |
579 | }, | 562 | }, |
580 | #endif | 563 | #endif |
581 | #ifdef CONFIG_NO_IDLE_HZ | ||
582 | { | ||
583 | .ctl_name = KERN_HZ_TIMER, | ||
584 | .procname = "hz_timer", | ||
585 | .data = &sysctl_hz_timer, | ||
586 | .maxlen = sizeof(int), | ||
587 | .mode = 0644, | ||
588 | .proc_handler = &proc_dointvec, | ||
589 | }, | ||
590 | #endif | ||
591 | { | 564 | { |
592 | .ctl_name = KERN_S390_USER_DEBUG_LOGGING, | 565 | .ctl_name = KERN_S390_USER_DEBUG_LOGGING, |
593 | .procname = "userprocess_debug", | 566 | .procname = "userprocess_debug", |
@@ -820,6 +793,14 @@ static struct ctl_table kern_table[] = { | |||
820 | .proc_handler = &proc_dostring, | 793 | .proc_handler = &proc_dostring, |
821 | .strategy = &sysctl_string, | 794 | .strategy = &sysctl_string, |
822 | }, | 795 | }, |
796 | #ifdef CONFIG_KEYS | ||
797 | { | ||
798 | .ctl_name = CTL_UNNUMBERED, | ||
799 | .procname = "keys", | ||
800 | .mode = 0555, | ||
801 | .child = key_sysctls, | ||
802 | }, | ||
803 | #endif | ||
823 | /* | 804 | /* |
824 | * NOTE: do not add new entries to this table unless you have read | 805 | * NOTE: do not add new entries to this table unless you have read |
825 | * Documentation/sysctl/ctl_unnumbered.txt | 806 | * Documentation/sysctl/ctl_unnumbered.txt |
@@ -1198,7 +1179,9 @@ static struct ctl_table fs_table[] = { | |||
1198 | .data = &sysctl_nr_open, | 1179 | .data = &sysctl_nr_open, |
1199 | .maxlen = sizeof(int), | 1180 | .maxlen = sizeof(int), |
1200 | .mode = 0644, | 1181 | .mode = 0644, |
1201 | .proc_handler = &proc_dointvec, | 1182 | .proc_handler = &proc_dointvec_minmax, |
1183 | .extra1 = &sysctl_nr_open_min, | ||
1184 | .extra2 = &sysctl_nr_open_max, | ||
1202 | }, | 1185 | }, |
1203 | { | 1186 | { |
1204 | .ctl_name = FS_DENTRY, | 1187 | .ctl_name = FS_DENTRY, |
@@ -1441,6 +1424,76 @@ void register_sysctl_root(struct ctl_table_root *root) | |||
1441 | } | 1424 | } |
1442 | 1425 | ||
1443 | #ifdef CONFIG_SYSCTL_SYSCALL | 1426 | #ifdef CONFIG_SYSCTL_SYSCALL |
1427 | /* Perform the actual read/write of a sysctl table entry. */ | ||
1428 | static int do_sysctl_strategy(struct ctl_table_root *root, | ||
1429 | struct ctl_table *table, | ||
1430 | int __user *name, int nlen, | ||
1431 | void __user *oldval, size_t __user *oldlenp, | ||
1432 | void __user *newval, size_t newlen) | ||
1433 | { | ||
1434 | int op = 0, rc; | ||
1435 | |||
1436 | if (oldval) | ||
1437 | op |= 004; | ||
1438 | if (newval) | ||
1439 | op |= 002; | ||
1440 | if (sysctl_perm(root, table, op)) | ||
1441 | return -EPERM; | ||
1442 | |||
1443 | if (table->strategy) { | ||
1444 | rc = table->strategy(table, name, nlen, oldval, oldlenp, | ||
1445 | newval, newlen); | ||
1446 | if (rc < 0) | ||
1447 | return rc; | ||
1448 | if (rc > 0) | ||
1449 | return 0; | ||
1450 | } | ||
1451 | |||
1452 | /* If there is no strategy routine, or if the strategy returns | ||
1453 | * zero, proceed with automatic r/w */ | ||
1454 | if (table->data && table->maxlen) { | ||
1455 | rc = sysctl_data(table, name, nlen, oldval, oldlenp, | ||
1456 | newval, newlen); | ||
1457 | if (rc < 0) | ||
1458 | return rc; | ||
1459 | } | ||
1460 | return 0; | ||
1461 | } | ||
1462 | |||
1463 | static int parse_table(int __user *name, int nlen, | ||
1464 | void __user *oldval, size_t __user *oldlenp, | ||
1465 | void __user *newval, size_t newlen, | ||
1466 | struct ctl_table_root *root, | ||
1467 | struct ctl_table *table) | ||
1468 | { | ||
1469 | int n; | ||
1470 | repeat: | ||
1471 | if (!nlen) | ||
1472 | return -ENOTDIR; | ||
1473 | if (get_user(n, name)) | ||
1474 | return -EFAULT; | ||
1475 | for ( ; table->ctl_name || table->procname; table++) { | ||
1476 | if (!table->ctl_name) | ||
1477 | continue; | ||
1478 | if (n == table->ctl_name) { | ||
1479 | int error; | ||
1480 | if (table->child) { | ||
1481 | if (sysctl_perm(root, table, 001)) | ||
1482 | return -EPERM; | ||
1483 | name++; | ||
1484 | nlen--; | ||
1485 | table = table->child; | ||
1486 | goto repeat; | ||
1487 | } | ||
1488 | error = do_sysctl_strategy(root, table, name, nlen, | ||
1489 | oldval, oldlenp, | ||
1490 | newval, newlen); | ||
1491 | return error; | ||
1492 | } | ||
1493 | } | ||
1494 | return -ENOTDIR; | ||
1495 | } | ||
1496 | |||
1444 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, | 1497 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, |
1445 | void __user *newval, size_t newlen) | 1498 | void __user *newval, size_t newlen) |
1446 | { | 1499 | { |
@@ -1458,7 +1511,8 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol | |||
1458 | for (head = sysctl_head_next(NULL); head; | 1511 | for (head = sysctl_head_next(NULL); head; |
1459 | head = sysctl_head_next(head)) { | 1512 | head = sysctl_head_next(head)) { |
1460 | error = parse_table(name, nlen, oldval, oldlenp, | 1513 | error = parse_table(name, nlen, oldval, oldlenp, |
1461 | newval, newlen, head->ctl_table); | 1514 | newval, newlen, |
1515 | head->root, head->ctl_table); | ||
1462 | if (error != -ENOTDIR) { | 1516 | if (error != -ENOTDIR) { |
1463 | sysctl_head_finish(head); | 1517 | sysctl_head_finish(head); |
1464 | break; | 1518 | break; |
@@ -1504,84 +1558,22 @@ static int test_perm(int mode, int op) | |||
1504 | return -EACCES; | 1558 | return -EACCES; |
1505 | } | 1559 | } |
1506 | 1560 | ||
1507 | int sysctl_perm(struct ctl_table *table, int op) | 1561 | int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op) |
1508 | { | 1562 | { |
1509 | int error; | 1563 | int error; |
1564 | int mode; | ||
1565 | |||
1510 | error = security_sysctl(table, op); | 1566 | error = security_sysctl(table, op); |
1511 | if (error) | 1567 | if (error) |
1512 | return error; | 1568 | return error; |
1513 | return test_perm(table->mode, op); | ||
1514 | } | ||
1515 | |||
1516 | #ifdef CONFIG_SYSCTL_SYSCALL | ||
1517 | static int parse_table(int __user *name, int nlen, | ||
1518 | void __user *oldval, size_t __user *oldlenp, | ||
1519 | void __user *newval, size_t newlen, | ||
1520 | struct ctl_table *table) | ||
1521 | { | ||
1522 | int n; | ||
1523 | repeat: | ||
1524 | if (!nlen) | ||
1525 | return -ENOTDIR; | ||
1526 | if (get_user(n, name)) | ||
1527 | return -EFAULT; | ||
1528 | for ( ; table->ctl_name || table->procname; table++) { | ||
1529 | if (!table->ctl_name) | ||
1530 | continue; | ||
1531 | if (n == table->ctl_name) { | ||
1532 | int error; | ||
1533 | if (table->child) { | ||
1534 | if (sysctl_perm(table, 001)) | ||
1535 | return -EPERM; | ||
1536 | name++; | ||
1537 | nlen--; | ||
1538 | table = table->child; | ||
1539 | goto repeat; | ||
1540 | } | ||
1541 | error = do_sysctl_strategy(table, name, nlen, | ||
1542 | oldval, oldlenp, | ||
1543 | newval, newlen); | ||
1544 | return error; | ||
1545 | } | ||
1546 | } | ||
1547 | return -ENOTDIR; | ||
1548 | } | ||
1549 | |||
1550 | /* Perform the actual read/write of a sysctl table entry. */ | ||
1551 | int do_sysctl_strategy (struct ctl_table *table, | ||
1552 | int __user *name, int nlen, | ||
1553 | void __user *oldval, size_t __user *oldlenp, | ||
1554 | void __user *newval, size_t newlen) | ||
1555 | { | ||
1556 | int op = 0, rc; | ||
1557 | |||
1558 | if (oldval) | ||
1559 | op |= 004; | ||
1560 | if (newval) | ||
1561 | op |= 002; | ||
1562 | if (sysctl_perm(table, op)) | ||
1563 | return -EPERM; | ||
1564 | 1569 | ||
1565 | if (table->strategy) { | 1570 | if (root->permissions) |
1566 | rc = table->strategy(table, name, nlen, oldval, oldlenp, | 1571 | mode = root->permissions(root, current->nsproxy, table); |
1567 | newval, newlen); | 1572 | else |
1568 | if (rc < 0) | 1573 | mode = table->mode; |
1569 | return rc; | ||
1570 | if (rc > 0) | ||
1571 | return 0; | ||
1572 | } | ||
1573 | 1574 | ||
1574 | /* If there is no strategy routine, or if the strategy returns | 1575 | return test_perm(mode, op); |
1575 | * zero, proceed with automatic r/w */ | ||
1576 | if (table->data && table->maxlen) { | ||
1577 | rc = sysctl_data(table, name, nlen, oldval, oldlenp, | ||
1578 | newval, newlen); | ||
1579 | if (rc < 0) | ||
1580 | return rc; | ||
1581 | } | ||
1582 | return 0; | ||
1583 | } | 1576 | } |
1584 | #endif /* CONFIG_SYSCTL_SYSCALL */ | ||
1585 | 1577 | ||
1586 | static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) | 1578 | static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) |
1587 | { | 1579 | { |
@@ -1594,9 +1586,13 @@ static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) | |||
1594 | 1586 | ||
1595 | static __init int sysctl_init(void) | 1587 | static __init int sysctl_init(void) |
1596 | { | 1588 | { |
1597 | int err; | ||
1598 | sysctl_set_parent(NULL, root_table); | 1589 | sysctl_set_parent(NULL, root_table); |
1599 | err = sysctl_check_table(current->nsproxy, root_table); | 1590 | #ifdef CONFIG_SYSCTL_SYSCALL_CHECK |
1591 | { | ||
1592 | int err; | ||
1593 | err = sysctl_check_table(current->nsproxy, root_table); | ||
1594 | } | ||
1595 | #endif | ||
1600 | return 0; | 1596 | return 0; |
1601 | } | 1597 | } |
1602 | 1598 | ||
@@ -1723,10 +1719,12 @@ struct ctl_table_header *__register_sysctl_paths( | |||
1723 | header->unregistering = NULL; | 1719 | header->unregistering = NULL; |
1724 | header->root = root; | 1720 | header->root = root; |
1725 | sysctl_set_parent(NULL, header->ctl_table); | 1721 | sysctl_set_parent(NULL, header->ctl_table); |
1722 | #ifdef CONFIG_SYSCTL_SYSCALL_CHECK | ||
1726 | if (sysctl_check_table(namespaces, header->ctl_table)) { | 1723 | if (sysctl_check_table(namespaces, header->ctl_table)) { |
1727 | kfree(header); | 1724 | kfree(header); |
1728 | return NULL; | 1725 | return NULL; |
1729 | } | 1726 | } |
1727 | #endif | ||
1730 | spin_lock(&sysctl_lock); | 1728 | spin_lock(&sysctl_lock); |
1731 | header_list = lookup_header_list(root, namespaces); | 1729 | header_list = lookup_header_list(root, namespaces); |
1732 | list_add_tail(&header->ctl_entry, header_list); | 1730 | list_add_tail(&header->ctl_entry, header_list); |