diff options
Diffstat (limited to 'kernel/sysctl.c')
| -rw-r--r-- | kernel/sysctl.c | 125 |
1 files changed, 99 insertions, 26 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 74f5b580fe34..75b22e22a72c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -136,7 +136,6 @@ static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; | |||
| 136 | /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ | 136 | /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ |
| 137 | static int maxolduid = 65535; | 137 | static int maxolduid = 65535; |
| 138 | static int minolduid; | 138 | static int minolduid; |
| 139 | static int min_percpu_pagelist_fract = 8; | ||
| 140 | 139 | ||
| 141 | static int ngroups_max = NGROUPS_MAX; | 140 | static int ngroups_max = NGROUPS_MAX; |
| 142 | static const int cap_last_cap = CAP_LAST_CAP; | 141 | static const int cap_last_cap = CAP_LAST_CAP; |
| @@ -152,10 +151,6 @@ static unsigned long hung_task_timeout_max = (LONG_MAX/HZ); | |||
| 152 | #ifdef CONFIG_SPARC | 151 | #ifdef CONFIG_SPARC |
| 153 | #endif | 152 | #endif |
| 154 | 153 | ||
| 155 | #ifdef CONFIG_SPARC64 | ||
| 156 | extern int sysctl_tsb_ratio; | ||
| 157 | #endif | ||
| 158 | |||
| 159 | #ifdef __hppa__ | 154 | #ifdef __hppa__ |
| 160 | extern int pwrsw_enabled; | 155 | extern int pwrsw_enabled; |
| 161 | #endif | 156 | #endif |
| @@ -173,6 +168,13 @@ extern int no_unaligned_warning; | |||
| 173 | #endif | 168 | #endif |
| 174 | 169 | ||
| 175 | #ifdef CONFIG_PROC_SYSCTL | 170 | #ifdef CONFIG_PROC_SYSCTL |
| 171 | |||
| 172 | #define SYSCTL_WRITES_LEGACY -1 | ||
| 173 | #define SYSCTL_WRITES_WARN 0 | ||
| 174 | #define SYSCTL_WRITES_STRICT 1 | ||
| 175 | |||
| 176 | static int sysctl_writes_strict = SYSCTL_WRITES_WARN; | ||
| 177 | |||
| 176 | static int proc_do_cad_pid(struct ctl_table *table, int write, | 178 | static int proc_do_cad_pid(struct ctl_table *table, int write, |
| 177 | void __user *buffer, size_t *lenp, loff_t *ppos); | 179 | void __user *buffer, size_t *lenp, loff_t *ppos); |
| 178 | static int proc_taint(struct ctl_table *table, int write, | 180 | static int proc_taint(struct ctl_table *table, int write, |
| @@ -195,7 +197,7 @@ static int proc_dostring_coredump(struct ctl_table *table, int write, | |||
| 195 | /* Note: sysrq code uses it's own private copy */ | 197 | /* Note: sysrq code uses it's own private copy */ |
| 196 | static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; | 198 | static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; |
| 197 | 199 | ||
| 198 | static int sysrq_sysctl_handler(ctl_table *table, int write, | 200 | static int sysrq_sysctl_handler(struct ctl_table *table, int write, |
| 199 | void __user *buffer, size_t *lenp, | 201 | void __user *buffer, size_t *lenp, |
| 200 | loff_t *ppos) | 202 | loff_t *ppos) |
| 201 | { | 203 | { |
| @@ -495,6 +497,15 @@ static struct ctl_table kern_table[] = { | |||
| 495 | .mode = 0644, | 497 | .mode = 0644, |
| 496 | .proc_handler = proc_taint, | 498 | .proc_handler = proc_taint, |
| 497 | }, | 499 | }, |
| 500 | { | ||
| 501 | .procname = "sysctl_writes_strict", | ||
| 502 | .data = &sysctl_writes_strict, | ||
| 503 | .maxlen = sizeof(int), | ||
| 504 | .mode = 0644, | ||
| 505 | .proc_handler = proc_dointvec_minmax, | ||
| 506 | .extra1 = &neg_one, | ||
| 507 | .extra2 = &one, | ||
| 508 | }, | ||
| 498 | #endif | 509 | #endif |
| 499 | #ifdef CONFIG_LATENCYTOP | 510 | #ifdef CONFIG_LATENCYTOP |
| 500 | { | 511 | { |
| @@ -643,7 +654,7 @@ static struct ctl_table kern_table[] = { | |||
| 643 | .extra2 = &one, | 654 | .extra2 = &one, |
| 644 | }, | 655 | }, |
| 645 | #endif | 656 | #endif |
| 646 | 657 | #ifdef CONFIG_UEVENT_HELPER | |
| 647 | { | 658 | { |
| 648 | .procname = "hotplug", | 659 | .procname = "hotplug", |
| 649 | .data = &uevent_helper, | 660 | .data = &uevent_helper, |
| @@ -651,7 +662,7 @@ static struct ctl_table kern_table[] = { | |||
| 651 | .mode = 0644, | 662 | .mode = 0644, |
| 652 | .proc_handler = proc_dostring, | 663 | .proc_handler = proc_dostring, |
| 653 | }, | 664 | }, |
| 654 | 665 | #endif | |
| 655 | #ifdef CONFIG_CHR_DEV_SG | 666 | #ifdef CONFIG_CHR_DEV_SG |
| 656 | { | 667 | { |
| 657 | .procname = "sg-big-buff", | 668 | .procname = "sg-big-buff", |
| @@ -849,6 +860,17 @@ static struct ctl_table kern_table[] = { | |||
| 849 | .extra1 = &zero, | 860 | .extra1 = &zero, |
| 850 | .extra2 = &one, | 861 | .extra2 = &one, |
| 851 | }, | 862 | }, |
| 863 | #ifdef CONFIG_SMP | ||
| 864 | { | ||
| 865 | .procname = "softlockup_all_cpu_backtrace", | ||
| 866 | .data = &sysctl_softlockup_all_cpu_backtrace, | ||
| 867 | .maxlen = sizeof(int), | ||
| 868 | .mode = 0644, | ||
| 869 | .proc_handler = proc_dointvec_minmax, | ||
| 870 | .extra1 = &zero, | ||
| 871 | .extra2 = &one, | ||
| 872 | }, | ||
| 873 | #endif /* CONFIG_SMP */ | ||
| 852 | { | 874 | { |
| 853 | .procname = "nmi_watchdog", | 875 | .procname = "nmi_watchdog", |
| 854 | .data = &watchdog_user_enabled, | 876 | .data = &watchdog_user_enabled, |
| @@ -1305,7 +1327,7 @@ static struct ctl_table vm_table[] = { | |||
| 1305 | .maxlen = sizeof(percpu_pagelist_fraction), | 1327 | .maxlen = sizeof(percpu_pagelist_fraction), |
| 1306 | .mode = 0644, | 1328 | .mode = 0644, |
| 1307 | .proc_handler = percpu_pagelist_fraction_sysctl_handler, | 1329 | .proc_handler = percpu_pagelist_fraction_sysctl_handler, |
| 1308 | .extra1 = &min_percpu_pagelist_fract, | 1330 | .extra1 = &zero, |
| 1309 | }, | 1331 | }, |
| 1310 | #ifdef CONFIG_MMU | 1332 | #ifdef CONFIG_MMU |
| 1311 | { | 1333 | { |
| @@ -1418,8 +1440,13 @@ static struct ctl_table vm_table[] = { | |||
| 1418 | (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL)) | 1440 | (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL)) |
| 1419 | { | 1441 | { |
| 1420 | .procname = "vdso_enabled", | 1442 | .procname = "vdso_enabled", |
| 1443 | #ifdef CONFIG_X86_32 | ||
| 1444 | .data = &vdso32_enabled, | ||
| 1445 | .maxlen = sizeof(vdso32_enabled), | ||
| 1446 | #else | ||
| 1421 | .data = &vdso_enabled, | 1447 | .data = &vdso_enabled, |
| 1422 | .maxlen = sizeof(vdso_enabled), | 1448 | .maxlen = sizeof(vdso_enabled), |
| 1449 | #endif | ||
| 1423 | .mode = 0644, | 1450 | .mode = 0644, |
| 1424 | .proc_handler = proc_dointvec, | 1451 | .proc_handler = proc_dointvec, |
| 1425 | .extra1 = &zero, | 1452 | .extra1 = &zero, |
| @@ -1698,8 +1725,8 @@ int __init sysctl_init(void) | |||
| 1698 | 1725 | ||
| 1699 | #ifdef CONFIG_PROC_SYSCTL | 1726 | #ifdef CONFIG_PROC_SYSCTL |
| 1700 | 1727 | ||
| 1701 | static int _proc_do_string(void* data, int maxlen, int write, | 1728 | static int _proc_do_string(char *data, int maxlen, int write, |
| 1702 | void __user *buffer, | 1729 | char __user *buffer, |
| 1703 | size_t *lenp, loff_t *ppos) | 1730 | size_t *lenp, loff_t *ppos) |
| 1704 | { | 1731 | { |
| 1705 | size_t len; | 1732 | size_t len; |
| @@ -1712,21 +1739,30 @@ static int _proc_do_string(void* data, int maxlen, int write, | |||
| 1712 | } | 1739 | } |
| 1713 | 1740 | ||
| 1714 | if (write) { | 1741 | if (write) { |
| 1715 | len = 0; | 1742 | if (sysctl_writes_strict == SYSCTL_WRITES_STRICT) { |
| 1743 | /* Only continue writes not past the end of buffer. */ | ||
| 1744 | len = strlen(data); | ||
| 1745 | if (len > maxlen - 1) | ||
| 1746 | len = maxlen - 1; | ||
| 1747 | |||
| 1748 | if (*ppos > len) | ||
| 1749 | return 0; | ||
| 1750 | len = *ppos; | ||
| 1751 | } else { | ||
| 1752 | /* Start writing from beginning of buffer. */ | ||
| 1753 | len = 0; | ||
| 1754 | } | ||
| 1755 | |||
| 1756 | *ppos += *lenp; | ||
| 1716 | p = buffer; | 1757 | p = buffer; |
| 1717 | while (len < *lenp) { | 1758 | while ((p - buffer) < *lenp && len < maxlen - 1) { |
| 1718 | if (get_user(c, p++)) | 1759 | if (get_user(c, p++)) |
| 1719 | return -EFAULT; | 1760 | return -EFAULT; |
| 1720 | if (c == 0 || c == '\n') | 1761 | if (c == 0 || c == '\n') |
| 1721 | break; | 1762 | break; |
| 1722 | len++; | 1763 | data[len++] = c; |
| 1723 | } | 1764 | } |
| 1724 | if (len >= maxlen) | 1765 | data[len] = 0; |
| 1725 | len = maxlen-1; | ||
| 1726 | if(copy_from_user(data, buffer, len)) | ||
| 1727 | return -EFAULT; | ||
| 1728 | ((char *) data)[len] = 0; | ||
| 1729 | *ppos += *lenp; | ||
| 1730 | } else { | 1766 | } else { |
| 1731 | len = strlen(data); | 1767 | len = strlen(data); |
| 1732 | if (len > maxlen) | 1768 | if (len > maxlen) |
| @@ -1743,10 +1779,10 @@ static int _proc_do_string(void* data, int maxlen, int write, | |||
| 1743 | if (len > *lenp) | 1779 | if (len > *lenp) |
| 1744 | len = *lenp; | 1780 | len = *lenp; |
| 1745 | if (len) | 1781 | if (len) |
| 1746 | if(copy_to_user(buffer, data, len)) | 1782 | if (copy_to_user(buffer, data, len)) |
| 1747 | return -EFAULT; | 1783 | return -EFAULT; |
| 1748 | if (len < *lenp) { | 1784 | if (len < *lenp) { |
| 1749 | if(put_user('\n', ((char __user *) buffer) + len)) | 1785 | if (put_user('\n', buffer + len)) |
| 1750 | return -EFAULT; | 1786 | return -EFAULT; |
| 1751 | len++; | 1787 | len++; |
| 1752 | } | 1788 | } |
| @@ -1756,6 +1792,14 @@ static int _proc_do_string(void* data, int maxlen, int write, | |||
| 1756 | return 0; | 1792 | return 0; |
| 1757 | } | 1793 | } |
| 1758 | 1794 | ||
| 1795 | static void warn_sysctl_write(struct ctl_table *table) | ||
| 1796 | { | ||
| 1797 | pr_warn_once("%s wrote to %s when file position was not 0!\n" | ||
| 1798 | "This will not be supported in the future. To silence this\n" | ||
| 1799 | "warning, set kernel.sysctl_writes_strict = -1\n", | ||
| 1800 | current->comm, table->procname); | ||
| 1801 | } | ||
| 1802 | |||
| 1759 | /** | 1803 | /** |
| 1760 | * proc_dostring - read a string sysctl | 1804 | * proc_dostring - read a string sysctl |
| 1761 | * @table: the sysctl table | 1805 | * @table: the sysctl table |
| @@ -1776,8 +1820,11 @@ static int _proc_do_string(void* data, int maxlen, int write, | |||
| 1776 | int proc_dostring(struct ctl_table *table, int write, | 1820 | int proc_dostring(struct ctl_table *table, int write, |
| 1777 | void __user *buffer, size_t *lenp, loff_t *ppos) | 1821 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 1778 | { | 1822 | { |
| 1779 | return _proc_do_string(table->data, table->maxlen, write, | 1823 | if (write && *ppos && sysctl_writes_strict == SYSCTL_WRITES_WARN) |
| 1780 | buffer, lenp, ppos); | 1824 | warn_sysctl_write(table); |
| 1825 | |||
| 1826 | return _proc_do_string((char *)(table->data), table->maxlen, write, | ||
| 1827 | (char __user *)buffer, lenp, ppos); | ||
| 1781 | } | 1828 | } |
| 1782 | 1829 | ||
| 1783 | static size_t proc_skip_spaces(char **buf) | 1830 | static size_t proc_skip_spaces(char **buf) |
| @@ -1951,6 +1998,18 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, | |||
| 1951 | conv = do_proc_dointvec_conv; | 1998 | conv = do_proc_dointvec_conv; |
| 1952 | 1999 | ||
| 1953 | if (write) { | 2000 | if (write) { |
| 2001 | if (*ppos) { | ||
| 2002 | switch (sysctl_writes_strict) { | ||
| 2003 | case SYSCTL_WRITES_STRICT: | ||
| 2004 | goto out; | ||
| 2005 | case SYSCTL_WRITES_WARN: | ||
| 2006 | warn_sysctl_write(table); | ||
| 2007 | break; | ||
| 2008 | default: | ||
| 2009 | break; | ||
| 2010 | } | ||
| 2011 | } | ||
| 2012 | |||
| 1954 | if (left > PAGE_SIZE - 1) | 2013 | if (left > PAGE_SIZE - 1) |
| 1955 | left = PAGE_SIZE - 1; | 2014 | left = PAGE_SIZE - 1; |
| 1956 | page = __get_free_page(GFP_TEMPORARY); | 2015 | page = __get_free_page(GFP_TEMPORARY); |
| @@ -2008,6 +2067,7 @@ free: | |||
| 2008 | return err ? : -EINVAL; | 2067 | return err ? : -EINVAL; |
| 2009 | } | 2068 | } |
| 2010 | *lenp -= left; | 2069 | *lenp -= left; |
| 2070 | out: | ||
| 2011 | *ppos += *lenp; | 2071 | *ppos += *lenp; |
| 2012 | return err; | 2072 | return err; |
| 2013 | } | 2073 | } |
| @@ -2200,6 +2260,18 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int | |||
| 2200 | left = *lenp; | 2260 | left = *lenp; |
| 2201 | 2261 | ||
| 2202 | if (write) { | 2262 | if (write) { |
| 2263 | if (*ppos) { | ||
| 2264 | switch (sysctl_writes_strict) { | ||
| 2265 | case SYSCTL_WRITES_STRICT: | ||
| 2266 | goto out; | ||
| 2267 | case SYSCTL_WRITES_WARN: | ||
| 2268 | warn_sysctl_write(table); | ||
| 2269 | break; | ||
| 2270 | default: | ||
| 2271 | break; | ||
| 2272 | } | ||
| 2273 | } | ||
| 2274 | |||
| 2203 | if (left > PAGE_SIZE - 1) | 2275 | if (left > PAGE_SIZE - 1) |
| 2204 | left = PAGE_SIZE - 1; | 2276 | left = PAGE_SIZE - 1; |
| 2205 | page = __get_free_page(GFP_TEMPORARY); | 2277 | page = __get_free_page(GFP_TEMPORARY); |
| @@ -2255,6 +2327,7 @@ free: | |||
| 2255 | return err ? : -EINVAL; | 2327 | return err ? : -EINVAL; |
| 2256 | } | 2328 | } |
| 2257 | *lenp -= left; | 2329 | *lenp -= left; |
| 2330 | out: | ||
| 2258 | *ppos += *lenp; | 2331 | *ppos += *lenp; |
| 2259 | return err; | 2332 | return err; |
| 2260 | } | 2333 | } |
| @@ -2501,11 +2574,11 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, | |||
| 2501 | bool first = 1; | 2574 | bool first = 1; |
| 2502 | size_t left = *lenp; | 2575 | size_t left = *lenp; |
| 2503 | unsigned long bitmap_len = table->maxlen; | 2576 | unsigned long bitmap_len = table->maxlen; |
| 2504 | unsigned long *bitmap = (unsigned long *) table->data; | 2577 | unsigned long *bitmap = *(unsigned long **) table->data; |
| 2505 | unsigned long *tmp_bitmap = NULL; | 2578 | unsigned long *tmp_bitmap = NULL; |
| 2506 | char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c; | 2579 | char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c; |
| 2507 | 2580 | ||
| 2508 | if (!bitmap_len || !left || (*ppos && !write)) { | 2581 | if (!bitmap || !bitmap_len || !left || (*ppos && !write)) { |
| 2509 | *lenp = 0; | 2582 | *lenp = 0; |
| 2510 | return 0; | 2583 | return 0; |
| 2511 | } | 2584 | } |
