aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2009-04-03 02:44:59 -0400
committerEric W. Biederman <ebiederm@xmission.com>2009-11-06 06:20:07 -0500
commitafa588b2651a03da4bc601a17a244b1cd97264f2 (patch)
treecb7a03753f282b4e459305fec307caf0837e756b /kernel
parentb419148e567728f6af0c3b01965c1cc141e3e13a (diff)
sysctl: Separate the binary sysctl logic into it's own file.
In preparation for more invasive cleanups separate the core binary sysctl logic into it's own file. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/sysctl.c165
-rw-r--r--kernel/sysctl_binary.c185
3 files changed, 186 insertions, 166 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index b8d4cd8ac0b9..986a5c197346 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -4,7 +4,7 @@
4 4
5obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ 5obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
6 cpu.o exit.o itimer.o time.o softirq.o resource.o \ 6 cpu.o exit.o itimer.o time.o softirq.o resource.o \
7 sysctl.o capability.o ptrace.o timer.o user.o \ 7 sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
8 signal.o sys.o kmod.o workqueue.o pid.o \ 8 signal.o sys.o kmod.o workqueue.o pid.o \
9 rcupdate.o extable.o params.o posix-timers.o \ 9 rcupdate.o extable.o params.o posix-timers.o \
10 kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ 10 kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 0d949c517412..6a642d7ffa85 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -27,7 +27,6 @@
27#include <linux/security.h> 27#include <linux/security.h>
28#include <linux/ctype.h> 28#include <linux/ctype.h>
29#include <linux/kmemcheck.h> 29#include <linux/kmemcheck.h>
30#include <linux/smp_lock.h>
31#include <linux/fs.h> 30#include <linux/fs.h>
32#include <linux/init.h> 31#include <linux/init.h>
33#include <linux/kernel.h> 32#include <linux/kernel.h>
@@ -60,7 +59,6 @@
60#include <asm/io.h> 59#include <asm/io.h>
61#endif 60#endif
62 61
63static int deprecated_sysctl_warning(struct __sysctl_args *args);
64 62
65#if defined(CONFIG_SYSCTL) 63#if defined(CONFIG_SYSCTL)
66 64
@@ -1766,122 +1764,6 @@ void register_sysctl_root(struct ctl_table_root *root)
1766 spin_unlock(&sysctl_lock); 1764 spin_unlock(&sysctl_lock);
1767} 1765}
1768 1766
1769#ifdef CONFIG_SYSCTL_SYSCALL
1770/* Perform the actual read/write of a sysctl table entry. */
1771static int do_sysctl_strategy(struct ctl_table_root *root,
1772 struct ctl_table *table,
1773 void __user *oldval, size_t __user *oldlenp,
1774 void __user *newval, size_t newlen)
1775{
1776 int op = 0, rc;
1777
1778 if (oldval)
1779 op |= MAY_READ;
1780 if (newval)
1781 op |= MAY_WRITE;
1782 if (sysctl_perm(root, table, op))
1783 return -EPERM;
1784
1785 if (table->strategy) {
1786 rc = table->strategy(table, oldval, oldlenp, newval, newlen);
1787 if (rc < 0)
1788 return rc;
1789 if (rc > 0)
1790 return 0;
1791 }
1792
1793 /* If there is no strategy routine, or if the strategy returns
1794 * zero, proceed with automatic r/w */
1795 if (table->data && table->maxlen) {
1796 rc = sysctl_data(table, oldval, oldlenp, newval, newlen);
1797 if (rc < 0)
1798 return rc;
1799 }
1800 return 0;
1801}
1802
1803static int parse_table(int __user *name, int nlen,
1804 void __user *oldval, size_t __user *oldlenp,
1805 void __user *newval, size_t newlen,
1806 struct ctl_table_root *root,
1807 struct ctl_table *table)
1808{
1809 int n;
1810repeat:
1811 if (!nlen)
1812 return -ENOTDIR;
1813 if (get_user(n, name))
1814 return -EFAULT;
1815 for ( ; table->ctl_name || table->procname; table++) {
1816 if (!table->ctl_name)
1817 continue;
1818 if (n == table->ctl_name) {
1819 int error;
1820 if (table->child) {
1821 if (sysctl_perm(root, table, MAY_EXEC))
1822 return -EPERM;
1823 name++;
1824 nlen--;
1825 table = table->child;
1826 goto repeat;
1827 }
1828 error = do_sysctl_strategy(root, table,
1829 oldval, oldlenp,
1830 newval, newlen);
1831 return error;
1832 }
1833 }
1834 return -ENOTDIR;
1835}
1836
1837int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
1838 void __user *newval, size_t newlen)
1839{
1840 struct ctl_table_header *head;
1841 int error = -ENOTDIR;
1842
1843 if (nlen <= 0 || nlen >= CTL_MAXNAME)
1844 return -ENOTDIR;
1845 if (oldval) {
1846 int old_len;
1847 if (!oldlenp || get_user(old_len, oldlenp))
1848 return -EFAULT;
1849 }
1850
1851 for (head = sysctl_head_next(NULL); head;
1852 head = sysctl_head_next(head)) {
1853 error = parse_table(name, nlen, oldval, oldlenp,
1854 newval, newlen,
1855 head->root, head->ctl_table);
1856 if (error != -ENOTDIR) {
1857 sysctl_head_finish(head);
1858 break;
1859 }
1860 }
1861 return error;
1862}
1863
1864SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
1865{
1866 struct __sysctl_args tmp;
1867 int error;
1868
1869 if (copy_from_user(&tmp, args, sizeof(tmp)))
1870 return -EFAULT;
1871
1872 error = deprecated_sysctl_warning(&tmp);
1873 if (error)
1874 goto out;
1875
1876 lock_kernel();
1877 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
1878 tmp.newval, tmp.newlen);
1879 unlock_kernel();
1880out:
1881 return error;
1882}
1883#endif /* CONFIG_SYSCTL_SYSCALL */
1884
1885/* 1767/*
1886 * sysctl_perm does NOT grant the superuser all rights automatically, because 1768 * sysctl_perm does NOT grant the superuser all rights automatically, because
1887 * some sysctl variables are readonly even to root. 1769 * some sysctl variables are readonly even to root.
@@ -3148,23 +3030,6 @@ int sysctl_ms_jiffies(struct ctl_table *table,
3148#else /* CONFIG_SYSCTL_SYSCALL */ 3030#else /* CONFIG_SYSCTL_SYSCALL */
3149 3031
3150 3032
3151SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
3152{
3153 struct __sysctl_args tmp;
3154 int error;
3155
3156 if (copy_from_user(&tmp, args, sizeof(tmp)))
3157 return -EFAULT;
3158
3159 error = deprecated_sysctl_warning(&tmp);
3160
3161 /* If no error reading the parameters then just -ENOSYS ... */
3162 if (!error)
3163 error = -ENOSYS;
3164
3165 return error;
3166}
3167
3168int sysctl_data(struct ctl_table *table, 3033int sysctl_data(struct ctl_table *table,
3169 void __user *oldval, size_t __user *oldlenp, 3034 void __user *oldval, size_t __user *oldlenp,
3170 void __user *newval, size_t newlen) 3035 void __user *newval, size_t newlen)
@@ -3202,36 +3067,6 @@ int sysctl_ms_jiffies(struct ctl_table *table,
3202 3067
3203#endif /* CONFIG_SYSCTL_SYSCALL */ 3068#endif /* CONFIG_SYSCTL_SYSCALL */
3204 3069
3205static int deprecated_sysctl_warning(struct __sysctl_args *args)
3206{
3207 static int msg_count;
3208 int name[CTL_MAXNAME];
3209 int i;
3210
3211 /* Check args->nlen. */
3212 if (args->nlen < 0 || args->nlen > CTL_MAXNAME)
3213 return -ENOTDIR;
3214
3215 /* Read in the sysctl name for better debug message logging */
3216 for (i = 0; i < args->nlen; i++)
3217 if (get_user(name[i], args->name + i))
3218 return -EFAULT;
3219
3220 /* Ignore accesses to kernel.version */
3221 if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
3222 return 0;
3223
3224 if (msg_count < 5) {
3225 msg_count++;
3226 printk(KERN_INFO
3227 "warning: process `%s' used the deprecated sysctl "
3228 "system call with ", current->comm);
3229 for (i = 0; i < args->nlen; i++)
3230 printk("%d.", name[i]);
3231 printk("\n");
3232 }
3233 return 0;
3234}
3235 3070
3236/* 3071/*
3237 * No sense putting this after each symbol definition, twice, 3072 * No sense putting this after each symbol definition, twice,
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
new file mode 100644
index 000000000000..eceeed20ca88
--- /dev/null
+++ b/kernel/sysctl_binary.c
@@ -0,0 +1,185 @@
1#include <linux/stat.h>
2#include <linux/sysctl.h>
3#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
4#include <linux/sunrpc/debug.h>
5#include <linux/string.h>
6#include <net/ip_vs.h>
7#include <linux/syscalls.h>
8#include <linux/namei.h>
9#include <linux/mount.h>
10#include <linux/fs.h>
11#include <linux/nsproxy.h>
12#include <linux/pid_namespace.h>
13#include <linux/file.h>
14#include <linux/ctype.h>
15#include <linux/smp_lock.h>
16
17static int deprecated_sysctl_warning(struct __sysctl_args *args);
18
19#ifdef CONFIG_SYSCTL_SYSCALL
20
21/* Perform the actual read/write of a sysctl table entry. */
22static int do_sysctl_strategy(struct ctl_table_root *root,
23 struct ctl_table *table,
24 void __user *oldval, size_t __user *oldlenp,
25 void __user *newval, size_t newlen)
26{
27 int op = 0, rc;
28
29 if (oldval)
30 op |= MAY_READ;
31 if (newval)
32 op |= MAY_WRITE;
33 if (sysctl_perm(root, table, op))
34 return -EPERM;
35
36 if (table->strategy) {
37 rc = table->strategy(table, oldval, oldlenp, newval, newlen);
38 if (rc < 0)
39 return rc;
40 if (rc > 0)
41 return 0;
42 }
43
44 /* If there is no strategy routine, or if the strategy returns
45 * zero, proceed with automatic r/w */
46 if (table->data && table->maxlen) {
47 rc = sysctl_data(table, oldval, oldlenp, newval, newlen);
48 if (rc < 0)
49 return rc;
50 }
51 return 0;
52}
53
54static int parse_table(int __user *name, int nlen,
55 void __user *oldval, size_t __user *oldlenp,
56 void __user *newval, size_t newlen,
57 struct ctl_table_root *root,
58 struct ctl_table *table)
59{
60 int n;
61repeat:
62 if (!nlen)
63 return -ENOTDIR;
64 if (get_user(n, name))
65 return -EFAULT;
66 for ( ; table->ctl_name || table->procname; table++) {
67 if (!table->ctl_name)
68 continue;
69 if (n == table->ctl_name) {
70 int error;
71 if (table->child) {
72 if (sysctl_perm(root, table, MAY_EXEC))
73 return -EPERM;
74 name++;
75 nlen--;
76 table = table->child;
77 goto repeat;
78 }
79 error = do_sysctl_strategy(root, table,
80 oldval, oldlenp,
81 newval, newlen);
82 return error;
83 }
84 }
85 return -ENOTDIR;
86}
87
88int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
89 void __user *newval, size_t newlen)
90{
91 struct ctl_table_header *head;
92 int error = -ENOTDIR;
93
94 if (nlen <= 0 || nlen >= CTL_MAXNAME)
95 return -ENOTDIR;
96 if (oldval) {
97 int old_len;
98 if (!oldlenp || get_user(old_len, oldlenp))
99 return -EFAULT;
100 }
101
102 for (head = sysctl_head_next(NULL); head;
103 head = sysctl_head_next(head)) {
104 error = parse_table(name, nlen, oldval, oldlenp,
105 newval, newlen,
106 head->root, head->ctl_table);
107 if (error != -ENOTDIR) {
108 sysctl_head_finish(head);
109 break;
110 }
111 }
112 return error;
113}
114
115SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
116{
117 struct __sysctl_args tmp;
118 int error;
119
120 if (copy_from_user(&tmp, args, sizeof(tmp)))
121 return -EFAULT;
122
123 error = deprecated_sysctl_warning(&tmp);
124 if (error)
125 goto out;
126
127 lock_kernel();
128 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
129 tmp.newval, tmp.newlen);
130 unlock_kernel();
131out:
132 return error;
133}
134
135#else /* CONFIG_SYSCTL_SYSCALL */
136
137SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
138{
139 struct __sysctl_args tmp;
140 int error;
141
142 if (copy_from_user(&tmp, args, sizeof(tmp)))
143 return -EFAULT;
144
145 error = deprecated_sysctl_warning(&tmp);
146
147 /* If no error reading the parameters then just -ENOSYS ... */
148 if (!error)
149 error = -ENOSYS;
150
151 return error;
152}
153
154#endif /* CONFIG_SYSCTL_SYSCALL */
155
156static int deprecated_sysctl_warning(struct __sysctl_args *args)
157{
158 static int msg_count;
159 int name[CTL_MAXNAME];
160 int i;
161
162 /* Check args->nlen. */
163 if (args->nlen < 0 || args->nlen > CTL_MAXNAME)
164 return -ENOTDIR;
165
166 /* Read in the sysctl name for better debug message logging */
167 for (i = 0; i < args->nlen; i++)
168 if (get_user(name[i], args->name + i))
169 return -EFAULT;
170
171 /* Ignore accesses to kernel.version */
172 if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
173 return 0;
174
175 if (msg_count < 5) {
176 msg_count++;
177 printk(KERN_INFO
178 "warning: process `%s' used the deprecated sysctl "
179 "system call with ", current->comm);
180 for (i = 0; i < args->nlen; i++)
181 printk("%d.", name[i]);
182 printk("\n");
183 }
184 return 0;
185}