]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - kernel/sysctl_binary.c
sysctl: Separate the binary sysctl logic into it's own file.
[thirdparty/kernel/stable.git] / kernel / sysctl_binary.c
CommitLineData
afa588b2
EB
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}