diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 4 | ||||
-rw-r--r-- | fs/proc/base.c | 178 | ||||
-rw-r--r-- | fs/proc/generic.c | 8 | ||||
-rw-r--r-- | fs/proc/inode.c | 2 | ||||
-rw-r--r-- | fs/proc/internal.h | 1 | ||||
-rw-r--r-- | fs/proc/root.c | 32 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 27 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 6 |
8 files changed, 151 insertions, 107 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 7c99c1cf7e5c..5e4f776b0917 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -489,8 +489,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
489 | vsize, | 489 | vsize, |
490 | mm ? get_mm_rss(mm) : 0, | 490 | mm ? get_mm_rss(mm) : 0, |
491 | rsslim, | 491 | rsslim, |
492 | mm ? mm->start_code : 0, | 492 | mm ? (permitted ? mm->start_code : 1) : 0, |
493 | mm ? mm->end_code : 0, | 493 | mm ? (permitted ? mm->end_code : 1) : 0, |
494 | (permitted && mm) ? mm->start_stack : 0, | 494 | (permitted && mm) ? mm->start_stack : 0, |
495 | esp, | 495 | esp, |
496 | eip, | 496 | eip, |
diff --git a/fs/proc/base.c b/fs/proc/base.c index d49c4b5d2c3e..5a670c11aeac 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -191,17 +191,20 @@ static int proc_root_link(struct inode *inode, struct path *path) | |||
191 | return result; | 191 | return result; |
192 | } | 192 | } |
193 | 193 | ||
194 | /* | 194 | static struct mm_struct *__check_mem_permission(struct task_struct *task) |
195 | * Return zero if current may access user memory in @task, -error if not. | ||
196 | */ | ||
197 | static int check_mem_permission(struct task_struct *task) | ||
198 | { | 195 | { |
196 | struct mm_struct *mm; | ||
197 | |||
198 | mm = get_task_mm(task); | ||
199 | if (!mm) | ||
200 | return ERR_PTR(-EINVAL); | ||
201 | |||
199 | /* | 202 | /* |
200 | * A task can always look at itself, in case it chooses | 203 | * A task can always look at itself, in case it chooses |
201 | * to use system calls instead of load instructions. | 204 | * to use system calls instead of load instructions. |
202 | */ | 205 | */ |
203 | if (task == current) | 206 | if (task == current) |
204 | return 0; | 207 | return mm; |
205 | 208 | ||
206 | /* | 209 | /* |
207 | * If current is actively ptrace'ing, and would also be | 210 | * If current is actively ptrace'ing, and would also be |
@@ -213,27 +216,53 @@ static int check_mem_permission(struct task_struct *task) | |||
213 | match = (tracehook_tracer_task(task) == current); | 216 | match = (tracehook_tracer_task(task) == current); |
214 | rcu_read_unlock(); | 217 | rcu_read_unlock(); |
215 | if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH)) | 218 | if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH)) |
216 | return 0; | 219 | return mm; |
217 | } | 220 | } |
218 | 221 | ||
219 | /* | 222 | /* |
220 | * Noone else is allowed. | 223 | * Noone else is allowed. |
221 | */ | 224 | */ |
222 | return -EPERM; | 225 | mmput(mm); |
226 | return ERR_PTR(-EPERM); | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * If current may access user memory in @task return a reference to the | ||
231 | * corresponding mm, otherwise ERR_PTR. | ||
232 | */ | ||
233 | static struct mm_struct *check_mem_permission(struct task_struct *task) | ||
234 | { | ||
235 | struct mm_struct *mm; | ||
236 | int err; | ||
237 | |||
238 | /* | ||
239 | * Avoid racing if task exec's as we might get a new mm but validate | ||
240 | * against old credentials. | ||
241 | */ | ||
242 | err = mutex_lock_killable(&task->signal->cred_guard_mutex); | ||
243 | if (err) | ||
244 | return ERR_PTR(err); | ||
245 | |||
246 | mm = __check_mem_permission(task); | ||
247 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
248 | |||
249 | return mm; | ||
223 | } | 250 | } |
224 | 251 | ||
225 | struct mm_struct *mm_for_maps(struct task_struct *task) | 252 | struct mm_struct *mm_for_maps(struct task_struct *task) |
226 | { | 253 | { |
227 | struct mm_struct *mm; | 254 | struct mm_struct *mm; |
255 | int err; | ||
228 | 256 | ||
229 | if (mutex_lock_killable(&task->signal->cred_guard_mutex)) | 257 | err = mutex_lock_killable(&task->signal->cred_guard_mutex); |
230 | return NULL; | 258 | if (err) |
259 | return ERR_PTR(err); | ||
231 | 260 | ||
232 | mm = get_task_mm(task); | 261 | mm = get_task_mm(task); |
233 | if (mm && mm != current->mm && | 262 | if (mm && mm != current->mm && |
234 | !ptrace_may_access(task, PTRACE_MODE_READ)) { | 263 | !ptrace_may_access(task, PTRACE_MODE_READ)) { |
235 | mmput(mm); | 264 | mmput(mm); |
236 | mm = NULL; | 265 | mm = ERR_PTR(-EACCES); |
237 | } | 266 | } |
238 | mutex_unlock(&task->signal->cred_guard_mutex); | 267 | mutex_unlock(&task->signal->cred_guard_mutex); |
239 | 268 | ||
@@ -279,9 +308,9 @@ out: | |||
279 | 308 | ||
280 | static int proc_pid_auxv(struct task_struct *task, char *buffer) | 309 | static int proc_pid_auxv(struct task_struct *task, char *buffer) |
281 | { | 310 | { |
282 | int res = 0; | 311 | struct mm_struct *mm = mm_for_maps(task); |
283 | struct mm_struct *mm = get_task_mm(task); | 312 | int res = PTR_ERR(mm); |
284 | if (mm) { | 313 | if (mm && !IS_ERR(mm)) { |
285 | unsigned int nwords = 0; | 314 | unsigned int nwords = 0; |
286 | do { | 315 | do { |
287 | nwords += 2; | 316 | nwords += 2; |
@@ -318,6 +347,23 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer) | |||
318 | } | 347 | } |
319 | #endif /* CONFIG_KALLSYMS */ | 348 | #endif /* CONFIG_KALLSYMS */ |
320 | 349 | ||
350 | static int lock_trace(struct task_struct *task) | ||
351 | { | ||
352 | int err = mutex_lock_killable(&task->signal->cred_guard_mutex); | ||
353 | if (err) | ||
354 | return err; | ||
355 | if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) { | ||
356 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
357 | return -EPERM; | ||
358 | } | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static void unlock_trace(struct task_struct *task) | ||
363 | { | ||
364 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
365 | } | ||
366 | |||
321 | #ifdef CONFIG_STACKTRACE | 367 | #ifdef CONFIG_STACKTRACE |
322 | 368 | ||
323 | #define MAX_STACK_TRACE_DEPTH 64 | 369 | #define MAX_STACK_TRACE_DEPTH 64 |
@@ -327,6 +373,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, | |||
327 | { | 373 | { |
328 | struct stack_trace trace; | 374 | struct stack_trace trace; |
329 | unsigned long *entries; | 375 | unsigned long *entries; |
376 | int err; | ||
330 | int i; | 377 | int i; |
331 | 378 | ||
332 | entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); | 379 | entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); |
@@ -337,15 +384,20 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, | |||
337 | trace.max_entries = MAX_STACK_TRACE_DEPTH; | 384 | trace.max_entries = MAX_STACK_TRACE_DEPTH; |
338 | trace.entries = entries; | 385 | trace.entries = entries; |
339 | trace.skip = 0; | 386 | trace.skip = 0; |
340 | save_stack_trace_tsk(task, &trace); | ||
341 | 387 | ||
342 | for (i = 0; i < trace.nr_entries; i++) { | 388 | err = lock_trace(task); |
343 | seq_printf(m, "[<%p>] %pS\n", | 389 | if (!err) { |
344 | (void *)entries[i], (void *)entries[i]); | 390 | save_stack_trace_tsk(task, &trace); |
391 | |||
392 | for (i = 0; i < trace.nr_entries; i++) { | ||
393 | seq_printf(m, "[<%pK>] %pS\n", | ||
394 | (void *)entries[i], (void *)entries[i]); | ||
395 | } | ||
396 | unlock_trace(task); | ||
345 | } | 397 | } |
346 | kfree(entries); | 398 | kfree(entries); |
347 | 399 | ||
348 | return 0; | 400 | return err; |
349 | } | 401 | } |
350 | #endif | 402 | #endif |
351 | 403 | ||
@@ -508,18 +560,22 @@ static int proc_pid_syscall(struct task_struct *task, char *buffer) | |||
508 | { | 560 | { |
509 | long nr; | 561 | long nr; |
510 | unsigned long args[6], sp, pc; | 562 | unsigned long args[6], sp, pc; |
563 | int res = lock_trace(task); | ||
564 | if (res) | ||
565 | return res; | ||
511 | 566 | ||
512 | if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) | 567 | if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) |
513 | return sprintf(buffer, "running\n"); | 568 | res = sprintf(buffer, "running\n"); |
514 | 569 | else if (nr < 0) | |
515 | if (nr < 0) | 570 | res = sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc); |
516 | return sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc); | 571 | else |
517 | 572 | res = sprintf(buffer, | |
518 | return sprintf(buffer, | ||
519 | "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", | 573 | "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", |
520 | nr, | 574 | nr, |
521 | args[0], args[1], args[2], args[3], args[4], args[5], | 575 | args[0], args[1], args[2], args[3], args[4], args[5], |
522 | sp, pc); | 576 | sp, pc); |
577 | unlock_trace(task); | ||
578 | return res; | ||
523 | } | 579 | } |
524 | #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ | 580 | #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ |
525 | 581 | ||
@@ -775,18 +831,14 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
775 | if (!task) | 831 | if (!task) |
776 | goto out_no_task; | 832 | goto out_no_task; |
777 | 833 | ||
778 | if (check_mem_permission(task)) | ||
779 | goto out; | ||
780 | |||
781 | ret = -ENOMEM; | 834 | ret = -ENOMEM; |
782 | page = (char *)__get_free_page(GFP_TEMPORARY); | 835 | page = (char *)__get_free_page(GFP_TEMPORARY); |
783 | if (!page) | 836 | if (!page) |
784 | goto out; | 837 | goto out; |
785 | 838 | ||
786 | ret = 0; | 839 | mm = check_mem_permission(task); |
787 | 840 | ret = PTR_ERR(mm); | |
788 | mm = get_task_mm(task); | 841 | if (IS_ERR(mm)) |
789 | if (!mm) | ||
790 | goto out_free; | 842 | goto out_free; |
791 | 843 | ||
792 | ret = -EIO; | 844 | ret = -EIO; |
@@ -800,8 +852,8 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
800 | int this_len, retval; | 852 | int this_len, retval; |
801 | 853 | ||
802 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; | 854 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; |
803 | retval = access_process_vm(task, src, page, this_len, 0); | 855 | retval = access_remote_vm(mm, src, page, this_len, 0); |
804 | if (!retval || check_mem_permission(task)) { | 856 | if (!retval) { |
805 | if (!ret) | 857 | if (!ret) |
806 | ret = -EIO; | 858 | ret = -EIO; |
807 | break; | 859 | break; |
@@ -829,10 +881,6 @@ out_no_task: | |||
829 | return ret; | 881 | return ret; |
830 | } | 882 | } |
831 | 883 | ||
832 | #define mem_write NULL | ||
833 | |||
834 | #ifndef mem_write | ||
835 | /* This is a security hazard */ | ||
836 | static ssize_t mem_write(struct file * file, const char __user *buf, | 884 | static ssize_t mem_write(struct file * file, const char __user *buf, |
837 | size_t count, loff_t *ppos) | 885 | size_t count, loff_t *ppos) |
838 | { | 886 | { |
@@ -840,18 +888,25 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
840 | char *page; | 888 | char *page; |
841 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); | 889 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); |
842 | unsigned long dst = *ppos; | 890 | unsigned long dst = *ppos; |
891 | struct mm_struct *mm; | ||
843 | 892 | ||
844 | copied = -ESRCH; | 893 | copied = -ESRCH; |
845 | if (!task) | 894 | if (!task) |
846 | goto out_no_task; | 895 | goto out_no_task; |
847 | 896 | ||
848 | if (check_mem_permission(task)) | 897 | mm = check_mem_permission(task); |
849 | goto out; | 898 | copied = PTR_ERR(mm); |
899 | if (IS_ERR(mm)) | ||
900 | goto out_task; | ||
901 | |||
902 | copied = -EIO; | ||
903 | if (file->private_data != (void *)((long)current->self_exec_id)) | ||
904 | goto out_mm; | ||
850 | 905 | ||
851 | copied = -ENOMEM; | 906 | copied = -ENOMEM; |
852 | page = (char *)__get_free_page(GFP_TEMPORARY); | 907 | page = (char *)__get_free_page(GFP_TEMPORARY); |
853 | if (!page) | 908 | if (!page) |
854 | goto out; | 909 | goto out_mm; |
855 | 910 | ||
856 | copied = 0; | 911 | copied = 0; |
857 | while (count > 0) { | 912 | while (count > 0) { |
@@ -862,7 +917,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
862 | copied = -EFAULT; | 917 | copied = -EFAULT; |
863 | break; | 918 | break; |
864 | } | 919 | } |
865 | retval = access_process_vm(task, dst, page, this_len, 1); | 920 | retval = access_remote_vm(mm, dst, page, this_len, 1); |
866 | if (!retval) { | 921 | if (!retval) { |
867 | if (!copied) | 922 | if (!copied) |
868 | copied = -EIO; | 923 | copied = -EIO; |
@@ -875,12 +930,13 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
875 | } | 930 | } |
876 | *ppos = dst; | 931 | *ppos = dst; |
877 | free_page((unsigned long) page); | 932 | free_page((unsigned long) page); |
878 | out: | 933 | out_mm: |
934 | mmput(mm); | ||
935 | out_task: | ||
879 | put_task_struct(task); | 936 | put_task_struct(task); |
880 | out_no_task: | 937 | out_no_task: |
881 | return copied; | 938 | return copied; |
882 | } | 939 | } |
883 | #endif | ||
884 | 940 | ||
885 | loff_t mem_lseek(struct file *file, loff_t offset, int orig) | 941 | loff_t mem_lseek(struct file *file, loff_t offset, int orig) |
886 | { | 942 | { |
@@ -917,20 +973,18 @@ static ssize_t environ_read(struct file *file, char __user *buf, | |||
917 | if (!task) | 973 | if (!task) |
918 | goto out_no_task; | 974 | goto out_no_task; |
919 | 975 | ||
920 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | ||
921 | goto out; | ||
922 | |||
923 | ret = -ENOMEM; | 976 | ret = -ENOMEM; |
924 | page = (char *)__get_free_page(GFP_TEMPORARY); | 977 | page = (char *)__get_free_page(GFP_TEMPORARY); |
925 | if (!page) | 978 | if (!page) |
926 | goto out; | 979 | goto out; |
927 | 980 | ||
928 | ret = 0; | ||
929 | 981 | ||
930 | mm = get_task_mm(task); | 982 | mm = mm_for_maps(task); |
931 | if (!mm) | 983 | ret = PTR_ERR(mm); |
984 | if (!mm || IS_ERR(mm)) | ||
932 | goto out_free; | 985 | goto out_free; |
933 | 986 | ||
987 | ret = 0; | ||
934 | while (count > 0) { | 988 | while (count > 0) { |
935 | int this_len, retval, max_len; | 989 | int this_len, retval, max_len; |
936 | 990 | ||
@@ -2748,8 +2802,12 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer) | |||
2748 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, | 2802 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, |
2749 | struct pid *pid, struct task_struct *task) | 2803 | struct pid *pid, struct task_struct *task) |
2750 | { | 2804 | { |
2751 | seq_printf(m, "%08x\n", task->personality); | 2805 | int err = lock_trace(task); |
2752 | return 0; | 2806 | if (!err) { |
2807 | seq_printf(m, "%08x\n", task->personality); | ||
2808 | unlock_trace(task); | ||
2809 | } | ||
2810 | return err; | ||
2753 | } | 2811 | } |
2754 | 2812 | ||
2755 | /* | 2813 | /* |
@@ -2768,7 +2826,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2768 | REG("environ", S_IRUSR, proc_environ_operations), | 2826 | REG("environ", S_IRUSR, proc_environ_operations), |
2769 | INF("auxv", S_IRUSR, proc_pid_auxv), | 2827 | INF("auxv", S_IRUSR, proc_pid_auxv), |
2770 | ONE("status", S_IRUGO, proc_pid_status), | 2828 | ONE("status", S_IRUGO, proc_pid_status), |
2771 | ONE("personality", S_IRUSR, proc_pid_personality), | 2829 | ONE("personality", S_IRUGO, proc_pid_personality), |
2772 | INF("limits", S_IRUGO, proc_pid_limits), | 2830 | INF("limits", S_IRUGO, proc_pid_limits), |
2773 | #ifdef CONFIG_SCHED_DEBUG | 2831 | #ifdef CONFIG_SCHED_DEBUG |
2774 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2832 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
@@ -2778,7 +2836,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2778 | #endif | 2836 | #endif |
2779 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | 2837 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
2780 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2838 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
2781 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2839 | INF("syscall", S_IRUGO, proc_pid_syscall), |
2782 | #endif | 2840 | #endif |
2783 | INF("cmdline", S_IRUGO, proc_pid_cmdline), | 2841 | INF("cmdline", S_IRUGO, proc_pid_cmdline), |
2784 | ONE("stat", S_IRUGO, proc_tgid_stat), | 2842 | ONE("stat", S_IRUGO, proc_tgid_stat), |
@@ -2797,7 +2855,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2797 | #ifdef CONFIG_PROC_PAGE_MONITOR | 2855 | #ifdef CONFIG_PROC_PAGE_MONITOR |
2798 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), | 2856 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), |
2799 | REG("smaps", S_IRUGO, proc_smaps_operations), | 2857 | REG("smaps", S_IRUGO, proc_smaps_operations), |
2800 | REG("pagemap", S_IRUSR, proc_pagemap_operations), | 2858 | REG("pagemap", S_IRUGO, proc_pagemap_operations), |
2801 | #endif | 2859 | #endif |
2802 | #ifdef CONFIG_SECURITY | 2860 | #ifdef CONFIG_SECURITY |
2803 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), | 2861 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), |
@@ -2806,7 +2864,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2806 | INF("wchan", S_IRUGO, proc_pid_wchan), | 2864 | INF("wchan", S_IRUGO, proc_pid_wchan), |
2807 | #endif | 2865 | #endif |
2808 | #ifdef CONFIG_STACKTRACE | 2866 | #ifdef CONFIG_STACKTRACE |
2809 | ONE("stack", S_IRUSR, proc_pid_stack), | 2867 | ONE("stack", S_IRUGO, proc_pid_stack), |
2810 | #endif | 2868 | #endif |
2811 | #ifdef CONFIG_SCHEDSTATS | 2869 | #ifdef CONFIG_SCHEDSTATS |
2812 | INF("schedstat", S_IRUGO, proc_pid_schedstat), | 2870 | INF("schedstat", S_IRUGO, proc_pid_schedstat), |
@@ -3108,14 +3166,14 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3108 | REG("environ", S_IRUSR, proc_environ_operations), | 3166 | REG("environ", S_IRUSR, proc_environ_operations), |
3109 | INF("auxv", S_IRUSR, proc_pid_auxv), | 3167 | INF("auxv", S_IRUSR, proc_pid_auxv), |
3110 | ONE("status", S_IRUGO, proc_pid_status), | 3168 | ONE("status", S_IRUGO, proc_pid_status), |
3111 | ONE("personality", S_IRUSR, proc_pid_personality), | 3169 | ONE("personality", S_IRUGO, proc_pid_personality), |
3112 | INF("limits", S_IRUGO, proc_pid_limits), | 3170 | INF("limits", S_IRUGO, proc_pid_limits), |
3113 | #ifdef CONFIG_SCHED_DEBUG | 3171 | #ifdef CONFIG_SCHED_DEBUG |
3114 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 3172 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
3115 | #endif | 3173 | #endif |
3116 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | 3174 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
3117 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 3175 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
3118 | INF("syscall", S_IRUSR, proc_pid_syscall), | 3176 | INF("syscall", S_IRUGO, proc_pid_syscall), |
3119 | #endif | 3177 | #endif |
3120 | INF("cmdline", S_IRUGO, proc_pid_cmdline), | 3178 | INF("cmdline", S_IRUGO, proc_pid_cmdline), |
3121 | ONE("stat", S_IRUGO, proc_tid_stat), | 3179 | ONE("stat", S_IRUGO, proc_tid_stat), |
@@ -3133,7 +3191,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3133 | #ifdef CONFIG_PROC_PAGE_MONITOR | 3191 | #ifdef CONFIG_PROC_PAGE_MONITOR |
3134 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), | 3192 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), |
3135 | REG("smaps", S_IRUGO, proc_smaps_operations), | 3193 | REG("smaps", S_IRUGO, proc_smaps_operations), |
3136 | REG("pagemap", S_IRUSR, proc_pagemap_operations), | 3194 | REG("pagemap", S_IRUGO, proc_pagemap_operations), |
3137 | #endif | 3195 | #endif |
3138 | #ifdef CONFIG_SECURITY | 3196 | #ifdef CONFIG_SECURITY |
3139 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), | 3197 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), |
@@ -3142,7 +3200,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3142 | INF("wchan", S_IRUGO, proc_pid_wchan), | 3200 | INF("wchan", S_IRUGO, proc_pid_wchan), |
3143 | #endif | 3201 | #endif |
3144 | #ifdef CONFIG_STACKTRACE | 3202 | #ifdef CONFIG_STACKTRACE |
3145 | ONE("stack", S_IRUSR, proc_pid_stack), | 3203 | ONE("stack", S_IRUGO, proc_pid_stack), |
3146 | #endif | 3204 | #endif |
3147 | #ifdef CONFIG_SCHEDSTATS | 3205 | #ifdef CONFIG_SCHEDSTATS |
3148 | INF("schedstat", S_IRUGO, proc_pid_schedstat), | 3206 | INF("schedstat", S_IRUGO, proc_pid_schedstat), |
@@ -3161,7 +3219,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3161 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), | 3219 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), |
3162 | #ifdef CONFIG_AUDITSYSCALL | 3220 | #ifdef CONFIG_AUDITSYSCALL |
3163 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), | 3221 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), |
3164 | REG("sessionid", S_IRUSR, proc_sessionid_operations), | 3222 | REG("sessionid", S_IRUGO, proc_sessionid_operations), |
3165 | #endif | 3223 | #endif |
3166 | #ifdef CONFIG_FAULT_INJECTION | 3224 | #ifdef CONFIG_FAULT_INJECTION |
3167 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), | 3225 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 01e07f2a188f..f1281339b6fa 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | DEFINE_SPINLOCK(proc_subdir_lock); | 29 | DEFINE_SPINLOCK(proc_subdir_lock); |
30 | 30 | ||
31 | static int proc_match(int len, const char *name, struct proc_dir_entry *de) | 31 | static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de) |
32 | { | 32 | { |
33 | if (de->namelen != len) | 33 | if (de->namelen != len) |
34 | return 0; | 34 | return 0; |
@@ -303,7 +303,7 @@ static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret, | |||
303 | { | 303 | { |
304 | const char *cp = name, *next; | 304 | const char *cp = name, *next; |
305 | struct proc_dir_entry *de; | 305 | struct proc_dir_entry *de; |
306 | int len; | 306 | unsigned int len; |
307 | 307 | ||
308 | de = *ret; | 308 | de = *ret; |
309 | if (!de) | 309 | if (!de) |
@@ -602,7 +602,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
602 | { | 602 | { |
603 | struct proc_dir_entry *ent = NULL; | 603 | struct proc_dir_entry *ent = NULL; |
604 | const char *fn = name; | 604 | const char *fn = name; |
605 | int len; | 605 | unsigned int len; |
606 | 606 | ||
607 | /* make sure name is valid */ | 607 | /* make sure name is valid */ |
608 | if (!name || !strlen(name)) goto out; | 608 | if (!name || !strlen(name)) goto out; |
@@ -786,7 +786,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
786 | struct proc_dir_entry **p; | 786 | struct proc_dir_entry **p; |
787 | struct proc_dir_entry *de = NULL; | 787 | struct proc_dir_entry *de = NULL; |
788 | const char *fn = name; | 788 | const char *fn = name; |
789 | int len; | 789 | unsigned int len; |
790 | 790 | ||
791 | spin_lock(&proc_subdir_lock); | 791 | spin_lock(&proc_subdir_lock); |
792 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | 792 | if (__xlate_proc_name(name, &parent, &fn) != 0) { |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index d6a7ca1fdac5..d15aa1b1cc8f 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -46,8 +46,6 @@ static void proc_evict_inode(struct inode *inode) | |||
46 | } | 46 | } |
47 | } | 47 | } |
48 | 48 | ||
49 | struct vfsmount *proc_mnt; | ||
50 | |||
51 | static struct kmem_cache * proc_inode_cachep; | 49 | static struct kmem_cache * proc_inode_cachep; |
52 | 50 | ||
53 | static struct inode *proc_alloc_inode(struct super_block *sb) | 51 | static struct inode *proc_alloc_inode(struct super_block *sb) |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 9ad561ded409..c03e8d3a3a5b 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -107,7 +107,6 @@ static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) | |||
107 | } | 107 | } |
108 | void pde_put(struct proc_dir_entry *pde); | 108 | void pde_put(struct proc_dir_entry *pde); |
109 | 109 | ||
110 | extern struct vfsmount *proc_mnt; | ||
111 | int proc_fill_super(struct super_block *); | 110 | int proc_fill_super(struct super_block *); |
112 | struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); | 111 | struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); |
113 | 112 | ||
diff --git a/fs/proc/root.c b/fs/proc/root.c index ef9fa8e24ad6..a9000e9cfee5 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -43,17 +43,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
43 | struct pid_namespace *ns; | 43 | struct pid_namespace *ns; |
44 | struct proc_inode *ei; | 44 | struct proc_inode *ei; |
45 | 45 | ||
46 | if (proc_mnt) { | ||
47 | /* Seed the root directory with a pid so it doesn't need | ||
48 | * to be special in base.c. I would do this earlier but | ||
49 | * the only task alive when /proc is mounted the first time | ||
50 | * is the init_task and it doesn't have any pids. | ||
51 | */ | ||
52 | ei = PROC_I(proc_mnt->mnt_sb->s_root->d_inode); | ||
53 | if (!ei->pid) | ||
54 | ei->pid = find_get_pid(1); | ||
55 | } | ||
56 | |||
57 | if (flags & MS_KERNMOUNT) | 46 | if (flags & MS_KERNMOUNT) |
58 | ns = (struct pid_namespace *)data; | 47 | ns = (struct pid_namespace *)data; |
59 | else | 48 | else |
@@ -71,16 +60,16 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
71 | return ERR_PTR(err); | 60 | return ERR_PTR(err); |
72 | } | 61 | } |
73 | 62 | ||
74 | ei = PROC_I(sb->s_root->d_inode); | ||
75 | if (!ei->pid) { | ||
76 | rcu_read_lock(); | ||
77 | ei->pid = get_pid(find_pid_ns(1, ns)); | ||
78 | rcu_read_unlock(); | ||
79 | } | ||
80 | |||
81 | sb->s_flags |= MS_ACTIVE; | 63 | sb->s_flags |= MS_ACTIVE; |
82 | } | 64 | } |
83 | 65 | ||
66 | ei = PROC_I(sb->s_root->d_inode); | ||
67 | if (!ei->pid) { | ||
68 | rcu_read_lock(); | ||
69 | ei->pid = get_pid(find_pid_ns(1, ns)); | ||
70 | rcu_read_unlock(); | ||
71 | } | ||
72 | |||
84 | return dget(sb->s_root); | 73 | return dget(sb->s_root); |
85 | } | 74 | } |
86 | 75 | ||
@@ -101,19 +90,20 @@ static struct file_system_type proc_fs_type = { | |||
101 | 90 | ||
102 | void __init proc_root_init(void) | 91 | void __init proc_root_init(void) |
103 | { | 92 | { |
93 | struct vfsmount *mnt; | ||
104 | int err; | 94 | int err; |
105 | 95 | ||
106 | proc_init_inodecache(); | 96 | proc_init_inodecache(); |
107 | err = register_filesystem(&proc_fs_type); | 97 | err = register_filesystem(&proc_fs_type); |
108 | if (err) | 98 | if (err) |
109 | return; | 99 | return; |
110 | proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); | 100 | mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); |
111 | if (IS_ERR(proc_mnt)) { | 101 | if (IS_ERR(mnt)) { |
112 | unregister_filesystem(&proc_fs_type); | 102 | unregister_filesystem(&proc_fs_type); |
113 | return; | 103 | return; |
114 | } | 104 | } |
115 | 105 | ||
116 | init_pid_ns.proc_mnt = proc_mnt; | 106 | init_pid_ns.proc_mnt = mnt; |
117 | proc_symlink("mounts", NULL, "self/mounts"); | 107 | proc_symlink("mounts", NULL, "self/mounts"); |
118 | 108 | ||
119 | proc_net_init(); | 109 | proc_net_init(); |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 93381aae9363..7c708a418acc 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -121,14 +121,14 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
121 | 121 | ||
122 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); | 122 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); |
123 | if (!priv->task) | 123 | if (!priv->task) |
124 | return NULL; | 124 | return ERR_PTR(-ESRCH); |
125 | 125 | ||
126 | mm = mm_for_maps(priv->task); | 126 | mm = mm_for_maps(priv->task); |
127 | if (!mm) | 127 | if (!mm || IS_ERR(mm)) |
128 | return NULL; | 128 | return mm; |
129 | down_read(&mm->mmap_sem); | 129 | down_read(&mm->mmap_sem); |
130 | 130 | ||
131 | tail_vma = get_gate_vma(priv->task); | 131 | tail_vma = get_gate_vma(priv->task->mm); |
132 | priv->tail_vma = tail_vma; | 132 | priv->tail_vma = tail_vma; |
133 | 133 | ||
134 | /* Start with last addr hint */ | 134 | /* Start with last addr hint */ |
@@ -251,8 +251,8 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) | |||
251 | const char *name = arch_vma_name(vma); | 251 | const char *name = arch_vma_name(vma); |
252 | if (!name) { | 252 | if (!name) { |
253 | if (mm) { | 253 | if (mm) { |
254 | if (vma->vm_start <= mm->start_brk && | 254 | if (vma->vm_start <= mm->brk && |
255 | vma->vm_end >= mm->brk) { | 255 | vma->vm_end >= mm->start_brk) { |
256 | name = "[heap]"; | 256 | name = "[heap]"; |
257 | } else if (vma->vm_start <= mm->start_stack && | 257 | } else if (vma->vm_start <= mm->start_stack && |
258 | vma->vm_end >= mm->start_stack) { | 258 | vma->vm_end >= mm->start_stack) { |
@@ -279,7 +279,8 @@ static int show_map(struct seq_file *m, void *v) | |||
279 | show_map_vma(m, vma); | 279 | show_map_vma(m, vma); |
280 | 280 | ||
281 | if (m->count < m->size) /* vma is copied successfully */ | 281 | if (m->count < m->size) /* vma is copied successfully */ |
282 | m->version = (vma != get_gate_vma(task))? vma->vm_start: 0; | 282 | m->version = (vma != get_gate_vma(task->mm)) |
283 | ? vma->vm_start : 0; | ||
283 | return 0; | 284 | return 0; |
284 | } | 285 | } |
285 | 286 | ||
@@ -468,7 +469,8 @@ static int show_smap(struct seq_file *m, void *v) | |||
468 | (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); | 469 | (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); |
469 | 470 | ||
470 | if (m->count < m->size) /* vma is copied successfully */ | 471 | if (m->count < m->size) /* vma is copied successfully */ |
471 | m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; | 472 | m->version = (vma != get_gate_vma(task->mm)) |
473 | ? vma->vm_start : 0; | ||
472 | return 0; | 474 | return 0; |
473 | } | 475 | } |
474 | 476 | ||
@@ -764,8 +766,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
764 | if (!task) | 766 | if (!task) |
765 | goto out; | 767 | goto out; |
766 | 768 | ||
767 | ret = -EACCES; | 769 | mm = mm_for_maps(task); |
768 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | 770 | ret = PTR_ERR(mm); |
771 | if (!mm || IS_ERR(mm)) | ||
769 | goto out_task; | 772 | goto out_task; |
770 | 773 | ||
771 | ret = -EINVAL; | 774 | ret = -EINVAL; |
@@ -778,10 +781,6 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
778 | if (!count) | 781 | if (!count) |
779 | goto out_task; | 782 | goto out_task; |
780 | 783 | ||
781 | mm = get_task_mm(task); | ||
782 | if (!mm) | ||
783 | goto out_task; | ||
784 | |||
785 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); | 784 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); |
786 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); | 785 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); |
787 | ret = -ENOMEM; | 786 | ret = -ENOMEM; |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index b535d3e5d5f1..980de547c070 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
@@ -199,13 +199,13 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
199 | /* pin the task and mm whilst we play with them */ | 199 | /* pin the task and mm whilst we play with them */ |
200 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); | 200 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); |
201 | if (!priv->task) | 201 | if (!priv->task) |
202 | return NULL; | 202 | return ERR_PTR(-ESRCH); |
203 | 203 | ||
204 | mm = mm_for_maps(priv->task); | 204 | mm = mm_for_maps(priv->task); |
205 | if (!mm) { | 205 | if (!mm || IS_ERR(mm)) { |
206 | put_task_struct(priv->task); | 206 | put_task_struct(priv->task); |
207 | priv->task = NULL; | 207 | priv->task = NULL; |
208 | return NULL; | 208 | return mm; |
209 | } | 209 | } |
210 | down_read(&mm->mmap_sem); | 210 | down_read(&mm->mmap_sem); |
211 | 211 | ||