aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/proc/base.c205
1 files changed, 196 insertions, 9 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 286a422f440e..bd7a9affc14b 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -196,18 +196,205 @@ static int proc_root_link(struct dentry *dentry, struct path *path)
196 return result; 196 return result;
197} 197}
198 198
199static int proc_pid_cmdline(struct seq_file *m, struct pid_namespace *ns, 199static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
200 struct pid *pid, struct task_struct *task) 200 size_t _count, loff_t *pos)
201{ 201{
202 struct task_struct *tsk;
203 struct mm_struct *mm;
204 char *page;
205 unsigned long count = _count;
206 unsigned long arg_start, arg_end, env_start, env_end;
207 unsigned long len1, len2, len;
208 unsigned long p;
209 char c;
210 ssize_t rv;
211
212 BUG_ON(*pos < 0);
213
214 tsk = get_proc_task(file_inode(file));
215 if (!tsk)
216 return -ESRCH;
217 mm = get_task_mm(tsk);
218 put_task_struct(tsk);
219 if (!mm)
220 return 0;
221 /* Check if process spawned far enough to have cmdline. */
222 if (!mm->env_end) {
223 rv = 0;
224 goto out_mmput;
225 }
226
227 page = (char *)__get_free_page(GFP_TEMPORARY);
228 if (!page) {
229 rv = -ENOMEM;
230 goto out_mmput;
231 }
232
233 down_read(&mm->mmap_sem);
234 arg_start = mm->arg_start;
235 arg_end = mm->arg_end;
236 env_start = mm->env_start;
237 env_end = mm->env_end;
238 up_read(&mm->mmap_sem);
239
240 BUG_ON(arg_start > arg_end);
241 BUG_ON(env_start > env_end);
242
243 len1 = arg_end - arg_start;
244 len2 = env_end - env_start;
245
202 /* 246 /*
203 * Rely on struct seq_operations::show() being called once 247 * Inherently racy -- command line shares address space
204 * per internal buffer allocation. See single_open(), traverse(). 248 * with code and data.
205 */ 249 */
206 BUG_ON(m->size < PAGE_SIZE); 250 rv = access_remote_vm(mm, arg_end - 1, &c, 1, 0);
207 m->count += get_cmdline(task, m->buf, PAGE_SIZE); 251 if (rv <= 0)
208 return 0; 252 goto out_free_page;
253
254 rv = 0;
255
256 if (c == '\0') {
257 /* Command line (set of strings) occupies whole ARGV. */
258 if (len1 <= *pos)
259 goto out_free_page;
260
261 p = arg_start + *pos;
262 len = len1 - *pos;
263 while (count > 0 && len > 0) {
264 unsigned int _count;
265 int nr_read;
266
267 _count = min3(count, len, PAGE_SIZE);
268 nr_read = access_remote_vm(mm, p, page, _count, 0);
269 if (nr_read < 0)
270 rv = nr_read;
271 if (nr_read <= 0)
272 goto out_free_page;
273
274 if (copy_to_user(buf, page, nr_read)) {
275 rv = -EFAULT;
276 goto out_free_page;
277 }
278
279 p += nr_read;
280 len -= nr_read;
281 buf += nr_read;
282 count -= nr_read;
283 rv += nr_read;
284 }
285 } else {
286 /*
287 * Command line (1 string) occupies ARGV and maybe
288 * extends into ENVP.
289 */
290 if (len1 + len2 <= *pos)
291 goto skip_argv_envp;
292 if (len1 <= *pos)
293 goto skip_argv;
294
295 p = arg_start + *pos;
296 len = len1 - *pos;
297 while (count > 0 && len > 0) {
298 unsigned int _count, l;
299 int nr_read;
300 bool final;
301
302 _count = min3(count, len, PAGE_SIZE);
303 nr_read = access_remote_vm(mm, p, page, _count, 0);
304 if (nr_read < 0)
305 rv = nr_read;
306 if (nr_read <= 0)
307 goto out_free_page;
308
309 /*
310 * Command line can be shorter than whole ARGV
311 * even if last "marker" byte says it is not.
312 */
313 final = false;
314 l = strnlen(page, nr_read);
315 if (l < nr_read) {
316 nr_read = l;
317 final = true;
318 }
319
320 if (copy_to_user(buf, page, nr_read)) {
321 rv = -EFAULT;
322 goto out_free_page;
323 }
324
325 p += nr_read;
326 len -= nr_read;
327 buf += nr_read;
328 count -= nr_read;
329 rv += nr_read;
330
331 if (final)
332 goto out_free_page;
333 }
334skip_argv:
335 /*
336 * Command line (1 string) occupies ARGV and
337 * extends into ENVP.
338 */
339 if (len1 <= *pos) {
340 p = env_start + *pos - len1;
341 len = len1 + len2 - *pos;
342 } else {
343 p = env_start;
344 len = len2;
345 }
346 while (count > 0 && len > 0) {
347 unsigned int _count, l;
348 int nr_read;
349 bool final;
350
351 _count = min3(count, len, PAGE_SIZE);
352 nr_read = access_remote_vm(mm, p, page, _count, 0);
353 if (nr_read < 0)
354 rv = nr_read;
355 if (nr_read <= 0)
356 goto out_free_page;
357
358 /* Find EOS. */
359 final = false;
360 l = strnlen(page, nr_read);
361 if (l < nr_read) {
362 nr_read = l;
363 final = true;
364 }
365
366 if (copy_to_user(buf, page, nr_read)) {
367 rv = -EFAULT;
368 goto out_free_page;
369 }
370
371 p += nr_read;
372 len -= nr_read;
373 buf += nr_read;
374 count -= nr_read;
375 rv += nr_read;
376
377 if (final)
378 goto out_free_page;
379 }
380skip_argv_envp:
381 ;
382 }
383
384out_free_page:
385 free_page((unsigned long)page);
386out_mmput:
387 mmput(mm);
388 if (rv > 0)
389 *pos += rv;
390 return rv;
209} 391}
210 392
393static const struct file_operations proc_pid_cmdline_ops = {
394 .read = proc_pid_cmdline_read,
395 .llseek = generic_file_llseek,
396};
397
211static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns, 398static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns,
212 struct pid *pid, struct task_struct *task) 399 struct pid *pid, struct task_struct *task)
213{ 400{
@@ -2572,7 +2759,7 @@ static const struct pid_entry tgid_base_stuff[] = {
2572#ifdef CONFIG_HAVE_ARCH_TRACEHOOK 2759#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
2573 ONE("syscall", S_IRUSR, proc_pid_syscall), 2760 ONE("syscall", S_IRUSR, proc_pid_syscall),
2574#endif 2761#endif
2575 ONE("cmdline", S_IRUGO, proc_pid_cmdline), 2762 REG("cmdline", S_IRUGO, proc_pid_cmdline_ops),
2576 ONE("stat", S_IRUGO, proc_tgid_stat), 2763 ONE("stat", S_IRUGO, proc_tgid_stat),
2577 ONE("statm", S_IRUGO, proc_pid_statm), 2764 ONE("statm", S_IRUGO, proc_pid_statm),
2578 REG("maps", S_IRUGO, proc_pid_maps_operations), 2765 REG("maps", S_IRUGO, proc_pid_maps_operations),
@@ -2918,7 +3105,7 @@ static const struct pid_entry tid_base_stuff[] = {
2918#ifdef CONFIG_HAVE_ARCH_TRACEHOOK 3105#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
2919 ONE("syscall", S_IRUSR, proc_pid_syscall), 3106 ONE("syscall", S_IRUSR, proc_pid_syscall),
2920#endif 3107#endif
2921 ONE("cmdline", S_IRUGO, proc_pid_cmdline), 3108 REG("cmdline", S_IRUGO, proc_pid_cmdline_ops),
2922 ONE("stat", S_IRUGO, proc_tid_stat), 3109 ONE("stat", S_IRUGO, proc_tid_stat),
2923 ONE("statm", S_IRUGO, proc_pid_statm), 3110 ONE("statm", S_IRUGO, proc_pid_statm),
2924 REG("maps", S_IRUGO, proc_tid_maps_operations), 3111 REG("maps", S_IRUGO, proc_tid_maps_operations),