diff options
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 153 |
1 files changed, 146 insertions, 7 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 6f3bb1f099fa..d12078fc215f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -2175,19 +2175,18 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, | |||
2175 | return 0; | 2175 | return 0; |
2176 | } | 2176 | } |
2177 | 2177 | ||
2178 | static int do_proc_douintvec_conv(bool *negp, unsigned long *lvalp, | 2178 | static int do_proc_douintvec_conv(unsigned long *lvalp, |
2179 | int *valp, | 2179 | unsigned int *valp, |
2180 | int write, void *data) | 2180 | int write, void *data) |
2181 | { | 2181 | { |
2182 | if (write) { | 2182 | if (write) { |
2183 | if (*negp) | 2183 | if (*lvalp > UINT_MAX) |
2184 | return -EINVAL; | 2184 | return -EINVAL; |
2185 | if (*lvalp > UINT_MAX) | 2185 | if (*lvalp > UINT_MAX) |
2186 | return -EINVAL; | 2186 | return -EINVAL; |
2187 | *valp = *lvalp; | 2187 | *valp = *lvalp; |
2188 | } else { | 2188 | } else { |
2189 | unsigned int val = *valp; | 2189 | unsigned int val = *valp; |
2190 | *negp = false; | ||
2191 | *lvalp = (unsigned long)val; | 2190 | *lvalp = (unsigned long)val; |
2192 | } | 2191 | } |
2193 | return 0; | 2192 | return 0; |
@@ -2287,6 +2286,146 @@ static int do_proc_dointvec(struct ctl_table *table, int write, | |||
2287 | buffer, lenp, ppos, conv, data); | 2286 | buffer, lenp, ppos, conv, data); |
2288 | } | 2287 | } |
2289 | 2288 | ||
2289 | static int do_proc_douintvec_w(unsigned int *tbl_data, | ||
2290 | struct ctl_table *table, | ||
2291 | void __user *buffer, | ||
2292 | size_t *lenp, loff_t *ppos, | ||
2293 | int (*conv)(unsigned long *lvalp, | ||
2294 | unsigned int *valp, | ||
2295 | int write, void *data), | ||
2296 | void *data) | ||
2297 | { | ||
2298 | unsigned long lval; | ||
2299 | int err = 0; | ||
2300 | size_t left; | ||
2301 | bool neg; | ||
2302 | char *kbuf = NULL, *p; | ||
2303 | |||
2304 | left = *lenp; | ||
2305 | |||
2306 | if (proc_first_pos_non_zero_ignore(ppos, table)) | ||
2307 | goto bail_early; | ||
2308 | |||
2309 | if (left > PAGE_SIZE - 1) | ||
2310 | left = PAGE_SIZE - 1; | ||
2311 | |||
2312 | p = kbuf = memdup_user_nul(buffer, left); | ||
2313 | if (IS_ERR(kbuf)) | ||
2314 | return -EINVAL; | ||
2315 | |||
2316 | left -= proc_skip_spaces(&p); | ||
2317 | if (!left) { | ||
2318 | err = -EINVAL; | ||
2319 | goto out_free; | ||
2320 | } | ||
2321 | |||
2322 | err = proc_get_long(&p, &left, &lval, &neg, | ||
2323 | proc_wspace_sep, | ||
2324 | sizeof(proc_wspace_sep), NULL); | ||
2325 | if (err || neg) { | ||
2326 | err = -EINVAL; | ||
2327 | goto out_free; | ||
2328 | } | ||
2329 | |||
2330 | if (conv(&lval, tbl_data, 1, data)) { | ||
2331 | err = -EINVAL; | ||
2332 | goto out_free; | ||
2333 | } | ||
2334 | |||
2335 | if (!err && left) | ||
2336 | left -= proc_skip_spaces(&p); | ||
2337 | |||
2338 | out_free: | ||
2339 | kfree(kbuf); | ||
2340 | if (err) | ||
2341 | return -EINVAL; | ||
2342 | |||
2343 | return 0; | ||
2344 | |||
2345 | /* This is in keeping with old __do_proc_dointvec() */ | ||
2346 | bail_early: | ||
2347 | *ppos += *lenp; | ||
2348 | return err; | ||
2349 | } | ||
2350 | |||
2351 | static int do_proc_douintvec_r(unsigned int *tbl_data, void __user *buffer, | ||
2352 | size_t *lenp, loff_t *ppos, | ||
2353 | int (*conv)(unsigned long *lvalp, | ||
2354 | unsigned int *valp, | ||
2355 | int write, void *data), | ||
2356 | void *data) | ||
2357 | { | ||
2358 | unsigned long lval; | ||
2359 | int err = 0; | ||
2360 | size_t left; | ||
2361 | |||
2362 | left = *lenp; | ||
2363 | |||
2364 | if (conv(&lval, tbl_data, 0, data)) { | ||
2365 | err = -EINVAL; | ||
2366 | goto out; | ||
2367 | } | ||
2368 | |||
2369 | err = proc_put_long(&buffer, &left, lval, false); | ||
2370 | if (err || !left) | ||
2371 | goto out; | ||
2372 | |||
2373 | err = proc_put_char(&buffer, &left, '\n'); | ||
2374 | |||
2375 | out: | ||
2376 | *lenp -= left; | ||
2377 | *ppos += *lenp; | ||
2378 | |||
2379 | return err; | ||
2380 | } | ||
2381 | |||
2382 | static int __do_proc_douintvec(void *tbl_data, struct ctl_table *table, | ||
2383 | int write, void __user *buffer, | ||
2384 | size_t *lenp, loff_t *ppos, | ||
2385 | int (*conv)(unsigned long *lvalp, | ||
2386 | unsigned int *valp, | ||
2387 | int write, void *data), | ||
2388 | void *data) | ||
2389 | { | ||
2390 | unsigned int *i, vleft; | ||
2391 | |||
2392 | if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { | ||
2393 | *lenp = 0; | ||
2394 | return 0; | ||
2395 | } | ||
2396 | |||
2397 | i = (unsigned int *) tbl_data; | ||
2398 | vleft = table->maxlen / sizeof(*i); | ||
2399 | |||
2400 | /* | ||
2401 | * Arrays are not supported, keep this simple. *Do not* add | ||
2402 | * support for them. | ||
2403 | */ | ||
2404 | if (vleft != 1) { | ||
2405 | *lenp = 0; | ||
2406 | return -EINVAL; | ||
2407 | } | ||
2408 | |||
2409 | if (!conv) | ||
2410 | conv = do_proc_douintvec_conv; | ||
2411 | |||
2412 | if (write) | ||
2413 | return do_proc_douintvec_w(i, table, buffer, lenp, ppos, | ||
2414 | conv, data); | ||
2415 | return do_proc_douintvec_r(i, buffer, lenp, ppos, conv, data); | ||
2416 | } | ||
2417 | |||
2418 | static int do_proc_douintvec(struct ctl_table *table, int write, | ||
2419 | void __user *buffer, size_t *lenp, loff_t *ppos, | ||
2420 | int (*conv)(unsigned long *lvalp, | ||
2421 | unsigned int *valp, | ||
2422 | int write, void *data), | ||
2423 | void *data) | ||
2424 | { | ||
2425 | return __do_proc_douintvec(table->data, table, write, | ||
2426 | buffer, lenp, ppos, conv, data); | ||
2427 | } | ||
2428 | |||
2290 | /** | 2429 | /** |
2291 | * proc_dointvec - read a vector of integers | 2430 | * proc_dointvec - read a vector of integers |
2292 | * @table: the sysctl table | 2431 | * @table: the sysctl table |
@@ -2322,8 +2461,8 @@ int proc_dointvec(struct ctl_table *table, int write, | |||
2322 | int proc_douintvec(struct ctl_table *table, int write, | 2461 | int proc_douintvec(struct ctl_table *table, int write, |
2323 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2462 | void __user *buffer, size_t *lenp, loff_t *ppos) |
2324 | { | 2463 | { |
2325 | return do_proc_dointvec(table, write, buffer, lenp, ppos, | 2464 | return do_proc_douintvec(table, write, buffer, lenp, ppos, |
2326 | do_proc_douintvec_conv, NULL); | 2465 | do_proc_douintvec_conv, NULL); |
2327 | } | 2466 | } |
2328 | 2467 | ||
2329 | /* | 2468 | /* |