aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r--kernel/sysctl.c94
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
181static int sysctl_writes_strict = SYSCTL_WRITES_WARN;
182
176static int proc_do_cad_pid(struct ctl_table *table, int write, 183static 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);
178static int proc_taint(struct ctl_table *table, int write, 185static 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 */
196static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; 203static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
197 204
198static int sysrq_sysctl_handler(ctl_table *table, int write, 205static 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
1706static int _proc_do_string(void* data, int maxlen, int write, 1722static 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
1789static 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,
1781int proc_dostring(struct ctl_table *table, int write, 1814int 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
1788static size_t proc_skip_spaces(char **buf) 1824static 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;
2064out:
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;
2324out:
2263 *ppos += *lenp; 2325 *ppos += *lenp;
2264 return err; 2326 return err;
2265} 2327}