History

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.

Eric W. Biederman committed 17 years ago

Commit afa588b1 parent b4191483 files · +186 −166Browse files

Showing the changes to kernel/sysctl_binary.c (1 of 3 files). Show all

Unified · Split

kernel/sysctl_binary.c+185−0
@@ -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}