diff options
Diffstat (limited to 'kernel/sysctl.c')
| -rw-r--r-- | kernel/sysctl.c | 350 |
1 files changed, 250 insertions, 100 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 6b16e16428d..a13bd4dfaeb 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | #include <linux/limits.h> | 43 | #include <linux/limits.h> |
| 44 | #include <linux/dcache.h> | 44 | #include <linux/dcache.h> |
| 45 | #include <linux/syscalls.h> | 45 | #include <linux/syscalls.h> |
| 46 | #include <linux/vmstat.h> | ||
| 46 | #include <linux/nfs_fs.h> | 47 | #include <linux/nfs_fs.h> |
| 47 | #include <linux/acpi.h> | 48 | #include <linux/acpi.h> |
| 48 | #include <linux/reboot.h> | 49 | #include <linux/reboot.h> |
| @@ -79,8 +80,6 @@ extern int pid_max_min, pid_max_max; | |||
| 79 | extern int sysctl_drop_caches; | 80 | extern int sysctl_drop_caches; |
| 80 | extern int percpu_pagelist_fraction; | 81 | extern int percpu_pagelist_fraction; |
| 81 | extern int compat_log; | 82 | extern int compat_log; |
| 82 | extern int maps_protect; | ||
| 83 | extern int sysctl_stat_interval; | ||
| 84 | extern int latencytop_enabled; | 83 | extern int latencytop_enabled; |
| 85 | extern int sysctl_nr_open_min, sysctl_nr_open_max; | 84 | extern int sysctl_nr_open_min, sysctl_nr_open_max; |
| 86 | #ifdef CONFIG_RCU_TORTURE_TEST | 85 | #ifdef CONFIG_RCU_TORTURE_TEST |
| @@ -88,15 +87,16 @@ extern int rcutorture_runnable; | |||
| 88 | #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ | 87 | #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ |
| 89 | 88 | ||
| 90 | /* Constants used for minimum and maximum */ | 89 | /* Constants used for minimum and maximum */ |
| 91 | #if defined(CONFIG_DETECT_SOFTLOCKUP) || defined(CONFIG_HIGHMEM) | 90 | #if defined(CONFIG_HIGHMEM) || defined(CONFIG_DETECT_SOFTLOCKUP) |
| 92 | static int one = 1; | 91 | static int one = 1; |
| 93 | #endif | 92 | #endif |
| 94 | 93 | ||
| 95 | #ifdef CONFIG_DETECT_SOFTLOCKUP | 94 | #ifdef CONFIG_DETECT_SOFTLOCKUP |
| 96 | static int sixty = 60; | 95 | static int sixty = 60; |
| 96 | static int neg_one = -1; | ||
| 97 | #endif | 97 | #endif |
| 98 | 98 | ||
| 99 | #ifdef CONFIG_MMU | 99 | #if defined(CONFIG_MMU) && defined(CONFIG_FILE_LOCKING) |
| 100 | static int two = 2; | 100 | static int two = 2; |
| 101 | #endif | 101 | #endif |
| 102 | 102 | ||
| @@ -110,17 +110,15 @@ static int min_percpu_pagelist_fract = 8; | |||
| 110 | 110 | ||
| 111 | static int ngroups_max = NGROUPS_MAX; | 111 | static int ngroups_max = NGROUPS_MAX; |
| 112 | 112 | ||
| 113 | #ifdef CONFIG_KMOD | 113 | #ifdef CONFIG_MODULES |
| 114 | extern char modprobe_path[]; | 114 | extern char modprobe_path[]; |
| 115 | #endif | 115 | #endif |
| 116 | #ifdef CONFIG_CHR_DEV_SG | 116 | #ifdef CONFIG_CHR_DEV_SG |
| 117 | extern int sg_big_buff; | 117 | extern int sg_big_buff; |
| 118 | #endif | 118 | #endif |
| 119 | 119 | ||
| 120 | #ifdef __sparc__ | 120 | #ifdef CONFIG_SPARC |
| 121 | extern char reboot_command []; | 121 | #include <asm/system.h> |
| 122 | extern int stop_a_enabled; | ||
| 123 | extern int scons_pwroff; | ||
| 124 | #endif | 122 | #endif |
| 125 | 123 | ||
| 126 | #ifdef __hppa__ | 124 | #ifdef __hppa__ |
| @@ -151,20 +149,22 @@ extern int max_lock_depth; | |||
| 151 | #ifdef CONFIG_PROC_SYSCTL | 149 | #ifdef CONFIG_PROC_SYSCTL |
| 152 | static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp, | 150 | static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp, |
| 153 | void __user *buffer, size_t *lenp, loff_t *ppos); | 151 | void __user *buffer, size_t *lenp, loff_t *ppos); |
| 154 | static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp, | 152 | static int proc_taint(struct ctl_table *table, int write, struct file *filp, |
| 155 | void __user *buffer, size_t *lenp, loff_t *ppos); | 153 | void __user *buffer, size_t *lenp, loff_t *ppos); |
| 156 | #endif | 154 | #endif |
| 157 | 155 | ||
| 158 | static struct ctl_table root_table[]; | 156 | static struct ctl_table root_table[]; |
| 159 | static struct ctl_table_root sysctl_table_root; | 157 | static struct ctl_table_root sysctl_table_root; |
| 160 | static struct ctl_table_header root_table_header = { | 158 | static struct ctl_table_header root_table_header = { |
| 159 | .count = 1, | ||
| 161 | .ctl_table = root_table, | 160 | .ctl_table = root_table, |
| 162 | .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.header_list), | 161 | .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list), |
| 163 | .root = &sysctl_table_root, | 162 | .root = &sysctl_table_root, |
| 163 | .set = &sysctl_table_root.default_set, | ||
| 164 | }; | 164 | }; |
| 165 | static struct ctl_table_root sysctl_table_root = { | 165 | static struct ctl_table_root sysctl_table_root = { |
| 166 | .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list), | 166 | .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list), |
| 167 | .header_list = LIST_HEAD_INIT(root_table_header.ctl_entry), | 167 | .default_set.list = LIST_HEAD_INIT(root_table_header.ctl_entry), |
| 168 | }; | 168 | }; |
| 169 | 169 | ||
| 170 | static struct ctl_table kern_table[]; | 170 | static struct ctl_table kern_table[]; |
| @@ -276,6 +276,16 @@ static struct ctl_table kern_table[] = { | |||
| 276 | }, | 276 | }, |
| 277 | { | 277 | { |
| 278 | .ctl_name = CTL_UNNUMBERED, | 278 | .ctl_name = CTL_UNNUMBERED, |
| 279 | .procname = "sched_shares_thresh", | ||
| 280 | .data = &sysctl_sched_shares_thresh, | ||
| 281 | .maxlen = sizeof(unsigned int), | ||
| 282 | .mode = 0644, | ||
| 283 | .proc_handler = &proc_dointvec_minmax, | ||
| 284 | .strategy = &sysctl_intvec, | ||
| 285 | .extra1 = &zero, | ||
| 286 | }, | ||
| 287 | { | ||
| 288 | .ctl_name = CTL_UNNUMBERED, | ||
| 279 | .procname = "sched_child_runs_first", | 289 | .procname = "sched_child_runs_first", |
| 280 | .data = &sysctl_sched_child_runs_first, | 290 | .data = &sysctl_sched_child_runs_first, |
| 281 | .maxlen = sizeof(unsigned int), | 291 | .maxlen = sizeof(unsigned int), |
| @@ -379,10 +389,9 @@ static struct ctl_table kern_table[] = { | |||
| 379 | #ifdef CONFIG_PROC_SYSCTL | 389 | #ifdef CONFIG_PROC_SYSCTL |
| 380 | { | 390 | { |
| 381 | .procname = "tainted", | 391 | .procname = "tainted", |
| 382 | .data = &tainted, | 392 | .maxlen = sizeof(long), |
| 383 | .maxlen = sizeof(int), | ||
| 384 | .mode = 0644, | 393 | .mode = 0644, |
| 385 | .proc_handler = &proc_dointvec_taint, | 394 | .proc_handler = &proc_taint, |
| 386 | }, | 395 | }, |
| 387 | #endif | 396 | #endif |
| 388 | #ifdef CONFIG_LATENCYTOP | 397 | #ifdef CONFIG_LATENCYTOP |
| @@ -412,7 +421,7 @@ static struct ctl_table kern_table[] = { | |||
| 412 | .mode = 0644, | 421 | .mode = 0644, |
| 413 | .proc_handler = &proc_dointvec, | 422 | .proc_handler = &proc_dointvec, |
| 414 | }, | 423 | }, |
| 415 | #ifdef __sparc__ | 424 | #ifdef CONFIG_SPARC |
| 416 | { | 425 | { |
| 417 | .ctl_name = KERN_SPARC_REBOOT, | 426 | .ctl_name = KERN_SPARC_REBOOT, |
| 418 | .procname = "reboot-cmd", | 427 | .procname = "reboot-cmd", |
| @@ -475,7 +484,7 @@ static struct ctl_table kern_table[] = { | |||
| 475 | .proc_handler = &ftrace_enable_sysctl, | 484 | .proc_handler = &ftrace_enable_sysctl, |
| 476 | }, | 485 | }, |
| 477 | #endif | 486 | #endif |
| 478 | #ifdef CONFIG_KMOD | 487 | #ifdef CONFIG_MODULES |
| 479 | { | 488 | { |
| 480 | .ctl_name = KERN_MODPROBE, | 489 | .ctl_name = KERN_MODPROBE, |
| 481 | .procname = "modprobe", | 490 | .procname = "modprobe", |
| @@ -623,7 +632,7 @@ static struct ctl_table kern_table[] = { | |||
| 623 | { | 632 | { |
| 624 | .ctl_name = KERN_PRINTK_RATELIMIT, | 633 | .ctl_name = KERN_PRINTK_RATELIMIT, |
| 625 | .procname = "printk_ratelimit", | 634 | .procname = "printk_ratelimit", |
| 626 | .data = &printk_ratelimit_jiffies, | 635 | .data = &printk_ratelimit_state.interval, |
| 627 | .maxlen = sizeof(int), | 636 | .maxlen = sizeof(int), |
| 628 | .mode = 0644, | 637 | .mode = 0644, |
| 629 | .proc_handler = &proc_dointvec_jiffies, | 638 | .proc_handler = &proc_dointvec_jiffies, |
| @@ -632,7 +641,7 @@ static struct ctl_table kern_table[] = { | |||
| 632 | { | 641 | { |
| 633 | .ctl_name = KERN_PRINTK_RATELIMIT_BURST, | 642 | .ctl_name = KERN_PRINTK_RATELIMIT_BURST, |
| 634 | .procname = "printk_ratelimit_burst", | 643 | .procname = "printk_ratelimit_burst", |
| 635 | .data = &printk_ratelimit_burst, | 644 | .data = &printk_ratelimit_state.burst, |
| 636 | .maxlen = sizeof(int), | 645 | .maxlen = sizeof(int), |
| 637 | .mode = 0644, | 646 | .mode = 0644, |
| 638 | .proc_handler = &proc_dointvec, | 647 | .proc_handler = &proc_dointvec, |
| @@ -739,13 +748,24 @@ static struct ctl_table kern_table[] = { | |||
| 739 | #ifdef CONFIG_DETECT_SOFTLOCKUP | 748 | #ifdef CONFIG_DETECT_SOFTLOCKUP |
| 740 | { | 749 | { |
| 741 | .ctl_name = CTL_UNNUMBERED, | 750 | .ctl_name = CTL_UNNUMBERED, |
| 751 | .procname = "softlockup_panic", | ||
| 752 | .data = &softlockup_panic, | ||
| 753 | .maxlen = sizeof(int), | ||
| 754 | .mode = 0644, | ||
| 755 | .proc_handler = &proc_dointvec_minmax, | ||
| 756 | .strategy = &sysctl_intvec, | ||
| 757 | .extra1 = &zero, | ||
| 758 | .extra2 = &one, | ||
| 759 | }, | ||
| 760 | { | ||
| 761 | .ctl_name = CTL_UNNUMBERED, | ||
| 742 | .procname = "softlockup_thresh", | 762 | .procname = "softlockup_thresh", |
| 743 | .data = &softlockup_thresh, | 763 | .data = &softlockup_thresh, |
| 744 | .maxlen = sizeof(unsigned long), | 764 | .maxlen = sizeof(int), |
| 745 | .mode = 0644, | 765 | .mode = 0644, |
| 746 | .proc_handler = &proc_doulongvec_minmax, | 766 | .proc_handler = &proc_dointvec_minmax, |
| 747 | .strategy = &sysctl_intvec, | 767 | .strategy = &sysctl_intvec, |
| 748 | .extra1 = &one, | 768 | .extra1 = &neg_one, |
| 749 | .extra2 = &sixty, | 769 | .extra2 = &sixty, |
| 750 | }, | 770 | }, |
| 751 | { | 771 | { |
| @@ -796,16 +816,6 @@ static struct ctl_table kern_table[] = { | |||
| 796 | .proc_handler = &proc_dointvec, | 816 | .proc_handler = &proc_dointvec, |
| 797 | }, | 817 | }, |
| 798 | #endif | 818 | #endif |
| 799 | #ifdef CONFIG_PROC_FS | ||
| 800 | { | ||
| 801 | .ctl_name = CTL_UNNUMBERED, | ||
| 802 | .procname = "maps_protect", | ||
| 803 | .data = &maps_protect, | ||
| 804 | .maxlen = sizeof(int), | ||
| 805 | .mode = 0644, | ||
| 806 | .proc_handler = &proc_dointvec, | ||
| 807 | }, | ||
| 808 | #endif | ||
| 809 | { | 819 | { |
| 810 | .ctl_name = CTL_UNNUMBERED, | 820 | .ctl_name = CTL_UNNUMBERED, |
| 811 | .procname = "poweroff_cmd", | 821 | .procname = "poweroff_cmd", |
| @@ -833,6 +843,16 @@ static struct ctl_table kern_table[] = { | |||
| 833 | .proc_handler = &proc_dointvec, | 843 | .proc_handler = &proc_dointvec, |
| 834 | }, | 844 | }, |
| 835 | #endif | 845 | #endif |
| 846 | #ifdef CONFIG_UNEVICTABLE_LRU | ||
| 847 | { | ||
| 848 | .ctl_name = CTL_UNNUMBERED, | ||
| 849 | .procname = "scan_unevictable_pages", | ||
| 850 | .data = &scan_unevictable_pages, | ||
| 851 | .maxlen = sizeof(scan_unevictable_pages), | ||
| 852 | .mode = 0644, | ||
| 853 | .proc_handler = &scan_unevictable_handler, | ||
| 854 | }, | ||
| 855 | #endif | ||
| 836 | /* | 856 | /* |
| 837 | * NOTE: do not add new entries to this table unless you have read | 857 | * NOTE: do not add new entries to this table unless you have read |
| 838 | * Documentation/sysctl/ctl_unnumbered.txt | 858 | * Documentation/sysctl/ctl_unnumbered.txt |
| @@ -947,7 +967,7 @@ static struct ctl_table vm_table[] = { | |||
| 947 | #ifdef CONFIG_HUGETLB_PAGE | 967 | #ifdef CONFIG_HUGETLB_PAGE |
| 948 | { | 968 | { |
| 949 | .procname = "nr_hugepages", | 969 | .procname = "nr_hugepages", |
| 950 | .data = &max_huge_pages, | 970 | .data = NULL, |
| 951 | .maxlen = sizeof(unsigned long), | 971 | .maxlen = sizeof(unsigned long), |
| 952 | .mode = 0644, | 972 | .mode = 0644, |
| 953 | .proc_handler = &hugetlb_sysctl_handler, | 973 | .proc_handler = &hugetlb_sysctl_handler, |
| @@ -973,10 +993,12 @@ static struct ctl_table vm_table[] = { | |||
| 973 | { | 993 | { |
| 974 | .ctl_name = CTL_UNNUMBERED, | 994 | .ctl_name = CTL_UNNUMBERED, |
| 975 | .procname = "nr_overcommit_hugepages", | 995 | .procname = "nr_overcommit_hugepages", |
| 976 | .data = &sysctl_overcommit_huge_pages, | 996 | .data = NULL, |
| 977 | .maxlen = sizeof(sysctl_overcommit_huge_pages), | 997 | .maxlen = sizeof(unsigned long), |
| 978 | .mode = 0644, | 998 | .mode = 0644, |
| 979 | .proc_handler = &hugetlb_overcommit_handler, | 999 | .proc_handler = &hugetlb_overcommit_handler, |
| 1000 | .extra1 = (void *)&hugetlb_zero, | ||
| 1001 | .extra2 = (void *)&hugetlb_infinity, | ||
| 980 | }, | 1002 | }, |
| 981 | #endif | 1003 | #endif |
| 982 | { | 1004 | { |
| @@ -1245,6 +1267,7 @@ static struct ctl_table fs_table[] = { | |||
| 1245 | .extra1 = &minolduid, | 1267 | .extra1 = &minolduid, |
| 1246 | .extra2 = &maxolduid, | 1268 | .extra2 = &maxolduid, |
| 1247 | }, | 1269 | }, |
| 1270 | #ifdef CONFIG_FILE_LOCKING | ||
| 1248 | { | 1271 | { |
| 1249 | .ctl_name = FS_LEASES, | 1272 | .ctl_name = FS_LEASES, |
| 1250 | .procname = "leases-enable", | 1273 | .procname = "leases-enable", |
| @@ -1253,6 +1276,7 @@ static struct ctl_table fs_table[] = { | |||
| 1253 | .mode = 0644, | 1276 | .mode = 0644, |
| 1254 | .proc_handler = &proc_dointvec, | 1277 | .proc_handler = &proc_dointvec, |
| 1255 | }, | 1278 | }, |
| 1279 | #endif | ||
| 1256 | #ifdef CONFIG_DNOTIFY | 1280 | #ifdef CONFIG_DNOTIFY |
| 1257 | { | 1281 | { |
| 1258 | .ctl_name = FS_DIR_NOTIFY, | 1282 | .ctl_name = FS_DIR_NOTIFY, |
| @@ -1264,6 +1288,7 @@ static struct ctl_table fs_table[] = { | |||
| 1264 | }, | 1288 | }, |
| 1265 | #endif | 1289 | #endif |
| 1266 | #ifdef CONFIG_MMU | 1290 | #ifdef CONFIG_MMU |
| 1291 | #ifdef CONFIG_FILE_LOCKING | ||
| 1267 | { | 1292 | { |
| 1268 | .ctl_name = FS_LEASE_TIME, | 1293 | .ctl_name = FS_LEASE_TIME, |
| 1269 | .procname = "lease-break-time", | 1294 | .procname = "lease-break-time", |
| @@ -1275,6 +1300,8 @@ static struct ctl_table fs_table[] = { | |||
| 1275 | .extra1 = &zero, | 1300 | .extra1 = &zero, |
| 1276 | .extra2 = &two, | 1301 | .extra2 = &two, |
| 1277 | }, | 1302 | }, |
| 1303 | #endif | ||
| 1304 | #ifdef CONFIG_AIO | ||
| 1278 | { | 1305 | { |
| 1279 | .procname = "aio-nr", | 1306 | .procname = "aio-nr", |
| 1280 | .data = &aio_nr, | 1307 | .data = &aio_nr, |
| @@ -1289,6 +1316,7 @@ static struct ctl_table fs_table[] = { | |||
| 1289 | .mode = 0644, | 1316 | .mode = 0644, |
| 1290 | .proc_handler = &proc_doulongvec_minmax, | 1317 | .proc_handler = &proc_doulongvec_minmax, |
| 1291 | }, | 1318 | }, |
| 1319 | #endif /* CONFIG_AIO */ | ||
| 1292 | #ifdef CONFIG_INOTIFY_USER | 1320 | #ifdef CONFIG_INOTIFY_USER |
| 1293 | { | 1321 | { |
| 1294 | .ctl_name = FS_INOTIFY, | 1322 | .ctl_name = FS_INOTIFY, |
| @@ -1372,6 +1400,9 @@ static void start_unregistering(struct ctl_table_header *p) | |||
| 1372 | spin_unlock(&sysctl_lock); | 1400 | spin_unlock(&sysctl_lock); |
| 1373 | wait_for_completion(&wait); | 1401 | wait_for_completion(&wait); |
| 1374 | spin_lock(&sysctl_lock); | 1402 | spin_lock(&sysctl_lock); |
| 1403 | } else { | ||
| 1404 | /* anything non-NULL; we'll never dereference it */ | ||
| 1405 | p->unregistering = ERR_PTR(-EINVAL); | ||
| 1375 | } | 1406 | } |
| 1376 | /* | 1407 | /* |
| 1377 | * do not remove from the list until nobody holds it; walking the | 1408 | * do not remove from the list until nobody holds it; walking the |
| @@ -1380,6 +1411,32 @@ static void start_unregistering(struct ctl_table_header *p) | |||
| 1380 | list_del_init(&p->ctl_entry); | 1411 | list_del_init(&p->ctl_entry); |
| 1381 | } | 1412 | } |
| 1382 | 1413 | ||
| 1414 | void sysctl_head_get(struct ctl_table_header *head) | ||
| 1415 | { | ||
| 1416 | spin_lock(&sysctl_lock); | ||
| 1417 | head->count++; | ||
| 1418 | spin_unlock(&sysctl_lock); | ||
| 1419 | } | ||
| 1420 | |||
| 1421 | void sysctl_head_put(struct ctl_table_header *head) | ||
| 1422 | { | ||
| 1423 | spin_lock(&sysctl_lock); | ||
| 1424 | if (!--head->count) | ||
| 1425 | kfree(head); | ||
| 1426 | spin_unlock(&sysctl_lock); | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) | ||
| 1430 | { | ||
| 1431 | if (!head) | ||
| 1432 | BUG(); | ||
| 1433 | spin_lock(&sysctl_lock); | ||
| 1434 | if (!use_table(head)) | ||
| 1435 | head = ERR_PTR(-ENOENT); | ||
| 1436 | spin_unlock(&sysctl_lock); | ||
| 1437 | return head; | ||
| 1438 | } | ||
| 1439 | |||
| 1383 | void sysctl_head_finish(struct ctl_table_header *head) | 1440 | void sysctl_head_finish(struct ctl_table_header *head) |
| 1384 | { | 1441 | { |
| 1385 | if (!head) | 1442 | if (!head) |
| @@ -1389,14 +1446,20 @@ void sysctl_head_finish(struct ctl_table_header *head) | |||
| 1389 | spin_unlock(&sysctl_lock); | 1446 | spin_unlock(&sysctl_lock); |
| 1390 | } | 1447 | } |
| 1391 | 1448 | ||
| 1449 | static struct ctl_table_set * | ||
| 1450 | lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces) | ||
| 1451 | { | ||
| 1452 | struct ctl_table_set *set = &root->default_set; | ||
| 1453 | if (root->lookup) | ||
| 1454 | set = root->lookup(root, namespaces); | ||
| 1455 | return set; | ||
| 1456 | } | ||
| 1457 | |||
| 1392 | static struct list_head * | 1458 | static struct list_head * |
| 1393 | lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces) | 1459 | lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces) |
| 1394 | { | 1460 | { |
| 1395 | struct list_head *header_list; | 1461 | struct ctl_table_set *set = lookup_header_set(root, namespaces); |
| 1396 | header_list = &root->header_list; | 1462 | return &set->list; |
| 1397 | if (root->lookup) | ||
| 1398 | header_list = root->lookup(root, namespaces); | ||
| 1399 | return header_list; | ||
| 1400 | } | 1463 | } |
| 1401 | 1464 | ||
| 1402 | struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, | 1465 | struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, |
| @@ -1459,22 +1522,20 @@ void register_sysctl_root(struct ctl_table_root *root) | |||
| 1459 | /* Perform the actual read/write of a sysctl table entry. */ | 1522 | /* Perform the actual read/write of a sysctl table entry. */ |
| 1460 | static int do_sysctl_strategy(struct ctl_table_root *root, | 1523 | static int do_sysctl_strategy(struct ctl_table_root *root, |
| 1461 | struct ctl_table *table, | 1524 | struct ctl_table *table, |
| 1462 | int __user *name, int nlen, | ||
| 1463 | void __user *oldval, size_t __user *oldlenp, | 1525 | void __user *oldval, size_t __user *oldlenp, |
| 1464 | void __user *newval, size_t newlen) | 1526 | void __user *newval, size_t newlen) |
| 1465 | { | 1527 | { |
| 1466 | int op = 0, rc; | 1528 | int op = 0, rc; |
| 1467 | 1529 | ||
| 1468 | if (oldval) | 1530 | if (oldval) |
| 1469 | op |= 004; | 1531 | op |= MAY_READ; |
| 1470 | if (newval) | 1532 | if (newval) |
| 1471 | op |= 002; | 1533 | op |= MAY_WRITE; |
| 1472 | if (sysctl_perm(root, table, op)) | 1534 | if (sysctl_perm(root, table, op)) |
| 1473 | return -EPERM; | 1535 | return -EPERM; |
| 1474 | 1536 | ||
| 1475 | if (table->strategy) { | 1537 | if (table->strategy) { |
| 1476 | rc = table->strategy(table, name, nlen, oldval, oldlenp, | 1538 | rc = table->strategy(table, oldval, oldlenp, newval, newlen); |
| 1477 | newval, newlen); | ||
| 1478 | if (rc < 0) | 1539 | if (rc < 0) |
| 1479 | return rc; | 1540 | return rc; |
| 1480 | if (rc > 0) | 1541 | if (rc > 0) |
| @@ -1484,8 +1545,7 @@ static int do_sysctl_strategy(struct ctl_table_root *root, | |||
| 1484 | /* If there is no strategy routine, or if the strategy returns | 1545 | /* If there is no strategy routine, or if the strategy returns |
| 1485 | * zero, proceed with automatic r/w */ | 1546 | * zero, proceed with automatic r/w */ |
| 1486 | if (table->data && table->maxlen) { | 1547 | if (table->data && table->maxlen) { |
| 1487 | rc = sysctl_data(table, name, nlen, oldval, oldlenp, | 1548 | rc = sysctl_data(table, oldval, oldlenp, newval, newlen); |
| 1488 | newval, newlen); | ||
| 1489 | if (rc < 0) | 1549 | if (rc < 0) |
| 1490 | return rc; | 1550 | return rc; |
| 1491 | } | 1551 | } |
| @@ -1510,14 +1570,14 @@ repeat: | |||
| 1510 | if (n == table->ctl_name) { | 1570 | if (n == table->ctl_name) { |
| 1511 | int error; | 1571 | int error; |
| 1512 | if (table->child) { | 1572 | if (table->child) { |
| 1513 | if (sysctl_perm(root, table, 001)) | 1573 | if (sysctl_perm(root, table, MAY_EXEC)) |
| 1514 | return -EPERM; | 1574 | return -EPERM; |
| 1515 | name++; | 1575 | name++; |
| 1516 | nlen--; | 1576 | nlen--; |
| 1517 | table = table->child; | 1577 | table = table->child; |
| 1518 | goto repeat; | 1578 | goto repeat; |
| 1519 | } | 1579 | } |
| 1520 | error = do_sysctl_strategy(root, table, name, nlen, | 1580 | error = do_sysctl_strategy(root, table, |
| 1521 | oldval, oldlenp, | 1581 | oldval, oldlenp, |
| 1522 | newval, newlen); | 1582 | newval, newlen); |
| 1523 | return error; | 1583 | return error; |
| @@ -1585,7 +1645,7 @@ static int test_perm(int mode, int op) | |||
| 1585 | mode >>= 6; | 1645 | mode >>= 6; |
| 1586 | else if (in_egroup_p(0)) | 1646 | else if (in_egroup_p(0)) |
| 1587 | mode >>= 3; | 1647 | mode >>= 3; |
| 1588 | if ((mode & op & 0007) == op) | 1648 | if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0) |
| 1589 | return 0; | 1649 | return 0; |
| 1590 | return -EACCES; | 1650 | return -EACCES; |
| 1591 | } | 1651 | } |
| @@ -1595,7 +1655,7 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op) | |||
| 1595 | int error; | 1655 | int error; |
| 1596 | int mode; | 1656 | int mode; |
| 1597 | 1657 | ||
| 1598 | error = security_sysctl(table, op); | 1658 | error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC)); |
| 1599 | if (error) | 1659 | if (error) |
| 1600 | return error; | 1660 | return error; |
| 1601 | 1661 | ||
| @@ -1630,6 +1690,54 @@ static __init int sysctl_init(void) | |||
| 1630 | 1690 | ||
| 1631 | core_initcall(sysctl_init); | 1691 | core_initcall(sysctl_init); |
| 1632 | 1692 | ||
| 1693 | static struct ctl_table *is_branch_in(struct ctl_table *branch, | ||
| 1694 | struct ctl_table *table) | ||
| 1695 | { | ||
| 1696 | struct ctl_table *p; | ||
| 1697 | const char *s = branch->procname; | ||
| 1698 | |||
| 1699 | /* branch should have named subdirectory as its first element */ | ||
| 1700 | if (!s || !branch->child) | ||
| 1701 | return NULL; | ||
| 1702 | |||
| 1703 | /* ... and nothing else */ | ||
| 1704 | if (branch[1].procname || branch[1].ctl_name) | ||
| 1705 | return NULL; | ||
| 1706 | |||
| 1707 | /* table should contain subdirectory with the same name */ | ||
| 1708 | for (p = table; p->procname || p->ctl_name; p++) { | ||
| 1709 | if (!p->child) | ||
| 1710 | continue; | ||
| 1711 | if (p->procname && strcmp(p->procname, s) == 0) | ||
| 1712 | return p; | ||
| 1713 | } | ||
| 1714 | return NULL; | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | /* see if attaching q to p would be an improvement */ | ||
| 1718 | static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q) | ||
| 1719 | { | ||
| 1720 | struct ctl_table *to = p->ctl_table, *by = q->ctl_table; | ||
| 1721 | struct ctl_table *next; | ||
| 1722 | int is_better = 0; | ||
| 1723 | int not_in_parent = !p->attached_by; | ||
| 1724 | |||
| 1725 | while ((next = is_branch_in(by, to)) != NULL) { | ||
| 1726 | if (by == q->attached_by) | ||
| 1727 | is_better = 1; | ||
| 1728 | if (to == p->attached_by) | ||
| 1729 | not_in_parent = 1; | ||
| 1730 | by = by->child; | ||
| 1731 | to = next->child; | ||
| 1732 | } | ||
| 1733 | |||
| 1734 | if (is_better && not_in_parent) { | ||
| 1735 | q->attached_by = by; | ||
| 1736 | q->attached_to = to; | ||
| 1737 | q->parent = p; | ||
| 1738 | } | ||
| 1739 | } | ||
| 1740 | |||
| 1633 | /** | 1741 | /** |
| 1634 | * __register_sysctl_paths - register a sysctl hierarchy | 1742 | * __register_sysctl_paths - register a sysctl hierarchy |
| 1635 | * @root: List of sysctl headers to register on | 1743 | * @root: List of sysctl headers to register on |
| @@ -1706,10 +1814,10 @@ struct ctl_table_header *__register_sysctl_paths( | |||
| 1706 | struct nsproxy *namespaces, | 1814 | struct nsproxy *namespaces, |
| 1707 | const struct ctl_path *path, struct ctl_table *table) | 1815 | const struct ctl_path *path, struct ctl_table *table) |
| 1708 | { | 1816 | { |
| 1709 | struct list_head *header_list; | ||
| 1710 | struct ctl_table_header *header; | 1817 | struct ctl_table_header *header; |
| 1711 | struct ctl_table *new, **prevp; | 1818 | struct ctl_table *new, **prevp; |
| 1712 | unsigned int n, npath; | 1819 | unsigned int n, npath; |
| 1820 | struct ctl_table_set *set; | ||
| 1713 | 1821 | ||
| 1714 | /* Count the path components */ | 1822 | /* Count the path components */ |
| 1715 | for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath) | 1823 | for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath) |
| @@ -1751,6 +1859,7 @@ struct ctl_table_header *__register_sysctl_paths( | |||
| 1751 | header->unregistering = NULL; | 1859 | header->unregistering = NULL; |
| 1752 | header->root = root; | 1860 | header->root = root; |
| 1753 | sysctl_set_parent(NULL, header->ctl_table); | 1861 | sysctl_set_parent(NULL, header->ctl_table); |
| 1862 | header->count = 1; | ||
| 1754 | #ifdef CONFIG_SYSCTL_SYSCALL_CHECK | 1863 | #ifdef CONFIG_SYSCTL_SYSCALL_CHECK |
| 1755 | if (sysctl_check_table(namespaces, header->ctl_table)) { | 1864 | if (sysctl_check_table(namespaces, header->ctl_table)) { |
| 1756 | kfree(header); | 1865 | kfree(header); |
| @@ -1758,8 +1867,20 @@ struct ctl_table_header *__register_sysctl_paths( | |||
| 1758 | } | 1867 | } |
| 1759 | #endif | 1868 | #endif |
| 1760 | spin_lock(&sysctl_lock); | 1869 | spin_lock(&sysctl_lock); |
| 1761 | header_list = lookup_header_list(root, namespaces); | 1870 | header->set = lookup_header_set(root, namespaces); |
| 1762 | list_add_tail(&header->ctl_entry, header_list); | 1871 | header->attached_by = header->ctl_table; |
| 1872 | header->attached_to = root_table; | ||
| 1873 | header->parent = &root_table_header; | ||
| 1874 | for (set = header->set; set; set = set->parent) { | ||
| 1875 | struct ctl_table_header *p; | ||
| 1876 | list_for_each_entry(p, &set->list, ctl_entry) { | ||
| 1877 | if (p->unregistering) | ||
| 1878 | continue; | ||
| 1879 | try_attach(p, header); | ||
| 1880 | } | ||
| 1881 | } | ||
| 1882 | header->parent->count++; | ||
| 1883 | list_add_tail(&header->ctl_entry, &header->set->list); | ||
| 1763 | spin_unlock(&sysctl_lock); | 1884 | spin_unlock(&sysctl_lock); |
| 1764 | 1885 | ||
| 1765 | return header; | 1886 | return header; |
| @@ -1814,8 +1935,37 @@ void unregister_sysctl_table(struct ctl_table_header * header) | |||
| 1814 | 1935 | ||
| 1815 | spin_lock(&sysctl_lock); | 1936 | spin_lock(&sysctl_lock); |
| 1816 | start_unregistering(header); | 1937 | start_unregistering(header); |
| 1938 | if (!--header->parent->count) { | ||
| 1939 | WARN_ON(1); | ||
| 1940 | kfree(header->parent); | ||
| 1941 | } | ||
| 1942 | if (!--header->count) | ||
| 1943 | kfree(header); | ||
| 1944 | spin_unlock(&sysctl_lock); | ||
| 1945 | } | ||
| 1946 | |||
| 1947 | int sysctl_is_seen(struct ctl_table_header *p) | ||
| 1948 | { | ||
| 1949 | struct ctl_table_set *set = p->set; | ||
| 1950 | int res; | ||
| 1951 | spin_lock(&sysctl_lock); | ||
| 1952 | if (p->unregistering) | ||
| 1953 | res = 0; | ||
| 1954 | else if (!set->is_seen) | ||
| 1955 | res = 1; | ||
| 1956 | else | ||
| 1957 | res = set->is_seen(set); | ||
| 1817 | spin_unlock(&sysctl_lock); | 1958 | spin_unlock(&sysctl_lock); |
| 1818 | kfree(header); | 1959 | return res; |
| 1960 | } | ||
| 1961 | |||
| 1962 | void setup_sysctl_set(struct ctl_table_set *p, | ||
| 1963 | struct ctl_table_set *parent, | ||
| 1964 | int (*is_seen)(struct ctl_table_set *)) | ||
| 1965 | { | ||
| 1966 | INIT_LIST_HEAD(&p->list); | ||
| 1967 | p->parent = parent ? parent : &sysctl_table_root.default_set; | ||
| 1968 | p->is_seen = is_seen; | ||
| 1819 | } | 1969 | } |
| 1820 | 1970 | ||
| 1821 | #else /* !CONFIG_SYSCTL */ | 1971 | #else /* !CONFIG_SYSCTL */ |
| @@ -1834,6 +1984,16 @@ void unregister_sysctl_table(struct ctl_table_header * table) | |||
| 1834 | { | 1984 | { |
| 1835 | } | 1985 | } |
| 1836 | 1986 | ||
| 1987 | void setup_sysctl_set(struct ctl_table_set *p, | ||
| 1988 | struct ctl_table_set *parent, | ||
| 1989 | int (*is_seen)(struct ctl_table_set *)) | ||
| 1990 | { | ||
| 1991 | } | ||
| 1992 | |||
| 1993 | void sysctl_head_put(struct ctl_table_header *head) | ||
| 1994 | { | ||
| 1995 | } | ||
| 1996 | |||
| 1837 | #endif /* CONFIG_SYSCTL */ | 1997 | #endif /* CONFIG_SYSCTL */ |
| 1838 | 1998 | ||
| 1839 | /* | 1999 | /* |
| @@ -2086,49 +2246,39 @@ int proc_dointvec(struct ctl_table *table, int write, struct file *filp, | |||
| 2086 | NULL,NULL); | 2246 | NULL,NULL); |
| 2087 | } | 2247 | } |
| 2088 | 2248 | ||
| 2089 | #define OP_SET 0 | ||
| 2090 | #define OP_AND 1 | ||
| 2091 | #define OP_OR 2 | ||
| 2092 | |||
| 2093 | static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp, | ||
| 2094 | int *valp, | ||
| 2095 | int write, void *data) | ||
| 2096 | { | ||
| 2097 | int op = *(int *)data; | ||
| 2098 | if (write) { | ||
| 2099 | int val = *negp ? -*lvalp : *lvalp; | ||
| 2100 | switch(op) { | ||
| 2101 | case OP_SET: *valp = val; break; | ||
| 2102 | case OP_AND: *valp &= val; break; | ||
| 2103 | case OP_OR: *valp |= val; break; | ||
| 2104 | } | ||
| 2105 | } else { | ||
| 2106 | int val = *valp; | ||
| 2107 | if (val < 0) { | ||
| 2108 | *negp = -1; | ||
| 2109 | *lvalp = (unsigned long)-val; | ||
| 2110 | } else { | ||
| 2111 | *negp = 0; | ||
| 2112 | *lvalp = (unsigned long)val; | ||
| 2113 | } | ||
| 2114 | } | ||
| 2115 | return 0; | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | /* | 2249 | /* |
| 2119 | * Taint values can only be increased | 2250 | * Taint values can only be increased |
| 2251 | * This means we can safely use a temporary. | ||
| 2120 | */ | 2252 | */ |
| 2121 | static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp, | 2253 | static int proc_taint(struct ctl_table *table, int write, struct file *filp, |
| 2122 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2254 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 2123 | { | 2255 | { |
| 2124 | int op; | 2256 | struct ctl_table t; |
| 2257 | unsigned long tmptaint = get_taint(); | ||
| 2258 | int err; | ||
| 2125 | 2259 | ||
| 2126 | if (write && !capable(CAP_SYS_ADMIN)) | 2260 | if (write && !capable(CAP_SYS_ADMIN)) |
| 2127 | return -EPERM; | 2261 | return -EPERM; |
| 2128 | 2262 | ||
| 2129 | op = OP_OR; | 2263 | t = *table; |
| 2130 | return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, | 2264 | t.data = &tmptaint; |
| 2131 | do_proc_dointvec_bset_conv,&op); | 2265 | err = proc_doulongvec_minmax(&t, write, filp, buffer, lenp, ppos); |
| 2266 | if (err < 0) | ||
| 2267 | return err; | ||
| 2268 | |||
| 2269 | if (write) { | ||
| 2270 | /* | ||
| 2271 | * Poor man's atomic or. Not worth adding a primitive | ||
| 2272 | * to everyone's atomic.h for this | ||
| 2273 | */ | ||
| 2274 | int i; | ||
| 2275 | for (i = 0; i < BITS_PER_LONG && tmptaint >> i; i++) { | ||
| 2276 | if ((tmptaint >> i) & 1) | ||
| 2277 | add_taint(i); | ||
| 2278 | } | ||
| 2279 | } | ||
| 2280 | |||
| 2281 | return err; | ||
| 2132 | } | 2282 | } |
| 2133 | 2283 | ||
| 2134 | struct do_proc_dointvec_minmax_conv_param { | 2284 | struct do_proc_dointvec_minmax_conv_param { |
| @@ -2576,7 +2726,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write, | |||
| 2576 | */ | 2726 | */ |
| 2577 | 2727 | ||
| 2578 | /* The generic sysctl data routine (used if no strategy routine supplied) */ | 2728 | /* The generic sysctl data routine (used if no strategy routine supplied) */ |
| 2579 | int sysctl_data(struct ctl_table *table, int __user *name, int nlen, | 2729 | int sysctl_data(struct ctl_table *table, |
| 2580 | void __user *oldval, size_t __user *oldlenp, | 2730 | void __user *oldval, size_t __user *oldlenp, |
| 2581 | void __user *newval, size_t newlen) | 2731 | void __user *newval, size_t newlen) |
| 2582 | { | 2732 | { |
| @@ -2610,7 +2760,7 @@ int sysctl_data(struct ctl_table *table, int __user *name, int nlen, | |||
| 2610 | } | 2760 | } |
| 2611 | 2761 | ||
| 2612 | /* The generic string strategy routine: */ | 2762 | /* The generic string strategy routine: */ |
| 2613 | int sysctl_string(struct ctl_table *table, int __user *name, int nlen, | 2763 | int sysctl_string(struct ctl_table *table, |
| 2614 | void __user *oldval, size_t __user *oldlenp, | 2764 | void __user *oldval, size_t __user *oldlenp, |
| 2615 | void __user *newval, size_t newlen) | 2765 | void __user *newval, size_t newlen) |
| 2616 | { | 2766 | { |
| @@ -2656,7 +2806,7 @@ int sysctl_string(struct ctl_table *table, int __user *name, int nlen, | |||
| 2656 | * are between the minimum and maximum values given in the arrays | 2806 | * are between the minimum and maximum values given in the arrays |
| 2657 | * table->extra1 and table->extra2, respectively. | 2807 | * table->extra1 and table->extra2, respectively. |
| 2658 | */ | 2808 | */ |
| 2659 | int sysctl_intvec(struct ctl_table *table, int __user *name, int nlen, | 2809 | int sysctl_intvec(struct ctl_table *table, |
| 2660 | void __user *oldval, size_t __user *oldlenp, | 2810 | void __user *oldval, size_t __user *oldlenp, |
| 2661 | void __user *newval, size_t newlen) | 2811 | void __user *newval, size_t newlen) |
| 2662 | { | 2812 | { |
| @@ -2692,7 +2842,7 @@ int sysctl_intvec(struct ctl_table *table, int __user *name, int nlen, | |||
| 2692 | } | 2842 | } |
| 2693 | 2843 | ||
| 2694 | /* Strategy function to convert jiffies to seconds */ | 2844 | /* Strategy function to convert jiffies to seconds */ |
| 2695 | int sysctl_jiffies(struct ctl_table *table, int __user *name, int nlen, | 2845 | int sysctl_jiffies(struct ctl_table *table, |
| 2696 | void __user *oldval, size_t __user *oldlenp, | 2846 | void __user *oldval, size_t __user *oldlenp, |
| 2697 | void __user *newval, size_t newlen) | 2847 | void __user *newval, size_t newlen) |
| 2698 | { | 2848 | { |
| @@ -2726,7 +2876,7 @@ int sysctl_jiffies(struct ctl_table *table, int __user *name, int nlen, | |||
| 2726 | } | 2876 | } |
| 2727 | 2877 | ||
| 2728 | /* Strategy function to convert jiffies to seconds */ | 2878 | /* Strategy function to convert jiffies to seconds */ |
| 2729 | int sysctl_ms_jiffies(struct ctl_table *table, int __user *name, int nlen, | 2879 | int sysctl_ms_jiffies(struct ctl_table *table, |
| 2730 | void __user *oldval, size_t __user *oldlenp, | 2880 | void __user *oldval, size_t __user *oldlenp, |
| 2731 | void __user *newval, size_t newlen) | 2881 | void __user *newval, size_t newlen) |
| 2732 | { | 2882 | { |
| @@ -2781,35 +2931,35 @@ asmlinkage long sys_sysctl(struct __sysctl_args __user *args) | |||
| 2781 | return error; | 2931 | return error; |
| 2782 | } | 2932 | } |
| 2783 | 2933 | ||
| 2784 | int sysctl_data(struct ctl_table *table, int __user *name, int nlen, | 2934 | int sysctl_data(struct ctl_table *table, |
| 2785 | void __user *oldval, size_t __user *oldlenp, | 2935 | void __user *oldval, size_t __user *oldlenp, |
| 2786 | void __user *newval, size_t newlen) | 2936 | void __user *newval, size_t newlen) |
| 2787 | { | 2937 | { |
| 2788 | return -ENOSYS; | 2938 | return -ENOSYS; |
| 2789 | } | 2939 | } |
| 2790 | 2940 | ||
| 2791 | int sysctl_string(struct ctl_table *table, int __user *name, int nlen, | 2941 | int sysctl_string(struct ctl_table *table, |
| 2792 | void __user *oldval, size_t __user *oldlenp, | 2942 | void __user *oldval, size_t __user *oldlenp, |
| 2793 | void __user *newval, size_t newlen) | 2943 | void __user *newval, size_t newlen) |
| 2794 | { | 2944 | { |
| 2795 | return -ENOSYS; | 2945 | return -ENOSYS; |
| 2796 | } | 2946 | } |
| 2797 | 2947 | ||
| 2798 | int sysctl_intvec(struct ctl_table *table, int __user *name, int nlen, | 2948 | int sysctl_intvec(struct ctl_table *table, |
| 2799 | void __user *oldval, size_t __user *oldlenp, | 2949 | void __user *oldval, size_t __user *oldlenp, |
| 2800 | void __user *newval, size_t newlen) | 2950 | void __user *newval, size_t newlen) |
| 2801 | { | 2951 | { |
| 2802 | return -ENOSYS; | 2952 | return -ENOSYS; |
| 2803 | } | 2953 | } |
| 2804 | 2954 | ||
| 2805 | int sysctl_jiffies(struct ctl_table *table, int __user *name, int nlen, | 2955 | int sysctl_jiffies(struct ctl_table *table, |
| 2806 | void __user *oldval, size_t __user *oldlenp, | 2956 | void __user *oldval, size_t __user *oldlenp, |
| 2807 | void __user *newval, size_t newlen) | 2957 | void __user *newval, size_t newlen) |
| 2808 | { | 2958 | { |
| 2809 | return -ENOSYS; | 2959 | return -ENOSYS; |
| 2810 | } | 2960 | } |
| 2811 | 2961 | ||
| 2812 | int sysctl_ms_jiffies(struct ctl_table *table, int __user *name, int nlen, | 2962 | int sysctl_ms_jiffies(struct ctl_table *table, |
| 2813 | void __user *oldval, size_t __user *oldlenp, | 2963 | void __user *oldval, size_t __user *oldlenp, |
| 2814 | void __user *newval, size_t newlen) | 2964 | void __user *newval, size_t newlen) |
| 2815 | { | 2965 | { |
