Commit 2830b68361a9f58354ad043c6d85043ea917f907

Authored by Eric W. Biederman
1 parent afa588b265

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>

Showing 1 changed file with 58 additions and 65 deletions Side-by-side Diff

kernel/sysctl_binary.c
... ... @@ -14,8 +14,6 @@
14 14 #include <linux/ctype.h>
15 15 #include <linux/smp_lock.h>
16 16  
17   -static int deprecated_sysctl_warning(struct __sysctl_args *args);
18   -
19 17 #ifdef CONFIG_SYSCTL_SYSCALL
20 18  
21 19 /* Perform the actual read/write of a sysctl table entry. */
... ... @@ -51,7 +49,7 @@
51 49 return 0;
52 50 }
53 51  
54   -static int parse_table(int __user *name, int nlen,
  52 +static int parse_table(const int *name, int nlen,
55 53 void __user *oldval, size_t __user *oldlenp,
56 54 void __user *newval, size_t newlen,
57 55 struct ctl_table_root *root,
... ... @@ -61,8 +59,7 @@
61 59 repeat:
62 60 if (!nlen)
63 61 return -ENOTDIR;
64   - if (get_user(n, name))
65   - return -EFAULT;
  62 + n = *name;
66 63 for ( ; table->ctl_name || table->procname; table++) {
67 64 if (!table->ctl_name)
68 65 continue;
69 66  
70 67  
... ... @@ -85,20 +82,14 @@
85 82 return -ENOTDIR;
86 83 }
87 84  
88   -int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
89   - void __user *newval, size_t newlen)
  85 +static 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 +
90 89 {
91 90 struct ctl_table_header *head;
92   - int error = -ENOTDIR;
  91 + ssize_t error = -ENOTDIR;
93 92  
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 93 for (head = sysctl_head_next(NULL); head;
103 94 head = sysctl_head_next(head)) {
104 95 error = parse_table(name, nlen, oldval, oldlenp,
105 96  
106 97  
107 98  
108 99  
109 100  
110 101  
111 102  
112 103  
... ... @@ -112,75 +103,77 @@
112 103 return error;
113 104 }
114 105  
115   -SYSCALL_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();
131   -out:
132   - return error;
133   -}
134   -
135 106 #else /* CONFIG_SYSCTL_SYSCALL */
136 107  
137   -SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
  108 +static 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;
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;
  112 + return -ENOSYS;
152 113 }
153 114  
154 115 #endif /* CONFIG_SYSCTL_SYSCALL */
155 116  
156   -static int deprecated_sysctl_warning(struct __sysctl_args *args)
  117 +static void deprecated_sysctl_warning(const int *name, int nlen)
157 118 {
158 119 static int msg_count;
159   - int name[CTL_MAXNAME];
160 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 122 /* Ignore accesses to kernel.version */
172   - if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
173   - return 0;
  123 + if ((nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
  124 + return;
174 125  
175 126 if (msg_count < 5) {
176 127 msg_count++;
177 128 printk(KERN_INFO
178 129 "warning: process `%s' used the deprecated sysctl "
179 130 "system call with ", current->comm);
180   - for (i = 0; i < args->nlen; i++)
  131 + for (i = 0; i < nlen; i++)
181 132 printk("%d.", name[i]);
182 133 printk("\n");
183 134 }
184   - return 0;
  135 + return;
  136 +}
  137 +
  138 +int 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 +
  164 +SYSCALL_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 }