aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r--kernel/sysctl.c390
1 files changed, 229 insertions, 161 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 8686b0f5fc12..4a976208de29 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2040,8 +2040,122 @@ int proc_dostring(struct ctl_table *table, int write,
2040 buffer, lenp, ppos); 2040 buffer, lenp, ppos);
2041} 2041}
2042 2042
2043static size_t proc_skip_spaces(char **buf)
2044{
2045 size_t ret;
2046 char *tmp = skip_spaces(*buf);
2047 ret = tmp - *buf;
2048 *buf = tmp;
2049 return ret;
2050}
2051
2052#define TMPBUFLEN 22
2053/**
2054 * proc_get_long - reads an ASCII formated integer from a user buffer
2055 *
2056 * @buf - a kernel buffer
2057 * @size - size of the kernel buffer
2058 * @val - this is where the number will be stored
2059 * @neg - set to %TRUE if number is negative
2060 * @perm_tr - a vector which contains the allowed trailers
2061 * @perm_tr_len - size of the perm_tr vector
2062 * @tr - pointer to store the trailer character
2063 *
2064 * In case of success 0 is returned and buf and size are updated with
2065 * the amount of bytes read. If tr is non NULL and a trailing
2066 * character exist (size is non zero after returning from this
2067 * function) tr is updated with the trailing character.
2068 */
2069static int proc_get_long(char **buf, size_t *size,
2070 unsigned long *val, bool *neg,
2071 const char *perm_tr, unsigned perm_tr_len, char *tr)
2072{
2073 int len;
2074 char *p, tmp[TMPBUFLEN];
2075
2076 if (!*size)
2077 return -EINVAL;
2078
2079 len = *size;
2080 if (len > TMPBUFLEN - 1)
2081 len = TMPBUFLEN - 1;
2082
2083 memcpy(tmp, *buf, len);
2084
2085 tmp[len] = 0;
2086 p = tmp;
2087 if (*p == '-' && *size > 1) {
2088 *neg = true;
2089 p++;
2090 } else
2091 *neg = false;
2092 if (!isdigit(*p))
2093 return -EINVAL;
2094
2095 *val = simple_strtoul(p, &p, 0);
2096
2097 len = p - tmp;
2098
2099 /* We don't know if the next char is whitespace thus we may accept
2100 * invalid integers (e.g. 1234...a) or two integers instead of one
2101 * (e.g. 123...1). So lets not allow such large numbers. */
2102 if (len == TMPBUFLEN - 1)
2103 return -EINVAL;
2104
2105 if (len < *size && perm_tr_len && !memchr(perm_tr, *p, perm_tr_len))
2106 return -EINVAL;
2043 2107
2044static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, 2108 if (tr && (len < *size))
2109 *tr = *p;
2110
2111 *buf += len;
2112 *size -= len;
2113
2114 return 0;
2115}
2116
2117/**
2118 * proc_put_long - coverts an integer to a decimal ASCII formated string
2119 *
2120 * @buf - the user buffer
2121 * @size - the size of the user buffer
2122 * @val - the integer to be converted
2123 * @neg - sign of the number, %TRUE for negative
2124 *
2125 * In case of success 0 is returned and buf and size are updated with
2126 * the amount of bytes read.
2127 */
2128static int proc_put_long(void __user **buf, size_t *size, unsigned long val,
2129 bool neg)
2130{
2131 int len;
2132 char tmp[TMPBUFLEN], *p = tmp;
2133
2134 sprintf(p, "%s%lu", neg ? "-" : "", val);
2135 len = strlen(tmp);
2136 if (len > *size)
2137 len = *size;
2138 if (copy_to_user(*buf, tmp, len))
2139 return -EFAULT;
2140 *size -= len;
2141 *buf += len;
2142 return 0;
2143}
2144#undef TMPBUFLEN
2145
2146static int proc_put_char(void __user **buf, size_t *size, char c)
2147{
2148 if (*size) {
2149 char __user **buffer = (char __user **)buf;
2150 if (put_user(c, *buffer))
2151 return -EFAULT;
2152 (*size)--, (*buffer)++;
2153 *buf = *buffer;
2154 }
2155 return 0;
2156}
2157
2158static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
2045 int *valp, 2159 int *valp,
2046 int write, void *data) 2160 int write, void *data)
2047{ 2161{
@@ -2050,33 +2164,31 @@ static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
2050 } else { 2164 } else {
2051 int val = *valp; 2165 int val = *valp;
2052 if (val < 0) { 2166 if (val < 0) {
2053 *negp = -1; 2167 *negp = true;
2054 *lvalp = (unsigned long)-val; 2168 *lvalp = (unsigned long)-val;
2055 } else { 2169 } else {
2056 *negp = 0; 2170 *negp = false;
2057 *lvalp = (unsigned long)val; 2171 *lvalp = (unsigned long)val;
2058 } 2172 }
2059 } 2173 }
2060 return 0; 2174 return 0;
2061} 2175}
2062 2176
2177static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
2178
2063static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, 2179static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
2064 int write, void __user *buffer, 2180 int write, void __user *buffer,
2065 size_t *lenp, loff_t *ppos, 2181 size_t *lenp, loff_t *ppos,
2066 int (*conv)(int *negp, unsigned long *lvalp, int *valp, 2182 int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
2067 int write, void *data), 2183 int write, void *data),
2068 void *data) 2184 void *data)
2069{ 2185{
2070#define TMPBUFLEN 21 2186 int *i, vleft, first = 1, err = 0;
2071 int *i, vleft, first = 1, neg; 2187 unsigned long page = 0;
2072 unsigned long lval; 2188 size_t left;
2073 size_t left, len; 2189 char *kbuf;
2074
2075 char buf[TMPBUFLEN], *p;
2076 char __user *s = buffer;
2077 2190
2078 if (!tbl_data || !table->maxlen || !*lenp || 2191 if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
2079 (*ppos && !write)) {
2080 *lenp = 0; 2192 *lenp = 0;
2081 return 0; 2193 return 0;
2082 } 2194 }
@@ -2088,89 +2200,69 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
2088 if (!conv) 2200 if (!conv)
2089 conv = do_proc_dointvec_conv; 2201 conv = do_proc_dointvec_conv;
2090 2202
2203 if (write) {
2204 if (left > PAGE_SIZE - 1)
2205 left = PAGE_SIZE - 1;
2206 page = __get_free_page(GFP_TEMPORARY);
2207 kbuf = (char *) page;
2208 if (!kbuf)
2209 return -ENOMEM;
2210 if (copy_from_user(kbuf, buffer, left)) {
2211 err = -EFAULT;
2212 goto free;
2213 }
2214 kbuf[left] = 0;
2215 }
2216
2091 for (; left && vleft--; i++, first=0) { 2217 for (; left && vleft--; i++, first=0) {
2092 if (write) { 2218 unsigned long lval;
2093 while (left) { 2219 bool neg;
2094 char c;
2095 if (get_user(c, s))
2096 return -EFAULT;
2097 if (!isspace(c))
2098 break;
2099 left--;