aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-03-23 15:52:50 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-23 17:01:18 -0400
commita9712bc12c40c172e393f85a9b2ba8db4bf59509 (patch)
treec40217e028ae937da7ad94e249e2247191ffcc8f /fs/proc
parent198214a7ee50375fa71a65e518341980cfd4b2f0 (diff)
deal with races in /proc/*/{syscall,stack,personality}
All of those are rw-r--r-- and all are broken for suid - if you open a file before the target does suid-root exec, you'll be still able to access it. For personality it's not a big deal, but for syscall and stack it's a real problem. Fix: check that task is tracable for you at the time of read(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/base.c69
1 files changed, 50 insertions, 19 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index bc15df390ec4..7d5bb8b9a4ff 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -347,6 +347,23 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer)
347} 347}
348#endif /* CONFIG_KALLSYMS */ 348#endif /* CONFIG_KALLSYMS */
349 349
350static 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
362static void unlock_trace(struct task_struct *task)
363{
364 mutex_unlock(&task->signal->cred_guard_mutex);
365}
366
350#ifdef CONFIG_STACKTRACE 367#ifdef CONFIG_STACKTRACE
351 368
352#define MAX_STACK_TRACE_DEPTH 64 369#define MAX_STACK_TRACE_DEPTH 64
@@ -356,6 +373,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,
356{ 373{
357 struct stack_trace trace; 374 struct stack_trace trace;
358 unsigned long *entries; 375 unsigned long *entries;
376 int err;
359 int i; 377 int i;
360 378
361 entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); 379 entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL);
@@ -366,15 +384,20 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,
366 trace.max_entries = MAX_STACK_TRACE_DEPTH; 384 trace.max_entries = MAX_STACK_TRACE_DEPTH;
367 trace.entries = entries; 385 trace.entries = entries;
368 trace.skip = 0; 386 trace.skip = 0;
369 save_stack_trace_tsk(task, &trace);
370 387
371 for (i = 0; i < trace.nr_entries; i++) { 388 err = lock_trace(task);
372 seq_printf(m, "[<%p>] %pS\n", 389 if (!err) {
373 (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, "[<%p>] %pS\n",
394 (void *)entries[i], (void *)entries[i]);
395 }
396 unlock_trace(task);
374 } 397 }
375 kfree(entries); 398 kfree(entries);
376 399
377 return 0; 400 return err;
378} 401}
379#endif 402#endif
380 403
@@ -537,18 +560,22 @@ static int proc_pid_syscall(struct task_struct *task, char *buffer)
537{ 560{
538 long nr; 561 long nr;
539 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;
540 566
541 if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) 567 if (task_current_syscall(task, &nr, args, 6, &sp, &pc))
542 return sprintf(buffer, "running\n"); 568 res = sprintf(buffer, "running\n");
543 569 else if (nr < 0)
544 if (nr < 0) 570 res = sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc);
545 return sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc); 571 else
546 572 res = sprintf(buffer,
547 return sprintf(buffer,
548 "%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",
549 nr, 574 nr,
550 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],
551 sp, pc); 576 sp, pc);
577 unlock_trace(task);
578 return res;
552} 579}
553#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ 580#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */
554 581
@@ -2775,8 +2802,12 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer)
2775static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, 2802static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
2776 struct pid *pid, struct task_struct *task) 2803 struct pid *pid, struct task_struct *task)
2777{ 2804{
2778 seq_printf(m, "%08x\n", task->personality); 2805 int err = lock_trace(task);
2779 return 0; 2806 if (!err) {
2807 seq_printf(m, "%08x\n", task->personality);
2808 unlock_trace(task);
2809 }
2810 return err;
2780} 2811}
2781 2812
2782/* 2813/*
@@ -2795,7 +2826,7 @@ static const struct pid_entry tgid_base_stuff[] = {
2795 REG("environ", S_IRUSR, proc_environ_operations), 2826 REG("environ", S_IRUSR, proc_environ_operations),
2796 INF("auxv", S_IRUSR, proc_pid_auxv), 2827 INF("auxv", S_IRUSR, proc_pid_auxv),
2797 ONE("status", S_IRUGO, proc_pid_status), 2828 ONE("status", S_IRUGO, proc_pid_status),
2798 ONE("personality", S_IRUSR, proc_pid_personality), 2829 ONE("personality", S_IRUGO, proc_pid_personality),
2799 INF("limits", S_IRUGO, proc_pid_limits), 2830 INF("limits", S_IRUGO, proc_pid_limits),
2800#ifdef CONFIG_SCHED_DEBUG 2831#ifdef CONFIG_SCHED_DEBUG
2801 REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), 2832 REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
@@ -2805,7 +2836,7 @@ static const struct pid_entry tgid_base_stuff[] = {
2805#endif 2836#endif
2806 REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), 2837 REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
2807#ifdef CONFIG_HAVE_ARCH_TRACEHOOK 2838#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
2808 INF("syscall", S_IRUSR, proc_pid_syscall), 2839 INF("syscall", S_IRUGO, proc_pid_syscall),
2809#endif 2840#endif
2810 INF("cmdline", S_IRUGO, proc_pid_cmdline), 2841 INF("cmdline", S_IRUGO, proc_pid_cmdline),
2811 ONE("stat", S_IRUGO, proc_tgid_stat), 2842 ONE("stat", S_IRUGO, proc_tgid_stat),
@@ -2833,7 +2864,7 @@ static const struct pid_entry tgid_base_stuff[] = {
2833 INF("wchan", S_IRUGO, proc_pid_wchan), 2864 INF("wchan", S_IRUGO, proc_pid_wchan),
2834#endif 2865#endif
2835#ifdef CONFIG_STACKTRACE 2866#ifdef CONFIG_STACKTRACE
2836 ONE("stack", S_IRUSR, proc_pid_stack), 2867 ONE("stack", S_IRUGO, proc_pid_stack),
2837#endif 2868#endif
2838#ifdef CONFIG_SCHEDSTATS 2869#ifdef CONFIG_SCHEDSTATS
2839 INF("schedstat", S_IRUGO, proc_pid_schedstat), 2870 INF("schedstat", S_IRUGO, proc_pid_schedstat),
@@ -3135,14 +3166,14 @@ static const struct pid_entry tid_base_stuff[] = {
3135 REG("environ", S_IRUSR, proc_environ_operations), 3166 REG("environ", S_IRUSR, proc_environ_operations),
3136 INF("auxv", S_IRUSR, proc_pid_auxv), 3167 INF("auxv", S_IRUSR, proc_pid_auxv),
3137 ONE("status", S_IRUGO, proc_pid_status), 3168 ONE("status", S_IRUGO, proc_pid_status),
3138 ONE("personality", S_IRUSR, proc_pid_personality), 3169 ONE("personality", S_IRUGO, proc_pid_personality),
3139 INF("limits", S_IRUGO, proc_pid_limits), 3170 INF("limits", S_IRUGO, proc_pid_limits),
3140#ifdef CONFIG_SCHED_DEBUG 3171#ifdef CONFIG_SCHED_DEBUG
3141 REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), 3172 REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
3142#endif 3173#endif
3143 REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), 3174 REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
3144#ifdef CONFIG_HAVE_ARCH_TRACEHOOK 3175#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
3145 INF("syscall", S_IRUSR, proc_pid_syscall), 3176 INF("syscall", S_IRUGO, proc_pid_syscall),
3146#endif 3177#endif
3147 INF("cmdline", S_IRUGO, proc_pid_cmdline), 3178 INF("cmdline", S_IRUGO, proc_pid_cmdline),
3148 ONE("stat", S_IRUGO, proc_tid_stat), 3179 ONE("stat", S_IRUGO, proc_tid_stat),
@@ -3169,7 +3200,7 @@ static const struct pid_entry tid_base_stuff[] = {
3169 INF("wchan", S_IRUGO, proc_pid_wchan), 3200 INF("wchan", S_IRUGO, proc_pid_wchan),
3170#endif 3201#endif
3171#ifdef CONFIG_STACKTRACE 3202#ifdef CONFIG_STACKTRACE
3172 ONE("stack", S_IRUSR, proc_pid_stack), 3203 ONE("stack", S_IRUGO, proc_pid_stack),
3173#endif 3204#endif
3174#ifdef CONFIG_SCHEDSTATS 3205#ifdef CONFIG_SCHEDSTATS
3175 INF("schedstat", S_IRUGO, proc_pid_schedstat), 3206 INF("schedstat", S_IRUGO, proc_pid_schedstat),