diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2007-10-18 06:05:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-18 17:37:22 -0400 |
commit | 49a0c45833c9aa9852ba02c9df0f18029509d0a9 (patch) | |
tree | 0884aec3c522e495aa8a412b44fc6c8c24522639 /kernel/sysctl.c | |
parent | d8217f076b73441dd3869c0c880df000655084cc (diff) |
sysctl: Factor out sysctl_data.
There as been no easy way to wrap the default sysctl strategy routine except
for returning 0. Which is not always what we want. The few instances I have
seen that want different behaviour have written their own version of
sysctl_data. While not too hard it is unnecessary code and has the potential
for extra bugs.
So to make these situations easier and make that part of sysctl more symetric
I have factord sysctl_data out of do_sysctl_strategy and exported as a
function everyone can use.
Further having sysctl_data be an explicit function makes checking for badly
formed sysctl tables much easier.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 66 |
1 files changed, 46 insertions, 20 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 73c84b6e7a35..88c8ea8f5e8c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -1443,7 +1443,6 @@ int do_sysctl_strategy (struct ctl_table *table, | |||
1443 | void __user *newval, size_t newlen) | 1443 | void __user *newval, size_t newlen) |
1444 | { | 1444 | { |
1445 | int op = 0, rc; | 1445 | int op = 0, rc; |
1446 | size_t len; | ||
1447 | 1446 | ||
1448 | if (oldval) | 1447 | if (oldval) |
1449 | op |= 004; | 1448 | op |= 004; |
@@ -1464,25 +1463,10 @@ int do_sysctl_strategy (struct ctl_table *table, | |||
1464 | /* If there is no strategy routine, or if the strategy returns | 1463 | /* If there is no strategy routine, or if the strategy returns |
1465 | * zero, proceed with automatic r/w */ | 1464 | * zero, proceed with automatic r/w */ |
1466 | if (table->data && table->maxlen) { | 1465 | if (table->data && table->maxlen) { |
1467 | if (oldval && oldlenp) { | 1466 | rc = sysctl_data(table, name, nlen, oldval, oldlenp, |
1468 | if (get_user(len, oldlenp)) | 1467 | newval, newlen); |
1469 | return -EFAULT; | 1468 | if (rc < 0) |
1470 | if (len) { | 1469 | return rc; |
1471 | if (len > table->maxlen) | ||
1472 | len = table->maxlen; | ||
1473 | if(copy_to_user(oldval, table->data, len)) | ||
1474 | return -EFAULT; | ||
1475 | if(put_user(len, oldlenp)) | ||
1476 | return -EFAULT; | ||
1477 | } | ||
1478 | } | ||
1479 | if (newval && newlen) { | ||
1480 | len = newlen; | ||
1481 | if (len > table->maxlen) | ||
1482 | len = table->maxlen; | ||
1483 | if(copy_from_user(table->data, newval, len)) | ||
1484 | return -EFAULT; | ||
1485 | } | ||
1486 | } | 1470 | } |
1487 | return 0; | 1471 | return 0; |
1488 | } | 1472 | } |
@@ -2381,6 +2365,40 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write, | |||
2381 | * General sysctl support routines | 2365 | * General sysctl support routines |
2382 | */ | 2366 | */ |
2383 | 2367 | ||
2368 | /* The generic sysctl data routine (used if no strategy routine supplied) */ | ||
2369 | int sysctl_data(struct ctl_table *table, int __user *name, int nlen, | ||
2370 | void __user *oldval, size_t __user *oldlenp, | ||
2371 | void __user *newval, size_t newlen) | ||
2372 | { | ||
2373 | size_t len; | ||
2374 | |||
2375 | /* Get out of I don't have a variable */ | ||
2376 | if (!table->data || !table->maxlen) | ||
2377 | return -ENOTDIR; | ||
2378 | |||
2379 | if (oldval && oldlenp) { | ||
2380 | if (get_user(len, oldlenp)) | ||
2381 | return -EFAULT; | ||
2382 | if (len) { | ||
2383 | if (len > table->maxlen) | ||
2384 | len = table->maxlen; | ||
2385 | if (copy_to_user(oldval, table->data, len)) | ||
2386 | return -EFAULT; | ||
2387 | if (put_user(len, oldlenp)) | ||
2388 | return -EFAULT; | ||
2389 | } | ||
2390 | } | ||
2391 | |||
2392 | if (newval && newlen) { | ||
2393 | if (newlen > table->maxlen) | ||
2394 | newlen = table->maxlen; | ||
2395 | |||
2396 | if (copy_from_user(table->data, newval, newlen)) | ||
2397 | return -EFAULT; | ||
2398 | } | ||
2399 | return 1; | ||
2400 | } | ||
2401 | |||
2384 | /* The generic string strategy routine: */ | 2402 | /* The generic string strategy routine: */ |
2385 | int sysctl_string(struct ctl_table *table, int __user *name, int nlen, | 2403 | int sysctl_string(struct ctl_table *table, int __user *name, int nlen, |
2386 | void __user *oldval, size_t __user *oldlenp, | 2404 | void __user *oldval, size_t __user *oldlenp, |
@@ -2569,6 +2587,13 @@ out: | |||
2569 | return -ENOSYS; | 2587 | return -ENOSYS; |
2570 | } | 2588 | } |
2571 | 2589 | ||
2590 | int sysctl_data(struct ctl_table *table, int __user *name, int nlen, | ||
2591 | void __user *oldval, size_t __user *oldlenp, | ||
2592 | void __user *newval, size_t newlen) | ||
2593 | { | ||
2594 | return -ENOSYS; | ||
2595 | } | ||
2596 | |||
2572 | int sysctl_string(struct ctl_table *table, int __user *name, int nlen, | 2597 | int sysctl_string(struct ctl_table *table, int __user *name, int nlen, |
2573 | void __user *oldval, size_t __user *oldlenp, | 2598 | void __user *oldval, size_t __user *oldlenp, |
2574 | void __user *newval, size_t newlen) | 2599 | void __user *newval, size_t newlen) |
@@ -2616,4 +2641,5 @@ EXPORT_SYMBOL(sysctl_intvec); | |||
2616 | EXPORT_SYMBOL(sysctl_jiffies); | 2641 | EXPORT_SYMBOL(sysctl_jiffies); |
2617 | EXPORT_SYMBOL(sysctl_ms_jiffies); | 2642 | EXPORT_SYMBOL(sysctl_ms_jiffies); |
2618 | EXPORT_SYMBOL(sysctl_string); | 2643 | EXPORT_SYMBOL(sysctl_string); |
2644 | EXPORT_SYMBOL(sysctl_data); | ||
2619 | EXPORT_SYMBOL(unregister_sysctl_table); | 2645 | EXPORT_SYMBOL(unregister_sysctl_table); |