diff options
-rw-r--r-- | kernel/sysctl_binary.c | 123 |
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 | ||
17 | static 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 | ||
54 | static int parse_table(int __user *name, int nlen, | 52 | static 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, | |||
61 | repeat: | 59 | repeat: |
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 | ||
88 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, | 85 | static 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 | ||
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 | #else /* CONFIG_SYSCTL_SYSCALL */ | 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; | 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 | ||
156 | static int deprecated_sysctl_warning(struct __sysctl_args *args) | 117 | static 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 | |||
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 | } |