aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-10-18 06:05:23 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:22 -0400
commit49a0c45833c9aa9852ba02c9df0f18029509d0a9 (patch)
tree0884aec3c522e495aa8a412b44fc6c8c24522639
parentd8217f076b73441dd3869c0c880df000655084cc (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>
-rw-r--r--include/linux/sysctl.h1
-rw-r--r--kernel/sysctl.c66
2 files changed, 47 insertions, 20 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index f73be4cd662e..5ca510b3cbe2 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -972,6 +972,7 @@ extern int do_sysctl_strategy (struct ctl_table *table,
972 void __user *oldval, size_t __user *oldlenp, 972 void __user *oldval, size_t __user *oldlenp,
973 void __user *newval, size_t newlen); 973 void __user *newval, size_t newlen);
974 974
975extern ctl_handler sysctl_data;
975extern ctl_handler sysctl_string; 976extern ctl_handler sysctl_string;
976extern ctl_handler sysctl_intvec; 977extern ctl_handler sysctl_intvec;
977extern ctl_handler sysctl_jiffies; 978extern ctl_handler sysctl_jiffies;
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) */
2369int 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: */
2385int sysctl_string(struct ctl_table *table, int __user *name, int nlen, 2403int 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
2590int 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
2572int sysctl_string(struct ctl_table *table, int __user *name, int nlen, 2597int 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);
2616EXPORT_SYMBOL(sysctl_jiffies); 2641EXPORT_SYMBOL(sysctl_jiffies);
2617EXPORT_SYMBOL(sysctl_ms_jiffies); 2642EXPORT_SYMBOL(sysctl_ms_jiffies);
2618EXPORT_SYMBOL(sysctl_string); 2643EXPORT_SYMBOL(sysctl_string);
2644EXPORT_SYMBOL(sysctl_data);
2619EXPORT_SYMBOL(unregister_sysctl_table); 2645EXPORT_SYMBOL(unregister_sysctl_table);