]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - kernel/sysctl_binary.c
sysctl: Make do_sysctl static
[mirror_ubuntu-bionic-kernel.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
afa588b2
EB
17#ifdef CONFIG_SYSCTL_SYSCALL
18
19/* Perform the actual read/write of a sysctl table entry. */
20static int do_sysctl_strategy(struct ctl_table_root *root,
21 struct ctl_table *table,
22 void __user *oldval, size_t __user *oldlenp,
23 void __user *newval, size_t newlen)
24{
25 int op = 0, rc;
26
27 if (oldval)
28 op |= MAY_READ;
29 if (newval)
30 op |= MAY_WRITE;
31 if (sysctl_perm(root, table, op))
32 return -EPERM;
33
34 if (table->strategy) {
35 rc = table->strategy(table, oldval, oldlenp, newval, newlen);
36 if (rc < 0)
37 return rc;
38 if (rc > 0)
39 return 0;
40 }
41
42 /* If there is no strategy routine, or if the strategy returns
43 * zero, proceed with automatic r/w */
44 if (table->data && table->maxlen) {
45 rc = sysctl_data(table, oldval, oldlenp, newval, newlen);
46 if (rc < 0)
47 return rc;
48 }
49 return 0;
50}
51
2830b683 52static int parse_table(const int *name, int nlen,
afa588b2
EB
53 void __user *oldval, size_t __user *oldlenp,
54 void __user *newval, size_t newlen,
55 struct ctl_table_root *root,
56 struct ctl_table *table)
57{
58 int n;
59repeat:
60 if (!nlen)
61 return -ENOTDIR;
2830b683 62 n = *name;
afa588b2
EB
63 for ( ; table->ctl_name || table->procname; table++) {
64 if (!table->ctl_name)
65 continue;
66 if (n == table->ctl_name) {
67 int error;
68 if (table->child) {
69 if (sysctl_perm(root, table, MAY_EXEC))
70 return -EPERM;
71 name++;
72 nlen--;
73 table = table->child;
74 goto repeat;
75 }
76 error = do_sysctl_strategy(root, table,
77 oldval, oldlenp,
78 newval, newlen);
79 return error;
80 }
81 }
82 return -ENOTDIR;
83}
84
2830b683
EB
85static ssize_t binary_sysctl(const int *name, int nlen,
86 void __user *oldval, size_t __user *oldlenp,
87 void __user *newval, size_t newlen)
88
afa588b2
EB
89{
90 struct ctl_table_header *head;
2830b683 91 ssize_t error = -ENOTDIR;
afa588b2
EB
92
93 for (head = sysctl_head_next(NULL); head;
94 head = sysctl_head_next(head)) {
95 error = parse_table(name, nlen, oldval, oldlenp,
96 newval, newlen,
97 head->root, head->ctl_table);
98 if (error != -ENOTDIR) {
99 sysctl_head_finish(head);
100 break;
101 }
102 }
103 return error;
104}
105
afa588b2
EB
106#else /* CONFIG_SYSCTL_SYSCALL */
107
2830b683
EB
108static ssize_t binary_sysctl(const int *ctl_name, int nlen,
109 void __user *oldval, size_t __user *oldlenp,
110 void __user *newval, size_t newlen)
afa588b2 111{
2830b683 112 return -ENOSYS;
afa588b2
EB
113}
114
115#endif /* CONFIG_SYSCTL_SYSCALL */
116
2830b683 117static void deprecated_sysctl_warning(const int *name, int nlen)
afa588b2
EB
118{
119 static int msg_count;
afa588b2
EB
120 int i;
121
afa588b2 122 /* Ignore accesses to kernel.version */
2830b683
EB
123 if ((nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
124 return;
afa588b2
EB
125
126 if (msg_count < 5) {
127 msg_count++;
128 printk(KERN_INFO
129 "warning: process `%s' used the deprecated sysctl "
130 "system call with ", current->comm);
2830b683 131 for (i = 0; i < nlen; i++)
afa588b2
EB
132 printk("%d.", name[i]);
133 printk("\n");
134 }
2830b683
EB
135 return;
136}
137
642c6d94 138static int do_sysctl(int __user *args_name, int nlen,
2830b683
EB
139 void __user *oldval, size_t __user *oldlenp,
140 void __user *newval, size_t newlen)
141{
142 int name[CTL_MAXNAME];
143 size_t oldlen = 0;
144 int i;
145
146 if (nlen <= 0 || nlen >= CTL_MAXNAME)
147 return -ENOTDIR;
148 if (oldval && !oldlenp)
149 return -EFAULT;
150 if (oldlenp && get_user(oldlen, oldlenp))
151 return -EFAULT;
152
153 /* Read in the sysctl name for simplicity */
154 for (i = 0; i < nlen; i++)
155 if (get_user(name[i], args_name + i))
156 return -EFAULT;
157
158 deprecated_sysctl_warning(name, nlen);
159
160 return binary_sysctl(name, nlen, oldval, oldlenp, newval, newlen);
161}
162
163
164SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
165{
166 struct __sysctl_args tmp;
167 int error;
168
169 if (copy_from_user(&tmp, args, sizeof(tmp)))
170 return -EFAULT;
171
172 lock_kernel();
173 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
174 tmp.newval, tmp.newlen);
175 unlock_kernel();
176
177 return error;
afa588b2 178}
da3f6f9b
EB
179
180#ifdef CONFIG_COMPAT
181#include <asm/compat.h>
182
183struct compat_sysctl_args {
184 compat_uptr_t name;
185 int nlen;
186 compat_uptr_t oldval;
187 compat_uptr_t oldlenp;
188 compat_uptr_t newval;
189 compat_size_t newlen;
190 compat_ulong_t __unused[4];
191};
192
193asmlinkage long compat_sys_sysctl(struct compat_sysctl_args __user *args)
194{
195 struct compat_sysctl_args tmp;
196 compat_size_t __user *compat_oldlenp;
197 size_t __user *oldlenp = NULL;
198 size_t oldlen = 0;
199 ssize_t result;
200
201 if (copy_from_user(&tmp, args, sizeof(tmp)))
202 return -EFAULT;
203
204 compat_oldlenp = compat_ptr(tmp.oldlenp);
205 if (compat_oldlenp) {
206 oldlenp = compat_alloc_user_space(sizeof(*compat_oldlenp));
207
208 if (get_user(oldlen, compat_oldlenp) ||
209 put_user(oldlen, oldlenp))
210 return -EFAULT;
211 }
212
213 lock_kernel();
214 result = do_sysctl(compat_ptr(tmp.name), tmp.nlen,
215 compat_ptr(tmp.oldval), oldlenp,
216 compat_ptr(tmp.newval), tmp.newlen);
217 unlock_kernel();
218
219 if (oldlenp && !result) {
220 if (get_user(oldlen, oldlenp) ||
221 put_user(oldlen, compat_oldlenp))
222 return -EFAULT;
223 }
224
225 return result;
226}
227
228#endif /* CONFIG_COMPAT */