aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2009-04-03 03:09:33 -0400
committerEric W. Biederman <ebiederm@xmission.com>2009-11-06 06:23:35 -0500
commit2830b68361a9f58354ad043c6d85043ea917f907 (patch)
treed4ab2ecbeb4340365274a8fc81c5dd0e0e092cb7 /kernel
parentafa588b2651a03da4bc601a17a244b1cd97264f2 (diff)
sysctl: Refactor the binary sysctl handling to remove duplicate code
Read in the binary sysctl path once, instead of reread it from user space each time the code needs to access a path element. The deprecated sysctl warning is moved to do_sysctl so that the compat_sysctl entries syscalls will also warn. The return of -ENOSYS when !CONFIG_SYSCTL_SYSCALL is moved to binary_sysctl. Always leaving a do_sysctl available that handles !CONFIG_SYSCTL_SYSCALL and printing the deprecated sysctl warning allows for a single defitition of the sysctl syscall. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sysctl_binary.c123
1 files changed, 58 insertions, 65 deletions
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index eceeed20ca88..930a31cd708b 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -14,8 +14,6 @@
14#include <linux/ctype.h> 14#include <linux/ctype.h>
15#include <linux/smp_lock.h> 15#include <linux/smp_lock.h>
16 16
17static int deprecated_sysctl_warning(struct __sysctl_args *args);
18
19#ifdef CONFIG_SYSCTL_SYSCALL 17#ifdef CONFIG_SYSCTL_SYSCALL
20 18
21/* Perform the actual read/write of a sysctl table entry. */ 19/* Perform the actual read/write of a sysctl table entry. */
@@ -51,7 +49,7 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
51 return 0; 49 return 0;
52} 50}
53 51
54static int parse_table(int __user *name, int nlen, 52static int parse_table(const int *name, int nlen,
55 void __user *oldval, size_t __user *oldlenp, 53 void __user *oldval, size_t __user *oldlenp,
56 void __user *newval, size_t newlen, 54 void __user *newval, size_t newlen,
57 struct ctl_table_root *root, 55 struct ctl_table_root *root,
@@ -61,8 +59,7 @@ static int parse_table(int __user *name, int nlen,
61repeat: 59repeat:
62 if (!nlen) 60 if (!nlen)
63 return -ENOTDIR; 61 return -ENOTDIR;
64 if (get_user(n, name)) 62 n = *name;
65 return -EFAULT;
66 for ( ; table->ctl_name || table->procname; table++) { 63 for ( ; table->ctl_name || table->procname; table++) {
67 if (!table->ctl_name) 64 if (!table->ctl_name)
68 continue; 65 continue;
@@ -85,19 +82,13 @@ repeat:
85 return -ENOTDIR; 82 return -ENOTDIR;
86} 83}
87 84
88int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, 85static ssize_t binary_sysctl(const int *name, int nlen,
89 void __user *newval, size_t newlen) 86 void __user *oldval, size_t __user *oldlenp,
87 void __user *newval, size_t newlen)
88
90{ 89{
91 struct ctl_table_header *head; 90 struct ctl_table_header *head;
92 int error = -ENOTDIR; 91 ssize_t 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 92
102 for (head = sysctl_head_next(NULL); head; 93 for (head = sysctl_head_next(NULL); head;
103 head = sysctl_head_next(head)) { 94 head = sysctl_head_next(head)) {
@@ -112,74 +103,76 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
112 return error; 103 return error;
113} 104}
114 105
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 */ 106#else /* CONFIG_SYSCTL_SYSCALL */
136 107
137SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) 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)
138{ 111{
139 struct __sysctl_args tmp; 112 return -ENOSYS;
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} 113}
153 114
154#endif /* CONFIG_SYSCTL_SYSCALL */ 115#endif /* CONFIG_SYSCTL_SYSCALL */
155 116
156static int deprecated_sysctl_warning(struct __sysctl_args *args) 117static void deprecated_sysctl_warning(const int *name, int nlen)
157{ 118{
158 static int msg_count; 119 static int msg_count;
159 int name[CTL_MAXNAME];
160 int i; 120 int i;
161 121
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 */ 122 /* Ignore accesses to kernel.version */
172 if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION)) 123 if ((nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
173 return 0; 124 return;
174 125
175 if (msg_count < 5) { 126 if (msg_count < 5) {
176 msg_count++; 127 msg_count++;
177 printk(KERN_INFO 128 printk(KERN_INFO
178 "warning: process `%s' used the deprecated sysctl " 129 "warning: process `%s' used the deprecated sysctl "
179 "system call with ", current->comm); 130 "system call with ", current->comm);
180 for (i = 0; i < args->nlen; i++) 131 for (i = 0; i < nlen; i++)
181 printk("%d.", name[i]); 132 printk("%d.", name[i]);
182 printk("\n"); 133 printk("\n");
183 } 134 }
184 return 0; 135 return;
136}
137
138int do_sysctl(int __user *args_name, int nlen,
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;
185} 178}