diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 108 |
1 files changed, 65 insertions, 43 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 54e270262979..29fd7ef97be9 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -400,23 +400,6 @@ static const struct file_operations proc_pid_cmdline_ops = { | |||
400 | .llseek = generic_file_llseek, | 400 | .llseek = generic_file_llseek, |
401 | }; | 401 | }; |
402 | 402 | ||
403 | static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns, | ||
404 | struct pid *pid, struct task_struct *task) | ||
405 | { | ||
406 | struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); | ||
407 | if (mm && !IS_ERR(mm)) { | ||
408 | unsigned int nwords = 0; | ||
409 | do { | ||
410 | nwords += 2; | ||
411 | } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */ | ||
412 | seq_write(m, mm->saved_auxv, nwords * sizeof(mm->saved_auxv[0])); | ||
413 | mmput(mm); | ||
414 | return 0; | ||
415 | } else | ||
416 | return PTR_ERR(mm); | ||
417 | } | ||
418 | |||
419 | |||
420 | #ifdef CONFIG_KALLSYMS | 403 | #ifdef CONFIG_KALLSYMS |
421 | /* | 404 | /* |
422 | * Provides a wchan file via kallsyms in a proper one-value-per-file format. | 405 | * Provides a wchan file via kallsyms in a proper one-value-per-file format. |
@@ -483,7 +466,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, | |||
483 | save_stack_trace_tsk(task, &trace); | 466 | save_stack_trace_tsk(task, &trace); |
484 | 467 | ||
485 | for (i = 0; i < trace.nr_entries; i++) { | 468 | for (i = 0; i < trace.nr_entries; i++) { |
486 | seq_printf(m, "[<%pK>] %pS\n", | 469 | seq_printf(m, "[<%pK>] %pB\n", |
487 | (void *)entries[i], (void *)entries[i]); | 470 | (void *)entries[i], (void *)entries[i]); |
488 | } | 471 | } |
489 | unlock_trace(task); | 472 | unlock_trace(task); |
@@ -709,7 +692,7 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr) | |||
709 | if (attr->ia_valid & ATTR_MODE) | 692 | if (attr->ia_valid & ATTR_MODE) |
710 | return -EPERM; | 693 | return -EPERM; |
711 | 694 | ||
712 | error = inode_change_ok(inode, attr); | 695 | error = setattr_prepare(dentry, attr); |
713 | if (error) | 696 | if (error) |
714 | return error; | 697 | return error; |
715 | 698 | ||
@@ -1014,6 +997,30 @@ static const struct file_operations proc_environ_operations = { | |||
1014 | .release = mem_release, | 997 | .release = mem_release, |
1015 | }; | 998 | }; |
1016 | 999 | ||
1000 | static int auxv_open(struct inode *inode, struct file *file) | ||
1001 | { | ||
1002 | return __mem_open(inode, file, PTRACE_MODE_READ_FSCREDS); | ||
1003 | } | ||
1004 | |||
1005 | static ssize_t auxv_read(struct file *file, char __user *buf, | ||
1006 | size_t count, loff_t *ppos) | ||
1007 | { | ||
1008 | struct mm_struct *mm = file->private_data; | ||
1009 | unsigned int nwords = 0; | ||
1010 | do { | ||
1011 | nwords += 2; | ||
1012 | } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */ | ||
1013 | return simple_read_from_buffer(buf, count, ppos, mm->saved_auxv, | ||
1014 | nwords * sizeof(mm->saved_auxv[0])); | ||
1015 | } | ||
1016 | |||
1017 | static const struct file_operations proc_auxv_operations = { | ||
1018 | .open = auxv_open, | ||
1019 | .read = auxv_read, | ||
1020 | .llseek = generic_file_llseek, | ||
1021 | .release = mem_release, | ||
1022 | }; | ||
1023 | |||
1017 | static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count, | 1024 | static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count, |
1018 | loff_t *ppos) | 1025 | loff_t *ppos) |
1019 | { | 1026 | { |
@@ -1556,18 +1563,13 @@ static const struct file_operations proc_pid_set_comm_operations = { | |||
1556 | static int proc_exe_link(struct dentry *dentry, struct path *exe_path) | 1563 | static int proc_exe_link(struct dentry *dentry, struct path *exe_path) |
1557 | { | 1564 | { |
1558 | struct task_struct *task; | 1565 | struct task_struct *task; |
1559 | struct mm_struct *mm; | ||
1560 | struct file *exe_file; | 1566 | struct file *exe_file; |
1561 | 1567 | ||
1562 | task = get_proc_task(d_inode(dentry)); | 1568 | task = get_proc_task(d_inode(dentry)); |
1563 | if (!task) | 1569 | if (!task) |
1564 | return -ENOENT; | 1570 | return -ENOENT; |
1565 | mm = get_task_mm(task); | 1571 | exe_file = get_task_exe_file(task); |
1566 | put_task_struct(task); | 1572 | put_task_struct(task); |
1567 | if (!mm) | ||
1568 | return -ENOENT; | ||
1569 | exe_file = get_mm_exe_file(mm); | ||
1570 | mmput(mm); | ||
1571 | if (exe_file) { | 1573 | if (exe_file) { |
1572 | *exe_path = exe_file->f_path; | 1574 | *exe_path = exe_file->f_path; |
1573 | path_get(&exe_file->f_path); | 1575 | path_get(&exe_file->f_path); |
@@ -2285,16 +2287,27 @@ static ssize_t timerslack_ns_write(struct file *file, const char __user *buf, | |||
2285 | if (!p) | 2287 | if (!p) |
2286 | return -ESRCH; | 2288 | return -ESRCH; |
2287 | 2289 | ||
2288 | if (ptrace_may_access(p, PTRACE_MODE_ATTACH_FSCREDS)) { | 2290 | if (p != current) { |
2289 | task_lock(p); | 2291 | if (!capable(CAP_SYS_NICE)) { |
2290 | if (slack_ns == 0) | 2292 | count = -EPERM; |
2291 | p->timer_slack_ns = p->default_timer_slack_ns; | 2293 | goto out; |
2292 | else | 2294 | } |
2293 | p->timer_slack_ns = slack_ns; | 2295 | |
2294 | task_unlock(p); | 2296 | err = security_task_setscheduler(p); |
2295 | } else | 2297 | if (err) { |
2296 | count = -EPERM; | 2298 | count = err; |
2299 | goto out; | ||
2300 | } | ||
2301 | } | ||
2302 | |||
2303 | task_lock(p); | ||
2304 | if (slack_ns == 0) | ||
2305 | p->timer_slack_ns = p->default_timer_slack_ns; | ||
2306 | else | ||
2307 | p->timer_slack_ns = slack_ns; | ||
2308 | task_unlock(p); | ||
2297 | 2309 | ||
2310 | out: | ||
2298 | put_task_struct(p); | 2311 | put_task_struct(p); |
2299 | 2312 | ||
2300 | return count; | 2313 | return count; |
@@ -2304,19 +2317,28 @@ static int timerslack_ns_show(struct seq_file *m, void *v) | |||
2304 | { | 2317 | { |
2305 | struct inode *inode = m->private; | 2318 | struct inode *inode = m->private; |
2306 | struct task_struct *p; | 2319 | struct task_struct *p; |
2307 | int err = 0; | 2320 | int err = 0; |
2308 | 2321 | ||
2309 | p = get_proc_task(inode); | 2322 | p = get_proc_task(inode); |
2310 | if (!p) | 2323 | if (!p) |
2311 | return -ESRCH; | 2324 | return -ESRCH; |
2312 | 2325 | ||
2313 | if (ptrace_may_access(p, PTRACE_MODE_ATTACH_FSCREDS)) { | 2326 | if (p != current) { |
2314 | task_lock(p); | ||
2315 | seq_printf(m, "%llu\n", p->timer_slack_ns); | ||
2316 | task_unlock(p); | ||
2317 | } else | ||
2318 | err = -EPERM; | ||
2319 | 2327 | ||
2328 | if (!capable(CAP_SYS_NICE)) { | ||
2329 | err = -EPERM; | ||
2330 | goto out; | ||
2331 | } | ||
2332 | err = security_task_getscheduler(p); | ||
2333 | if (err) | ||
2334 | goto out; | ||
2335 | } | ||
2336 | |||
2337 | task_lock(p); | ||
2338 | seq_printf(m, "%llu\n", p->timer_slack_ns); | ||
2339 | task_unlock(p); | ||
2340 | |||
2341 | out: | ||
2320 | put_task_struct(p); | 2342 | put_task_struct(p); |
2321 | 2343 | ||
2322 | return err; | 2344 | return err; |
@@ -2827,7 +2849,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2827 | DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), | 2849 | DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), |
2828 | #endif | 2850 | #endif |
2829 | REG("environ", S_IRUSR, proc_environ_operations), | 2851 | REG("environ", S_IRUSR, proc_environ_operations), |
2830 | ONE("auxv", S_IRUSR, proc_pid_auxv), | 2852 | REG("auxv", S_IRUSR, proc_auxv_operations), |
2831 | ONE("status", S_IRUGO, proc_pid_status), | 2853 | ONE("status", S_IRUGO, proc_pid_status), |
2832 | ONE("personality", S_IRUSR, proc_pid_personality), | 2854 | ONE("personality", S_IRUSR, proc_pid_personality), |
2833 | ONE("limits", S_IRUGO, proc_pid_limits), | 2855 | ONE("limits", S_IRUGO, proc_pid_limits), |
@@ -3215,7 +3237,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3215 | DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), | 3237 | DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), |
3216 | #endif | 3238 | #endif |
3217 | REG("environ", S_IRUSR, proc_environ_operations), | 3239 | REG("environ", S_IRUSR, proc_environ_operations), |
3218 | ONE("auxv", S_IRUSR, proc_pid_auxv), | 3240 | REG("auxv", S_IRUSR, proc_auxv_operations), |
3219 | ONE("status", S_IRUGO, proc_pid_status), | 3241 | ONE("status", S_IRUGO, proc_pid_status), |
3220 | ONE("personality", S_IRUSR, proc_pid_personality), | 3242 | ONE("personality", S_IRUSR, proc_pid_personality), |
3221 | ONE("limits", S_IRUGO, proc_pid_limits), | 3243 | ONE("limits", S_IRUGO, proc_pid_limits), |