diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 71 |
1 files changed, 8 insertions, 63 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 255f6754c70d..8040f9d1cf07 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -212,7 +212,7 @@ static int proc_root_link(struct dentry *dentry, struct path *path) | |||
212 | static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf, | 212 | static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf, |
213 | size_t count, loff_t *ppos) | 213 | size_t count, loff_t *ppos) |
214 | { | 214 | { |
215 | unsigned long arg_start, arg_end, env_start, env_end; | 215 | unsigned long arg_start, arg_end; |
216 | unsigned long pos, len; | 216 | unsigned long pos, len; |
217 | char *page; | 217 | char *page; |
218 | 218 | ||
@@ -223,36 +223,18 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf, | |||
223 | spin_lock(&mm->arg_lock); | 223 | spin_lock(&mm->arg_lock); |
224 | arg_start = mm->arg_start; | 224 | arg_start = mm->arg_start; |
225 | arg_end = mm->arg_end; | 225 | arg_end = mm->arg_end; |
226 | env_start = mm->env_start; | ||
227 | env_end = mm->env_end; | ||
228 | spin_unlock(&mm->arg_lock); | 226 | spin_unlock(&mm->arg_lock); |
229 | 227 | ||
230 | if (arg_start >= arg_end) | 228 | if (arg_start >= arg_end) |
231 | return 0; | 229 | return 0; |
232 | 230 | ||
233 | /* | ||
234 | * We have traditionally allowed the user to re-write | ||
235 | * the argument strings and overflow the end result | ||
236 | * into the environment section. But only do that if | ||
237 | * the environment area is contiguous to the arguments. | ||
238 | */ | ||
239 | if (env_start != arg_end || env_start >= env_end) | ||
240 | env_start = env_end = arg_end; | ||
241 | |||
242 | /* .. and limit it to a maximum of one page of slop */ | ||
243 | if (env_end >= arg_end + PAGE_SIZE) | ||
244 | env_end = arg_end + PAGE_SIZE - 1; | ||
245 | |||
246 | /* We're not going to care if "*ppos" has high bits set */ | 231 | /* We're not going to care if "*ppos" has high bits set */ |
247 | pos = arg_start + *ppos; | ||
248 | |||
249 | /* .. but we do check the result is in the proper range */ | 232 | /* .. but we do check the result is in the proper range */ |
250 | if (pos < arg_start || pos >= env_end) | 233 | pos = arg_start + *ppos; |
234 | if (pos < arg_start || pos >= arg_end) | ||
251 | return 0; | 235 | return 0; |
252 | 236 | if (count > arg_end - pos) | |
253 | /* .. and we never go past env_end */ | 237 | count = arg_end - pos; |
254 | if (env_end - pos < count) | ||
255 | count = env_end - pos; | ||
256 | 238 | ||
257 | page = (char *)__get_free_page(GFP_KERNEL); | 239 | page = (char *)__get_free_page(GFP_KERNEL); |
258 | if (!page) | 240 | if (!page) |
@@ -262,48 +244,11 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf, | |||
262 | while (count) { | 244 | while (count) { |
263 | int got; | 245 | int got; |
264 | size_t size = min_t(size_t, PAGE_SIZE, count); | 246 | size_t size = min_t(size_t, PAGE_SIZE, count); |
265 | long offset; | ||
266 | 247 | ||
267 | /* | 248 | got = access_remote_vm(mm, pos, page, size, FOLL_ANON); |
268 | * Are we already starting past the official end? | 249 | if (got <= 0) |
269 | * We always include the last byte that is *supposed* | ||
270 | * to be NUL | ||
271 | */ | ||
272 | offset = (pos >= arg_end) ? pos - arg_end + 1 : 0; | ||
273 | |||
274 | got = access_remote_vm(mm, pos - offset, page, size + offset, FOLL_ANON); | ||
275 | if (got <= offset) | ||
276 | break; | 250 | break; |
277 | got -= offset; | 251 | got -= copy_to_user(buf, page, got); |
278 | |||
279 | /* Don't walk past a NUL character once you hit arg_end */ | ||
280 | if (pos + got >= arg_end) { | ||
281 | int n = 0; | ||
282 | |||
283 | /* | ||
284 | * If we started before 'arg_end' but ended up | ||
285 | * at or after it, we start the NUL character | ||
286 | * check at arg_end-1 (where we expect the normal | ||
287 | * EOF to be). | ||
288 | * | ||
289 | * NOTE! This is smaller than 'got', because | ||
290 | * pos + got >= arg_end | ||
291 | */ | ||
292 | if (pos < arg_end) | ||
293 | n = arg_end - pos - 1; | ||
294 | |||
295 | /* Cut off at first NUL after 'n' */ | ||
296 | got = n + strnlen(page+n, offset+got-n); | ||
297 | if (got < offset) | ||
298 | break; | ||
299 | got -= offset; | ||
300 | |||
301 | /* Include the NUL if it existed */ | ||
302 | if (got < size) | ||
303 | got++; | ||
304 | } | ||
305 | |||
306 | got -= copy_to_user(buf, page+offset, got); | ||
307 | if (unlikely(!got)) { | 252 | if (unlikely(!got)) { |
308 | if (!len) | 253 | if (!len) |
309 | len = -EFAULT; | 254 | len = -EFAULT; |