diff options
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 94 |
1 files changed, 78 insertions, 16 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 40ce2d983b12..db19e3e2aa4b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -173,6 +173,13 @@ extern int no_unaligned_warning; | |||
173 | #endif | 173 | #endif |
174 | 174 | ||
175 | #ifdef CONFIG_PROC_SYSCTL | 175 | #ifdef CONFIG_PROC_SYSCTL |
176 | |||
177 | #define SYSCTL_WRITES_LEGACY -1 | ||
178 | #define SYSCTL_WRITES_WARN 0 | ||
179 | #define SYSCTL_WRITES_STRICT 1 | ||
180 | |||
181 | static int sysctl_writes_strict = SYSCTL_WRITES_WARN; | ||
182 | |||
176 | static int proc_do_cad_pid(struct ctl_table *table, int write, | 183 | static int proc_do_cad_pid(struct ctl_table *table, int write, |
177 | void __user *buffer, size_t *lenp, loff_t *ppos); | 184 | void __user *buffer, size_t *lenp, loff_t *ppos); |
178 | static int proc_taint(struct ctl_table *table, int write, | 185 | static int proc_taint(struct ctl_table *table, int write, |
@@ -195,7 +202,7 @@ static int proc_dostring_coredump(struct ctl_table *table, int write, | |||
195 | /* Note: sysrq code uses it's own private copy */ | 202 | /* Note: sysrq code uses it's own private copy */ |
196 | static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; | 203 | static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; |
197 | 204 | ||
198 | static int sysrq_sysctl_handler(ctl_table *table, int write, | 205 | static int sysrq_sysctl_handler(struct ctl_table *table, int write, |
199 | void __user *buffer, size_t *lenp, | 206 | void __user *buffer, size_t *lenp, |
200 | loff_t *ppos) | 207 | loff_t *ppos) |
201 | { | 208 | { |
@@ -495,6 +502,15 @@ static struct ctl_table kern_table[] = { | |||
495 | .mode = 0644, | 502 | .mode = 0644, |
496 | .proc_handler = proc_taint, | 503 | .proc_handler = proc_taint, |
497 | }, | 504 | }, |
505 | { | ||
506 | .procname = "sysctl_writes_strict", | ||
507 | .data = &sysctl_writes_strict, | ||
508 | .maxlen = sizeof(int), | ||
509 | .mode = 0644, | ||
510 | .proc_handler = proc_dointvec_minmax, | ||
511 | .extra1 = &neg_one, | ||
512 | .extra2 = &one, | ||
513 | }, | ||
498 | #endif | 514 | #endif |
499 | #ifdef CONFIG_LATENCYTOP | 515 | #ifdef CONFIG_LATENCYTOP |
500 | { | 516 | { |
@@ -1703,8 +1719,8 @@ int __init sysctl_init(void) | |||
1703 | 1719 | ||
1704 | #ifdef CONFIG_PROC_SYSCTL | 1720 | #ifdef CONFIG_PROC_SYSCTL |
1705 | 1721 | ||
1706 | static int _proc_do_string(void* data, int maxlen, int write, | 1722 | static int _proc_do_string(char *data, int maxlen, int write, |
1707 | void __user *buffer, | 1723 | char __user *buffer, |
1708 | size_t *lenp, loff_t *ppos) | 1724 | size_t *lenp, loff_t *ppos) |
1709 | { | 1725 | { |
1710 | size_t len; | 1726 | size_t len; |
@@ -1717,21 +1733,30 @@ static int _proc_do_string(void* data, int maxlen, int write, | |||
1717 | } | 1733 | } |
1718 | 1734 | ||
1719 | if (write) { | 1735 | if (write) { |
1720 | len = 0; | 1736 | if (sysctl_writes_strict == SYSCTL_WRITES_STRICT) { |
1737 | /* Only continue writes not past the end of buffer. */ | ||
1738 | len = strlen(data); | ||
1739 | if (len > maxlen - 1) | ||
1740 | len = maxlen - 1; | ||
1741 | |||
1742 | if (*ppos > len) | ||
1743 | return 0; | ||
1744 | len = *ppos; | ||
1745 | } else { | ||
1746 | /* Start writing from beginning of buffer. */ | ||
1747 | len = 0; | ||
1748 | } | ||
1749 | |||
1750 | *ppos += *lenp; | ||
1721 | p = buffer; | 1751 | p = buffer; |
1722 | while (len < *lenp) { | 1752 | while ((p - buffer) < *lenp && len < maxlen - 1) { |
1723 | if (get_user(c, p++)) | 1753 | if (get_user(c, p++)) |
1724 | return -EFAULT; | 1754 | return -EFAULT; |
1725 | if (c == 0 || c == '\n') | 1755 | if (c == 0 || c == '\n') |
1726 | break; | 1756 | break; |
1727 | len++; | 1757 | data[len++] = c; |
1728 | } | 1758 | } |
1729 | if (len >= maxlen) | 1759 | data[len] = 0; |
1730 | len = maxlen-1; | ||
1731 | if(copy_from_user(data, buffer, len)) | ||
1732 | return -EFAULT; | ||
1733 | ((char *) data)[len] = 0; | ||
1734 | *ppos += *lenp; | ||
1735 | } else { | 1760 | } else { |
1736 | len = strlen(data); | 1761 | len = strlen(data); |
1737 | if (len > maxlen) | 1762 | if (len > maxlen) |
@@ -1748,10 +1773,10 @@ static int _proc_do_string(void* data, int maxlen, int write, | |||
1748 | if (len > *lenp) | 1773 | if (len > *lenp) |
1749 | len = *lenp; | 1774 | len = *lenp; |
1750 | if (len) | 1775 | if (len) |
1751 | if(copy_to_user(buffer, data, len)) | 1776 | if (copy_to_user(buffer, data, len)) |
1752 | return -EFAULT; | 1777 | return -EFAULT; |
1753 | if (len < *lenp) { | 1778 | if (len < *lenp) { |
1754 | if(put_user('\n', ((char __user *) buffer) + len)) | 1779 | if (put_user('\n', buffer + len)) |
1755 | return -EFAULT; | 1780 | return -EFAULT; |
1756 | len++; | 1781 | len++; |
1757 | } | 1782 | } |
@@ -1761,6 +1786,14 @@ static int _proc_do_string(void* data, int maxlen, int write, | |||
1761 | return 0; | 1786 | return 0; |
1762 | } | 1787 | } |
1763 | 1788 | ||
1789 | static void warn_sysctl_write(struct ctl_table *table) | ||
1790 | { | ||
1791 | pr_warn_once("%s wrote to %s when file position was not 0!\n" | ||
1792 | "This will not be supported in the future. To silence this\n" | ||
1793 | "warning, set kernel.sysctl_writes_strict = -1\n", | ||
1794 | current->comm, table->procname); | ||
1795 | } | ||
1796 | |||
1764 | /** | 1797 | /** |
1765 | * proc_dostring - read a string sysctl | 1798 | * proc_dostring - read a string sysctl |
1766 | * @table: the sysctl table | 1799 | * @table: the sysctl table |
@@ -1781,8 +1814,11 @@ static int _proc_do_string(void* data, int maxlen, int write, | |||
1781 | int proc_dostring(struct ctl_table *table, int write, | 1814 | int proc_dostring(struct ctl_table *table, int write, |
1782 | void __user *buffer, size_t *lenp, loff_t *ppos) | 1815 | void __user *buffer, size_t *lenp, loff_t *ppos) |
1783 | { | 1816 | { |
1784 | return _proc_do_string(table->data, table->maxlen, write, | 1817 | if (write && *ppos && sysctl_writes_strict == SYSCTL_WRITES_WARN) |
1785 | buffer, lenp, ppos); | 1818 | warn_sysctl_write(table); |
1819 | |||
1820 | return _proc_do_string((char *)(table->data), table->maxlen, write, | ||
1821 | (char __user *)buffer, lenp, ppos); | ||
1786 | } | 1822 | } |
1787 | 1823 | ||
1788 | static size_t proc_skip_spaces(char **buf) | 1824 | static size_t proc_skip_spaces(char **buf) |
@@ -1956,6 +1992,18 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, | |||
1956 | conv = do_proc_dointvec_conv; | 1992 | conv = do_proc_dointvec_conv; |
1957 | 1993 | ||
1958 | if (write) { | 1994 | if (write) { |
1995 | if (*ppos) { | ||
1996 | switch (sysctl_writes_strict) { | ||
1997 | case SYSCTL_WRITES_STRICT: | ||
1998 | goto out; | ||
1999 | case SYSCTL_WRITES_WARN: | ||
2000 | warn_sysctl_write(table); | ||
2001 | break; | ||
2002 | default: | ||
2003 | break; | ||
2004 | } | ||
2005 | } | ||
2006 | |||
1959 | if (left > PAGE_SIZE - 1) | 2007 | if (left > PAGE_SIZE - 1) |
1960 | left = PAGE_SIZE - 1; | 2008 | left = PAGE_SIZE - 1; |
1961 | page = __get_free_page(GFP_TEMPORARY); | 2009 | page = __get_free_page(GFP_TEMPORARY); |
@@ -2013,6 +2061,7 @@ free: | |||
2013 | return err ? : -EINVAL; | 2061 | return err ? : -EINVAL; |
2014 | } | 2062 | } |
2015 | *lenp -= left; | 2063 | *lenp -= left; |
2064 | out: | ||
2016 | *ppos += *lenp; | 2065 | *ppos += *lenp; |
2017 | return err; | 2066 | return err; |
2018 | } | 2067 | } |
@@ -2205,6 +2254,18 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int | |||
2205 | left = *lenp; | 2254 | left = *lenp; |
2206 | 2255 | ||
2207 | if (write) { | 2256 | if (write) { |
2257 | if (*ppos) { | ||
2258 | switch (sysctl_writes_strict) { | ||
2259 | case SYSCTL_WRITES_STRICT: | ||
2260 | goto out; | ||
2261 | case SYSCTL_WRITES_WARN: | ||
2262 | warn_sysctl_write(table); | ||
2263 | break; | ||
2264 | default: | ||
2265 | break; | ||
2266 | } | ||
2267 | } | ||
2268 | |||
2208 | if (left > PAGE_SIZE - 1) | 2269 | if (left > PAGE_SIZE - 1) |
2209 | left = PAGE_SIZE - 1; | 2270 | left = PAGE_SIZE - 1; |
2210 | page = __get_free_page(GFP_TEMPORARY); | 2271 | page = __get_free_page(GFP_TEMPORARY); |
@@ -2260,6 +2321,7 @@ free: | |||
2260 | return err ? : -EINVAL; | 2321 | return err ? : -EINVAL; |
2261 | } | 2322 | } |
2262 | *lenp -= left; | 2323 | *lenp -= left; |
2324 | out: | ||
2263 | *ppos += *lenp; | 2325 | *ppos += *lenp; |
2264 | return err; | 2326 | return err; |
2265 | } | 2327 | } |