| .. | .. |
|---|
| 59 | 59 | #include <linux/capability.h> |
|---|
| 60 | 60 | #include <linux/file.h> |
|---|
| 61 | 61 | #include <linux/fdtable.h> |
|---|
| 62 | +#include <linux/generic-radix-tree.h> |
|---|
| 62 | 63 | #include <linux/string.h> |
|---|
| 63 | 64 | #include <linux/seq_file.h> |
|---|
| 64 | 65 | #include <linux/namei.h> |
|---|
| .. | .. |
|---|
| 92 | 93 | #include <linux/sched/coredump.h> |
|---|
| 93 | 94 | #include <linux/sched/debug.h> |
|---|
| 94 | 95 | #include <linux/sched/stat.h> |
|---|
| 95 | | -#include <linux/flex_array.h> |
|---|
| 96 | 96 | #include <linux/posix-timers.h> |
|---|
| 97 | +#include <linux/time_namespace.h> |
|---|
| 98 | +#include <linux/resctrl.h> |
|---|
| 97 | 99 | #include <linux/cpufreq_times.h> |
|---|
| 98 | 100 | #include <trace/events/oom.h> |
|---|
| 99 | | -#include <linux/swait.h> |
|---|
| 100 | 101 | #include "internal.h" |
|---|
| 101 | 102 | #include "fd.h" |
|---|
| 102 | 103 | |
|---|
| .. | .. |
|---|
| 142 | 143 | #define REG(NAME, MODE, fops) \ |
|---|
| 143 | 144 | NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}) |
|---|
| 144 | 145 | #define ONE(NAME, MODE, show) \ |
|---|
| 145 | | - NOD(NAME, (S_IFREG|(MODE)), \ |
|---|
| 146 | + NOD(NAME, (S_IFREG|(MODE)), \ |
|---|
| 146 | 147 | NULL, &proc_single_file_operations, \ |
|---|
| 147 | 148 | { .proc_show = show } ) |
|---|
| 149 | +#define ATTR(LSM, NAME, MODE) \ |
|---|
| 150 | + NOD(NAME, (S_IFREG|(MODE)), \ |
|---|
| 151 | + NULL, &proc_pid_attr_operations, \ |
|---|
| 152 | + { .lsm = LSM }) |
|---|
| 148 | 153 | |
|---|
| 149 | 154 | /* |
|---|
| 150 | 155 | * Count the number of hardlinks for the pid_entry table, excluding the . |
|---|
| .. | .. |
|---|
| 401 | 406 | |
|---|
| 402 | 407 | static int lock_trace(struct task_struct *task) |
|---|
| 403 | 408 | { |
|---|
| 404 | | - int err = mutex_lock_killable(&task->signal->cred_guard_mutex); |
|---|
| 409 | + int err = down_read_killable(&task->signal->exec_update_lock); |
|---|
| 405 | 410 | if (err) |
|---|
| 406 | 411 | return err; |
|---|
| 407 | 412 | if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) { |
|---|
| 408 | | - mutex_unlock(&task->signal->cred_guard_mutex); |
|---|
| 413 | + up_read(&task->signal->exec_update_lock); |
|---|
| 409 | 414 | return -EPERM; |
|---|
| 410 | 415 | } |
|---|
| 411 | 416 | return 0; |
|---|
| .. | .. |
|---|
| 413 | 418 | |
|---|
| 414 | 419 | static void unlock_trace(struct task_struct *task) |
|---|
| 415 | 420 | { |
|---|
| 416 | | - mutex_unlock(&task->signal->cred_guard_mutex); |
|---|
| 421 | + up_read(&task->signal->exec_update_lock); |
|---|
| 417 | 422 | } |
|---|
| 418 | 423 | |
|---|
| 419 | 424 | #ifdef CONFIG_STACKTRACE |
|---|
| .. | .. |
|---|
| 423 | 428 | static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, |
|---|
| 424 | 429 | struct pid *pid, struct task_struct *task) |
|---|
| 425 | 430 | { |
|---|
| 426 | | - struct stack_trace trace; |
|---|
| 427 | 431 | unsigned long *entries; |
|---|
| 428 | 432 | int err; |
|---|
| 429 | 433 | |
|---|
| .. | .. |
|---|
| 446 | 450 | if (!entries) |
|---|
| 447 | 451 | return -ENOMEM; |
|---|
| 448 | 452 | |
|---|
| 449 | | - trace.nr_entries = 0; |
|---|
| 450 | | - trace.max_entries = MAX_STACK_TRACE_DEPTH; |
|---|
| 451 | | - trace.entries = entries; |
|---|
| 452 | | - trace.skip = 0; |
|---|
| 453 | | - |
|---|
| 454 | 453 | err = lock_trace(task); |
|---|
| 455 | 454 | if (!err) { |
|---|
| 456 | | - unsigned int i; |
|---|
| 455 | + unsigned int i, nr_entries; |
|---|
| 457 | 456 | |
|---|
| 458 | | - save_stack_trace_tsk(task, &trace); |
|---|
| 457 | + nr_entries = stack_trace_save_tsk(task, entries, |
|---|
| 458 | + MAX_STACK_TRACE_DEPTH, 0); |
|---|
| 459 | 459 | |
|---|
| 460 | | - for (i = 0; i < trace.nr_entries; i++) { |
|---|
| 460 | + for (i = 0; i < nr_entries; i++) { |
|---|
| 461 | 461 | seq_printf(m, "[<0>] %pB\n", (void *)entries[i]); |
|---|
| 462 | 462 | } |
|---|
| 463 | + |
|---|
| 463 | 464 | unlock_trace(task); |
|---|
| 464 | 465 | } |
|---|
| 465 | 466 | kfree(entries); |
|---|
| .. | .. |
|---|
| 476 | 477 | struct pid *pid, struct task_struct *task) |
|---|
| 477 | 478 | { |
|---|
| 478 | 479 | if (unlikely(!sched_info_on())) |
|---|
| 479 | | - seq_printf(m, "0 0 0\n"); |
|---|
| 480 | + seq_puts(m, "0 0 0\n"); |
|---|
| 480 | 481 | else |
|---|
| 481 | 482 | seq_printf(m, "%llu %llu %lu\n", |
|---|
| 482 | 483 | (unsigned long long)task->se.sum_exec_runtime, |
|---|
| .. | .. |
|---|
| 505 | 506 | lr->count, lr->time, lr->max); |
|---|
| 506 | 507 | for (q = 0; q < LT_BACKTRACEDEPTH; q++) { |
|---|
| 507 | 508 | unsigned long bt = lr->backtrace[q]; |
|---|
| 509 | + |
|---|
| 508 | 510 | if (!bt) |
|---|
| 509 | | - break; |
|---|
| 510 | | - if (bt == ULONG_MAX) |
|---|
| 511 | 511 | break; |
|---|
| 512 | 512 | seq_printf(m, " %ps", (void *)bt); |
|---|
| 513 | 513 | } |
|---|
| .. | .. |
|---|
| 531 | 531 | |
|---|
| 532 | 532 | if (!task) |
|---|
| 533 | 533 | return -ESRCH; |
|---|
| 534 | | - clear_all_latency_tracing(task); |
|---|
| 534 | + clear_tsk_latency_tracing(task); |
|---|
| 535 | 535 | put_task_struct(task); |
|---|
| 536 | 536 | |
|---|
| 537 | 537 | return count; |
|---|
| .. | .. |
|---|
| 550 | 550 | static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns, |
|---|
| 551 | 551 | struct pid *pid, struct task_struct *task) |
|---|
| 552 | 552 | { |
|---|
| 553 | | - unsigned long totalpages = totalram_pages + total_swap_pages; |
|---|
| 553 | + unsigned long totalpages = totalram_pages() + total_swap_pages; |
|---|
| 554 | 554 | unsigned long points = 0; |
|---|
| 555 | + long badness; |
|---|
| 555 | 556 | |
|---|
| 556 | | - points = oom_badness(task, NULL, NULL, totalpages) * |
|---|
| 557 | | - 1000 / totalpages; |
|---|
| 557 | + badness = oom_badness(task, totalpages); |
|---|
| 558 | + /* |
|---|
| 559 | + * Special case OOM_SCORE_ADJ_MIN for all others scale the |
|---|
| 560 | + * badness value into [0, 2000] range which we have been |
|---|
| 561 | + * exporting for a long time so userspace might depend on it. |
|---|
| 562 | + */ |
|---|
| 563 | + if (badness != LONG_MIN) |
|---|
| 564 | + points = (1000 + badness * 1000 / (long)totalpages) * 2 / 3; |
|---|
| 565 | + |
|---|
| 558 | 566 | seq_printf(m, "%lu\n", points); |
|---|
| 559 | 567 | |
|---|
| 560 | 568 | return 0; |
|---|
| .. | .. |
|---|
| 601 | 609 | /* |
|---|
| 602 | 610 | * print the file header |
|---|
| 603 | 611 | */ |
|---|
| 604 | | - seq_printf(m, "%-25s %-20s %-20s %-10s\n", |
|---|
| 605 | | - "Limit", "Soft Limit", "Hard Limit", "Units"); |
|---|
| 612 | + seq_puts(m, "Limit " |
|---|
| 613 | + "Soft Limit " |
|---|
| 614 | + "Hard Limit " |
|---|
| 615 | + "Units \n"); |
|---|
| 606 | 616 | |
|---|
| 607 | 617 | for (i = 0; i < RLIM_NLIMITS; i++) { |
|---|
| 608 | 618 | if (rlim[i].rlim_cur == RLIM_INFINITY) |
|---|
| .. | .. |
|---|
| 630 | 640 | static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns, |
|---|
| 631 | 641 | struct pid *pid, struct task_struct *task) |
|---|
| 632 | 642 | { |
|---|
| 633 | | - long nr; |
|---|
| 634 | | - unsigned long args[6], sp, pc; |
|---|
| 643 | + struct syscall_info info; |
|---|
| 644 | + u64 *args = &info.data.args[0]; |
|---|
| 635 | 645 | int res; |
|---|
| 636 | 646 | |
|---|
| 637 | 647 | res = lock_trace(task); |
|---|
| 638 | 648 | if (res) |
|---|
| 639 | 649 | return res; |
|---|
| 640 | 650 | |
|---|
| 641 | | - if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) |
|---|
| 651 | + if (task_current_syscall(task, &info)) |
|---|
| 642 | 652 | seq_puts(m, "running\n"); |
|---|
| 643 | | - else if (nr < 0) |
|---|
| 644 | | - seq_printf(m, "%ld 0x%lx 0x%lx\n", nr, sp, pc); |
|---|
| 653 | + else if (info.data.nr < 0) |
|---|
| 654 | + seq_printf(m, "%d 0x%llx 0x%llx\n", |
|---|
| 655 | + info.data.nr, info.sp, info.data.instruction_pointer); |
|---|
| 645 | 656 | else |
|---|
| 646 | 657 | seq_printf(m, |
|---|
| 647 | | - "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", |
|---|
| 648 | | - nr, |
|---|
| 658 | + "%d 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n", |
|---|
| 659 | + info.data.nr, |
|---|
| 649 | 660 | args[0], args[1], args[2], args[3], args[4], args[5], |
|---|
| 650 | | - sp, pc); |
|---|
| 661 | + info.sp, info.data.instruction_pointer); |
|---|
| 651 | 662 | unlock_trace(task); |
|---|
| 652 | 663 | |
|---|
| 653 | 664 | return 0; |
|---|
| .. | .. |
|---|
| 696 | 707 | * May current process learn task's sched/cmdline info (for hide_pid_min=1) |
|---|
| 697 | 708 | * or euid/egid (for hide_pid_min=2)? |
|---|
| 698 | 709 | */ |
|---|
| 699 | | -static bool has_pid_permissions(struct pid_namespace *pid, |
|---|
| 710 | +static bool has_pid_permissions(struct proc_fs_info *fs_info, |
|---|
| 700 | 711 | struct task_struct *task, |
|---|
| 701 | | - int hide_pid_min) |
|---|
| 712 | + enum proc_hidepid hide_pid_min) |
|---|
| 702 | 713 | { |
|---|
| 703 | | - if (pid->hide_pid < hide_pid_min) |
|---|
| 714 | + /* |
|---|
| 715 | + * If 'hidpid' mount option is set force a ptrace check, |
|---|
| 716 | + * we indicate that we are using a filesystem syscall |
|---|
| 717 | + * by passing PTRACE_MODE_READ_FSCREDS |
|---|
| 718 | + */ |
|---|
| 719 | + if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE) |
|---|
| 720 | + return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); |
|---|
| 721 | + |
|---|
| 722 | + if (fs_info->hide_pid < hide_pid_min) |
|---|
| 704 | 723 | return true; |
|---|
| 705 | | - if (in_group_p(pid->pid_gid)) |
|---|
| 724 | + if (in_group_p(fs_info->pid_gid)) |
|---|
| 706 | 725 | return true; |
|---|
| 707 | 726 | return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); |
|---|
| 708 | 727 | } |
|---|
| .. | .. |
|---|
| 710 | 729 | |
|---|
| 711 | 730 | static int proc_pid_permission(struct inode *inode, int mask) |
|---|
| 712 | 731 | { |
|---|
| 713 | | - struct pid_namespace *pid = proc_pid_ns(inode); |
|---|
| 732 | + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); |
|---|
| 714 | 733 | struct task_struct *task; |
|---|
| 715 | 734 | bool has_perms; |
|---|
| 716 | 735 | |
|---|
| 717 | 736 | task = get_proc_task(inode); |
|---|
| 718 | 737 | if (!task) |
|---|
| 719 | 738 | return -ESRCH; |
|---|
| 720 | | - has_perms = has_pid_permissions(pid, task, HIDEPID_NO_ACCESS); |
|---|
| 739 | + has_perms = has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS); |
|---|
| 721 | 740 | put_task_struct(task); |
|---|
| 722 | 741 | |
|---|
| 723 | 742 | if (!has_perms) { |
|---|
| 724 | | - if (pid->hide_pid == HIDEPID_INVISIBLE) { |
|---|
| 743 | + if (fs_info->hide_pid == HIDEPID_INVISIBLE) { |
|---|
| 725 | 744 | /* |
|---|
| 726 | 745 | * Let's make getdents(), stat(), and open() |
|---|
| 727 | 746 | * consistent with each other. If a process |
|---|
| .. | .. |
|---|
| 745 | 764 | static int proc_single_show(struct seq_file *m, void *v) |
|---|
| 746 | 765 | { |
|---|
| 747 | 766 | struct inode *inode = m->private; |
|---|
| 748 | | - struct pid_namespace *ns = proc_pid_ns(inode); |
|---|
| 767 | + struct pid_namespace *ns = proc_pid_ns(inode->i_sb); |
|---|
| 749 | 768 | struct pid *pid = proc_pid(inode); |
|---|
| 750 | 769 | struct task_struct *task; |
|---|
| 751 | 770 | int ret; |
|---|
| .. | .. |
|---|
| 1031 | 1050 | oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) / |
|---|
| 1032 | 1051 | OOM_SCORE_ADJ_MAX; |
|---|
| 1033 | 1052 | put_task_struct(task); |
|---|
| 1053 | + if (oom_adj > OOM_ADJUST_MAX) |
|---|
| 1054 | + oom_adj = OOM_ADJUST_MAX; |
|---|
| 1034 | 1055 | len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj); |
|---|
| 1035 | 1056 | return simple_read_from_buffer(buf, count, ppos, buffer, len); |
|---|
| 1036 | 1057 | } |
|---|
| .. | .. |
|---|
| 1223 | 1244 | .llseek = default_llseek, |
|---|
| 1224 | 1245 | }; |
|---|
| 1225 | 1246 | |
|---|
| 1226 | | -#ifdef CONFIG_AUDITSYSCALL |
|---|
| 1247 | +#ifdef CONFIG_AUDIT |
|---|
| 1227 | 1248 | #define TMPBUFLEN 11 |
|---|
| 1228 | 1249 | static ssize_t proc_loginuid_read(struct file * file, char __user * buf, |
|---|
| 1229 | 1250 | size_t count, loff_t *ppos) |
|---|
| .. | .. |
|---|
| 1249 | 1270 | uid_t loginuid; |
|---|
| 1250 | 1271 | kuid_t kloginuid; |
|---|
| 1251 | 1272 | int rv; |
|---|
| 1273 | + |
|---|
| 1274 | + /* Don't let kthreads write their own loginuid */ |
|---|
| 1275 | + if (current->flags & PF_KTHREAD) |
|---|
| 1276 | + return -EPERM; |
|---|
| 1252 | 1277 | |
|---|
| 1253 | 1278 | rcu_read_lock(); |
|---|
| 1254 | 1279 | if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { |
|---|
| .. | .. |
|---|
| 1413 | 1438 | static int sched_show(struct seq_file *m, void *v) |
|---|
| 1414 | 1439 | { |
|---|
| 1415 | 1440 | struct inode *inode = m->private; |
|---|
| 1416 | | - struct pid_namespace *ns = proc_pid_ns(inode); |
|---|
| 1441 | + struct pid_namespace *ns = proc_pid_ns(inode->i_sb); |
|---|
| 1417 | 1442 | struct task_struct *p; |
|---|
| 1418 | 1443 | |
|---|
| 1419 | 1444 | p = get_proc_task(inode); |
|---|
| .. | .. |
|---|
| 1533 | 1558 | |
|---|
| 1534 | 1559 | #endif /* CONFIG_SCHED_AUTOGROUP */ |
|---|
| 1535 | 1560 | |
|---|
| 1561 | +#ifdef CONFIG_TIME_NS |
|---|
| 1562 | +static int timens_offsets_show(struct seq_file *m, void *v) |
|---|
| 1563 | +{ |
|---|
| 1564 | + struct task_struct *p; |
|---|
| 1565 | + |
|---|
| 1566 | + p = get_proc_task(file_inode(m->file)); |
|---|
| 1567 | + if (!p) |
|---|
| 1568 | + return -ESRCH; |
|---|
| 1569 | + proc_timens_show_offsets(p, m); |
|---|
| 1570 | + |
|---|
| 1571 | + put_task_struct(p); |
|---|
| 1572 | + |
|---|
| 1573 | + return 0; |
|---|
| 1574 | +} |
|---|
| 1575 | + |
|---|
| 1576 | +static ssize_t timens_offsets_write(struct file *file, const char __user *buf, |
|---|
| 1577 | + size_t count, loff_t *ppos) |
|---|
| 1578 | +{ |
|---|
| 1579 | + struct inode *inode = file_inode(file); |
|---|
| 1580 | + struct proc_timens_offset offsets[2]; |
|---|
| 1581 | + char *kbuf = NULL, *pos, *next_line; |
|---|
| 1582 | + struct task_struct *p; |
|---|
| 1583 | + int ret, noffsets; |
|---|
| 1584 | + |
|---|
| 1585 | + /* Only allow < page size writes at the beginning of the file */ |
|---|
| 1586 | + if ((*ppos != 0) || (count >= PAGE_SIZE)) |
|---|
| 1587 | + return -EINVAL; |
|---|
| 1588 | + |
|---|
| 1589 | + /* Slurp in the user data */ |
|---|
| 1590 | + kbuf = memdup_user_nul(buf, count); |
|---|
| 1591 | + if (IS_ERR(kbuf)) |
|---|
| 1592 | + return PTR_ERR(kbuf); |
|---|
| 1593 | + |
|---|
| 1594 | + /* Parse the user data */ |
|---|
| 1595 | + ret = -EINVAL; |
|---|
| 1596 | + noffsets = 0; |
|---|
| 1597 | + for (pos = kbuf; pos; pos = next_line) { |
|---|
| 1598 | + struct proc_timens_offset *off = &offsets[noffsets]; |
|---|
| 1599 | + char clock[10]; |
|---|
| 1600 | + int err; |
|---|
| 1601 | + |
|---|
| 1602 | + /* Find the end of line and ensure we don't look past it */ |
|---|
| 1603 | + next_line = strchr(pos, '\n'); |
|---|
| 1604 | + if (next_line) { |
|---|
| 1605 | + *next_line = '\0'; |
|---|
| 1606 | + next_line++; |
|---|
| 1607 | + if (*next_line == '\0') |
|---|
| 1608 | + next_line = NULL; |
|---|
| 1609 | + } |
|---|
| 1610 | + |
|---|
| 1611 | + err = sscanf(pos, "%9s %lld %lu", clock, |
|---|
| 1612 | + &off->val.tv_sec, &off->val.tv_nsec); |
|---|
| 1613 | + if (err != 3 || off->val.tv_nsec >= NSEC_PER_SEC) |
|---|
| 1614 | + goto out; |
|---|
| 1615 | + |
|---|
| 1616 | + clock[sizeof(clock) - 1] = 0; |
|---|
| 1617 | + if (strcmp(clock, "monotonic") == 0 || |
|---|
| 1618 | + strcmp(clock, __stringify(CLOCK_MONOTONIC)) == 0) |
|---|
| 1619 | + off->clockid = CLOCK_MONOTONIC; |
|---|
| 1620 | + else if (strcmp(clock, "boottime") == 0 || |
|---|
| 1621 | + strcmp(clock, __stringify(CLOCK_BOOTTIME)) == 0) |
|---|
| 1622 | + off->clockid = CLOCK_BOOTTIME; |
|---|
| 1623 | + else |
|---|
| 1624 | + goto out; |
|---|
| 1625 | + |
|---|
| 1626 | + noffsets++; |
|---|
| 1627 | + if (noffsets == ARRAY_SIZE(offsets)) { |
|---|
| 1628 | + if (next_line) |
|---|
| 1629 | + count = next_line - kbuf; |
|---|
| 1630 | + break; |
|---|
| 1631 | + } |
|---|
| 1632 | + } |
|---|
| 1633 | + |
|---|
| 1634 | + ret = -ESRCH; |
|---|
| 1635 | + p = get_proc_task(inode); |
|---|
| 1636 | + if (!p) |
|---|
| 1637 | + goto out; |
|---|
| 1638 | + ret = proc_timens_set_offset(file, p, offsets, noffsets); |
|---|
| 1639 | + put_task_struct(p); |
|---|
| 1640 | + if (ret) |
|---|
| 1641 | + goto out; |
|---|
| 1642 | + |
|---|
| 1643 | + ret = count; |
|---|
| 1644 | +out: |
|---|
| 1645 | + kfree(kbuf); |
|---|
| 1646 | + return ret; |
|---|
| 1647 | +} |
|---|
| 1648 | + |
|---|
| 1649 | +static int timens_offsets_open(struct inode *inode, struct file *filp) |
|---|
| 1650 | +{ |
|---|
| 1651 | + return single_open(filp, timens_offsets_show, inode); |
|---|
| 1652 | +} |
|---|
| 1653 | + |
|---|
| 1654 | +static const struct file_operations proc_timens_offsets_operations = { |
|---|
| 1655 | + .open = timens_offsets_open, |
|---|
| 1656 | + .read = seq_read, |
|---|
| 1657 | + .write = timens_offsets_write, |
|---|
| 1658 | + .llseek = seq_lseek, |
|---|
| 1659 | + .release = single_release, |
|---|
| 1660 | +}; |
|---|
| 1661 | +#endif /* CONFIG_TIME_NS */ |
|---|
| 1662 | + |
|---|
| 1536 | 1663 | static ssize_t comm_write(struct file *file, const char __user *buf, |
|---|
| 1537 | 1664 | size_t count, loff_t *offset) |
|---|
| 1538 | 1665 | { |
|---|
| .. | .. |
|---|
| 1626 | 1753 | if (error) |
|---|
| 1627 | 1754 | goto out; |
|---|
| 1628 | 1755 | |
|---|
| 1629 | | - nd_jump_link(&path); |
|---|
| 1630 | | - return NULL; |
|---|
| 1756 | + error = nd_jump_link(&path); |
|---|
| 1631 | 1757 | out: |
|---|
| 1632 | 1758 | return ERR_PTR(error); |
|---|
| 1633 | 1759 | } |
|---|
| .. | .. |
|---|
| 1743 | 1869 | *rgid = gid; |
|---|
| 1744 | 1870 | } |
|---|
| 1745 | 1871 | |
|---|
| 1872 | +void proc_pid_evict_inode(struct proc_inode *ei) |
|---|
| 1873 | +{ |
|---|
| 1874 | + struct pid *pid = ei->pid; |
|---|
| 1875 | + |
|---|
| 1876 | + if (S_ISDIR(ei->vfs_inode.i_mode)) { |
|---|
| 1877 | + spin_lock(&pid->lock); |
|---|
| 1878 | + hlist_del_init_rcu(&ei->sibling_inodes); |
|---|
| 1879 | + spin_unlock(&pid->lock); |
|---|
| 1880 | + } |
|---|
| 1881 | + |
|---|
| 1882 | + put_pid(pid); |
|---|
| 1883 | +} |
|---|
| 1884 | + |
|---|
| 1746 | 1885 | struct inode *proc_pid_make_inode(struct super_block * sb, |
|---|
| 1747 | 1886 | struct task_struct *task, umode_t mode) |
|---|
| 1748 | 1887 | { |
|---|
| 1749 | 1888 | struct inode * inode; |
|---|
| 1750 | 1889 | struct proc_inode *ei; |
|---|
| 1890 | + struct pid *pid; |
|---|
| 1751 | 1891 | |
|---|
| 1752 | 1892 | /* We need a new inode */ |
|---|
| 1753 | 1893 | |
|---|
| .. | .. |
|---|
| 1765 | 1905 | /* |
|---|
| 1766 | 1906 | * grab the reference to task. |
|---|
| 1767 | 1907 | */ |
|---|
| 1768 | | - ei->pid = get_task_pid(task, PIDTYPE_PID); |
|---|
| 1769 | | - if (!ei->pid) |
|---|
| 1908 | + pid = get_task_pid(task, PIDTYPE_PID); |
|---|
| 1909 | + if (!pid) |
|---|
| 1770 | 1910 | goto out_unlock; |
|---|
| 1911 | + |
|---|
| 1912 | + /* Let the pid remember us for quick removal */ |
|---|
| 1913 | + ei->pid = pid; |
|---|
| 1914 | + if (S_ISDIR(mode)) { |
|---|
| 1915 | + spin_lock(&pid->lock); |
|---|
| 1916 | + hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes); |
|---|
| 1917 | + spin_unlock(&pid->lock); |
|---|
| 1918 | + } |
|---|
| 1771 | 1919 | |
|---|
| 1772 | 1920 | task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); |
|---|
| 1773 | 1921 | security_task_to_inode(task, inode); |
|---|
| .. | .. |
|---|
| 1784 | 1932 | u32 request_mask, unsigned int query_flags) |
|---|
| 1785 | 1933 | { |
|---|
| 1786 | 1934 | struct inode *inode = d_inode(path->dentry); |
|---|
| 1787 | | - struct pid_namespace *pid = proc_pid_ns(inode); |
|---|
| 1935 | + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); |
|---|
| 1788 | 1936 | struct task_struct *task; |
|---|
| 1789 | 1937 | |
|---|
| 1790 | 1938 | generic_fillattr(inode, stat); |
|---|
| .. | .. |
|---|
| 1794 | 1942 | rcu_read_lock(); |
|---|
| 1795 | 1943 | task = pid_task(proc_pid(inode), PIDTYPE_PID); |
|---|
| 1796 | 1944 | if (task) { |
|---|
| 1797 | | - if (!has_pid_permissions(pid, task, HIDEPID_INVISIBLE)) { |
|---|
| 1945 | + if (!has_pid_permissions(fs_info, task, HIDEPID_INVISIBLE)) { |
|---|
| 1798 | 1946 | rcu_read_unlock(); |
|---|
| 1799 | 1947 | /* |
|---|
| 1800 | 1948 | * This doesn't prevent learning whether PID exists, |
|---|
| .. | .. |
|---|
| 1891 | 2039 | |
|---|
| 1892 | 2040 | child = d_hash_and_lookup(dir, &qname); |
|---|
| 1893 | 2041 | if (!child) { |
|---|
| 1894 | | - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); |
|---|
| 2042 | + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); |
|---|
| 1895 | 2043 | child = d_alloc_parallel(dir, &qname, &wq); |
|---|
| 1896 | 2044 | if (IS_ERR(child)) |
|---|
| 1897 | 2045 | goto end_instantiate; |
|---|
| .. | .. |
|---|
| 1979 | 2127 | goto out; |
|---|
| 1980 | 2128 | |
|---|
| 1981 | 2129 | if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) { |
|---|
| 1982 | | - status = down_read_killable(&mm->mmap_sem); |
|---|
| 2130 | + status = mmap_read_lock_killable(mm); |
|---|
| 1983 | 2131 | if (!status) { |
|---|
| 1984 | 2132 | exact_vma_exists = !!find_exact_vma(mm, vm_start, |
|---|
| 1985 | 2133 | vm_end); |
|---|
| 1986 | | - up_read(&mm->mmap_sem); |
|---|
| 2134 | + mmap_read_unlock(mm); |
|---|
| 1987 | 2135 | } |
|---|
| 1988 | 2136 | } |
|---|
| 1989 | 2137 | |
|---|
| .. | .. |
|---|
| 2030 | 2178 | if (rc) |
|---|
| 2031 | 2179 | goto out_mmput; |
|---|
| 2032 | 2180 | |
|---|
| 2033 | | - rc = down_read_killable(&mm->mmap_sem); |
|---|
| 2181 | + rc = mmap_read_lock_killable(mm); |
|---|
| 2034 | 2182 | if (rc) |
|---|
| 2035 | 2183 | goto out_mmput; |
|---|
| 2036 | 2184 | |
|---|
| .. | .. |
|---|
| 2041 | 2189 | path_get(path); |
|---|
| 2042 | 2190 | rc = 0; |
|---|
| 2043 | 2191 | } |
|---|
| 2044 | | - up_read(&mm->mmap_sem); |
|---|
| 2192 | + mmap_read_unlock(mm); |
|---|
| 2045 | 2193 | |
|---|
| 2046 | 2194 | out_mmput: |
|---|
| 2047 | 2195 | mmput(mm); |
|---|
| .. | .. |
|---|
| 2056 | 2204 | }; |
|---|
| 2057 | 2205 | |
|---|
| 2058 | 2206 | /* |
|---|
| 2059 | | - * Only allow CAP_SYS_ADMIN to follow the links, due to concerns about how the |
|---|
| 2060 | | - * symlinks may be used to bypass permissions on ancestor directories in the |
|---|
| 2061 | | - * path to the file in question. |
|---|
| 2207 | + * Only allow CAP_SYS_ADMIN and CAP_CHECKPOINT_RESTORE to follow the links, due |
|---|
| 2208 | + * to concerns about how the symlinks may be used to bypass permissions on |
|---|
| 2209 | + * ancestor directories in the path to the file in question. |
|---|
| 2062 | 2210 | */ |
|---|
| 2063 | 2211 | static const char * |
|---|
| 2064 | 2212 | proc_map_files_get_link(struct dentry *dentry, |
|---|
| 2065 | 2213 | struct inode *inode, |
|---|
| 2066 | 2214 | struct delayed_call *done) |
|---|
| 2067 | 2215 | { |
|---|
| 2068 | | - if (!capable(CAP_SYS_ADMIN)) |
|---|
| 2216 | + if (!checkpoint_restore_ns_capable(&init_user_ns)) |
|---|
| 2069 | 2217 | return ERR_PTR(-EPERM); |
|---|
| 2070 | 2218 | |
|---|
| 2071 | 2219 | return proc_pid_get_link(dentry, inode, done); |
|---|
| .. | .. |
|---|
| 2131 | 2279 | goto out_put_task; |
|---|
| 2132 | 2280 | |
|---|
| 2133 | 2281 | result = ERR_PTR(-EINTR); |
|---|
| 2134 | | - if (down_read_killable(&mm->mmap_sem)) |
|---|
| 2282 | + if (mmap_read_lock_killable(mm)) |
|---|
| 2135 | 2283 | goto out_put_mm; |
|---|
| 2136 | 2284 | |
|---|
| 2137 | 2285 | result = ERR_PTR(-ENOENT); |
|---|
| .. | .. |
|---|
| 2144 | 2292 | (void *)(unsigned long)vma->vm_file->f_mode); |
|---|
| 2145 | 2293 | |
|---|
| 2146 | 2294 | out_no_vma: |
|---|
| 2147 | | - up_read(&mm->mmap_sem); |
|---|
| 2295 | + mmap_read_unlock(mm); |
|---|
| 2148 | 2296 | out_put_mm: |
|---|
| 2149 | 2297 | mmput(mm); |
|---|
| 2150 | 2298 | out_put_task: |
|---|
| .. | .. |
|---|
| 2166 | 2314 | struct task_struct *task; |
|---|
| 2167 | 2315 | struct mm_struct *mm; |
|---|
| 2168 | 2316 | unsigned long nr_files, pos, i; |
|---|
| 2169 | | - struct flex_array *fa = NULL; |
|---|
| 2170 | | - struct map_files_info info; |
|---|
| 2317 | + GENRADIX(struct map_files_info) fa; |
|---|
| 2171 | 2318 | struct map_files_info *p; |
|---|
| 2172 | 2319 | int ret; |
|---|
| 2320 | + |
|---|
| 2321 | + genradix_init(&fa); |
|---|
| 2173 | 2322 | |
|---|
| 2174 | 2323 | ret = -ENOENT; |
|---|
| 2175 | 2324 | task = get_proc_task(file_inode(file)); |
|---|
| .. | .. |
|---|
| 2188 | 2337 | if (!mm) |
|---|
| 2189 | 2338 | goto out_put_task; |
|---|
| 2190 | 2339 | |
|---|
| 2191 | | - ret = down_read_killable(&mm->mmap_sem); |
|---|
| 2340 | + ret = mmap_read_lock_killable(mm); |
|---|
| 2192 | 2341 | if (ret) { |
|---|
| 2193 | 2342 | mmput(mm); |
|---|
| 2194 | 2343 | goto out_put_task; |
|---|
| .. | .. |
|---|
| 2199 | 2348 | /* |
|---|
| 2200 | 2349 | * We need two passes here: |
|---|
| 2201 | 2350 | * |
|---|
| 2202 | | - * 1) Collect vmas of mapped files with mmap_sem taken |
|---|
| 2203 | | - * 2) Release mmap_sem and instantiate entries |
|---|
| 2351 | + * 1) Collect vmas of mapped files with mmap_lock taken |
|---|
| 2352 | + * 2) Release mmap_lock and instantiate entries |
|---|
| 2204 | 2353 | * |
|---|
| 2205 | 2354 | * otherwise we get lockdep complained, since filldir() |
|---|
| 2206 | | - * routine might require mmap_sem taken in might_fault(). |
|---|
| 2355 | + * routine might require mmap_lock taken in might_fault(). |
|---|
| 2207 | 2356 | */ |
|---|
| 2208 | 2357 | |
|---|
| 2209 | 2358 | for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) { |
|---|
| 2210 | | - if (vma->vm_file && ++pos > ctx->pos) |
|---|
| 2211 | | - nr_files++; |
|---|
| 2212 | | - } |
|---|
| 2359 | + if (!vma->vm_file) |
|---|
| 2360 | + continue; |
|---|
| 2361 | + if (++pos <= ctx->pos) |
|---|
| 2362 | + continue; |
|---|
| 2213 | 2363 | |
|---|
| 2214 | | - if (nr_files) { |
|---|
| 2215 | | - fa = flex_array_alloc(sizeof(info), nr_files, |
|---|
| 2216 | | - GFP_KERNEL); |
|---|
| 2217 | | - if (!fa || flex_array_prealloc(fa, 0, nr_files, |
|---|
| 2218 | | - GFP_KERNEL)) { |
|---|
| 2364 | + p = genradix_ptr_alloc(&fa, nr_files++, GFP_KERNEL); |
|---|
| 2365 | + if (!p) { |
|---|
| 2219 | 2366 | ret = -ENOMEM; |
|---|
| 2220 | | - if (fa) |
|---|
| 2221 | | - flex_array_free(fa); |
|---|
| 2222 | | - up_read(&mm->mmap_sem); |
|---|
| 2367 | + mmap_read_unlock(mm); |
|---|
| 2223 | 2368 | mmput(mm); |
|---|
| 2224 | 2369 | goto out_put_task; |
|---|
| 2225 | 2370 | } |
|---|
| 2226 | | - for (i = 0, vma = mm->mmap, pos = 2; vma; |
|---|
| 2227 | | - vma = vma->vm_next) { |
|---|
| 2228 | | - if (!vma->vm_file) |
|---|
| 2229 | | - continue; |
|---|
| 2230 | | - if (++pos <= ctx->pos) |
|---|
| 2231 | | - continue; |
|---|
| 2232 | 2371 | |
|---|
| 2233 | | - info.start = vma->vm_start; |
|---|
| 2234 | | - info.end = vma->vm_end; |
|---|
| 2235 | | - info.mode = vma->vm_file->f_mode; |
|---|
| 2236 | | - if (flex_array_put(fa, i++, &info, GFP_KERNEL)) |
|---|
| 2237 | | - BUG(); |
|---|
| 2238 | | - } |
|---|
| 2372 | + p->start = vma->vm_start; |
|---|
| 2373 | + p->end = vma->vm_end; |
|---|
| 2374 | + p->mode = vma->vm_file->f_mode; |
|---|
| 2239 | 2375 | } |
|---|
| 2240 | | - up_read(&mm->mmap_sem); |
|---|
| 2376 | + mmap_read_unlock(mm); |
|---|
| 2241 | 2377 | mmput(mm); |
|---|
| 2242 | 2378 | |
|---|
| 2243 | 2379 | for (i = 0; i < nr_files; i++) { |
|---|
| 2244 | 2380 | char buf[4 * sizeof(long) + 2]; /* max: %lx-%lx\0 */ |
|---|
| 2245 | 2381 | unsigned int len; |
|---|
| 2246 | 2382 | |
|---|
| 2247 | | - p = flex_array_get(fa, i); |
|---|
| 2383 | + p = genradix_ptr(&fa, i); |
|---|
| 2248 | 2384 | len = snprintf(buf, sizeof(buf), "%lx-%lx", p->start, p->end); |
|---|
| 2249 | 2385 | if (!proc_fill_cache(file, ctx, |
|---|
| 2250 | 2386 | buf, len, |
|---|
| .. | .. |
|---|
| 2254 | 2390 | break; |
|---|
| 2255 | 2391 | ctx->pos++; |
|---|
| 2256 | 2392 | } |
|---|
| 2257 | | - if (fa) |
|---|
| 2258 | | - flex_array_free(fa); |
|---|
| 2259 | 2393 | |
|---|
| 2260 | 2394 | out_put_task: |
|---|
| 2261 | 2395 | put_task_struct(task); |
|---|
| 2262 | 2396 | out: |
|---|
| 2397 | + genradix_free(&fa); |
|---|
| 2263 | 2398 | return ret; |
|---|
| 2264 | 2399 | } |
|---|
| 2265 | 2400 | |
|---|
| .. | .. |
|---|
| 2358 | 2493 | return -ENOMEM; |
|---|
| 2359 | 2494 | |
|---|
| 2360 | 2495 | tp->pid = proc_pid(inode); |
|---|
| 2361 | | - tp->ns = proc_pid_ns(inode); |
|---|
| 2496 | + tp->ns = proc_pid_ns(inode->i_sb); |
|---|
| 2362 | 2497 | return 0; |
|---|
| 2363 | 2498 | } |
|---|
| 2364 | 2499 | |
|---|
| .. | .. |
|---|
| 2387 | 2522 | return -ESRCH; |
|---|
| 2388 | 2523 | |
|---|
| 2389 | 2524 | if (p != current) { |
|---|
| 2390 | | - if (!capable(CAP_SYS_NICE)) { |
|---|
| 2525 | + rcu_read_lock(); |
|---|
| 2526 | + if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) { |
|---|
| 2527 | + rcu_read_unlock(); |
|---|
| 2391 | 2528 | count = -EPERM; |
|---|
| 2392 | 2529 | goto out; |
|---|
| 2393 | 2530 | } |
|---|
| 2531 | + rcu_read_unlock(); |
|---|
| 2394 | 2532 | |
|---|
| 2395 | 2533 | err = security_task_setscheduler(p); |
|---|
| 2396 | 2534 | if (err) { |
|---|
| .. | .. |
|---|
| 2423 | 2561 | return -ESRCH; |
|---|
| 2424 | 2562 | |
|---|
| 2425 | 2563 | if (p != current) { |
|---|
| 2426 | | - |
|---|
| 2427 | | - if (!capable(CAP_SYS_NICE)) { |
|---|
| 2564 | + rcu_read_lock(); |
|---|
| 2565 | + if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) { |
|---|
| 2566 | + rcu_read_unlock(); |
|---|
| 2428 | 2567 | err = -EPERM; |
|---|
| 2429 | 2568 | goto out; |
|---|
| 2430 | 2569 | } |
|---|
| 2570 | + rcu_read_unlock(); |
|---|
| 2571 | + |
|---|
| 2431 | 2572 | err = security_task_getscheduler(p); |
|---|
| 2432 | 2573 | if (err) |
|---|
| 2433 | 2574 | goto out; |
|---|
| .. | .. |
|---|
| 2482 | 2623 | |
|---|
| 2483 | 2624 | static struct dentry *proc_pident_lookup(struct inode *dir, |
|---|
| 2484 | 2625 | struct dentry *dentry, |
|---|
| 2485 | | - const struct pid_entry *ents, |
|---|
| 2486 | | - unsigned int nents) |
|---|
| 2626 | + const struct pid_entry *p, |
|---|
| 2627 | + const struct pid_entry *end) |
|---|
| 2487 | 2628 | { |
|---|
| 2488 | 2629 | struct task_struct *task = get_proc_task(dir); |
|---|
| 2489 | | - const struct pid_entry *p, *last; |
|---|
| 2490 | 2630 | struct dentry *res = ERR_PTR(-ENOENT); |
|---|
| 2491 | 2631 | |
|---|
| 2492 | 2632 | if (!task) |
|---|
| .. | .. |
|---|
| 2496 | 2636 | * Yes, it does not scale. And it should not. Don't add |
|---|
| 2497 | 2637 | * new entries into /proc/<tgid>/ without very good reasons. |
|---|
| 2498 | 2638 | */ |
|---|
| 2499 | | - last = &ents[nents]; |
|---|
| 2500 | | - for (p = ents; p < last; p++) { |
|---|
| 2639 | + for (; p < end; p++) { |
|---|
| 2501 | 2640 | if (p->len != dentry->d_name.len) |
|---|
| 2502 | 2641 | continue; |
|---|
| 2503 | 2642 | if (!memcmp(dentry->d_name.name, p->name, p->len)) { |
|---|
| .. | .. |
|---|
| 2555 | 2694 | if (!task) |
|---|
| 2556 | 2695 | return -ESRCH; |
|---|
| 2557 | 2696 | |
|---|
| 2558 | | - length = security_getprocattr(task, |
|---|
| 2697 | + length = security_getprocattr(task, PROC_I(inode)->op.lsm, |
|---|
| 2559 | 2698 | (char*)file->f_path.dentry->d_name.name, |
|---|
| 2560 | 2699 | &p); |
|---|
| 2561 | 2700 | put_task_struct(task); |
|---|
| .. | .. |
|---|
| 2613 | 2752 | if (rv < 0) |
|---|
| 2614 | 2753 | goto out_free; |
|---|
| 2615 | 2754 | |
|---|
| 2616 | | - rv = security_setprocattr(file->f_path.dentry->d_name.name, page, count); |
|---|
| 2755 | + rv = security_setprocattr(PROC_I(inode)->op.lsm, |
|---|
| 2756 | + file->f_path.dentry->d_name.name, page, |
|---|
| 2757 | + count); |
|---|
| 2617 | 2758 | mutex_unlock(¤t->signal->cred_guard_mutex); |
|---|
| 2618 | 2759 | out_free: |
|---|
| 2619 | 2760 | kfree(page); |
|---|
| .. | .. |
|---|
| 2629 | 2770 | .release = mem_release, |
|---|
| 2630 | 2771 | }; |
|---|
| 2631 | 2772 | |
|---|
| 2773 | +#define LSM_DIR_OPS(LSM) \ |
|---|
| 2774 | +static int proc_##LSM##_attr_dir_iterate(struct file *filp, \ |
|---|
| 2775 | + struct dir_context *ctx) \ |
|---|
| 2776 | +{ \ |
|---|
| 2777 | + return proc_pident_readdir(filp, ctx, \ |
|---|
| 2778 | + LSM##_attr_dir_stuff, \ |
|---|
| 2779 | + ARRAY_SIZE(LSM##_attr_dir_stuff)); \ |
|---|
| 2780 | +} \ |
|---|
| 2781 | +\ |
|---|
| 2782 | +static const struct file_operations proc_##LSM##_attr_dir_ops = { \ |
|---|
| 2783 | + .read = generic_read_dir, \ |
|---|
| 2784 | + .iterate = proc_##LSM##_attr_dir_iterate, \ |
|---|
| 2785 | + .llseek = default_llseek, \ |
|---|
| 2786 | +}; \ |
|---|
| 2787 | +\ |
|---|
| 2788 | +static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \ |
|---|
| 2789 | + struct dentry *dentry, unsigned int flags) \ |
|---|
| 2790 | +{ \ |
|---|
| 2791 | + return proc_pident_lookup(dir, dentry, \ |
|---|
| 2792 | + LSM##_attr_dir_stuff, \ |
|---|
| 2793 | + LSM##_attr_dir_stuff + ARRAY_SIZE(LSM##_attr_dir_stuff)); \ |
|---|
| 2794 | +} \ |
|---|
| 2795 | +\ |
|---|
| 2796 | +static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \ |
|---|
| 2797 | + .lookup = proc_##LSM##_attr_dir_lookup, \ |
|---|
| 2798 | + .getattr = pid_getattr, \ |
|---|
| 2799 | + .setattr = proc_setattr, \ |
|---|
| 2800 | +} |
|---|
| 2801 | + |
|---|
| 2802 | +#ifdef CONFIG_SECURITY_SMACK |
|---|
| 2803 | +static const struct pid_entry smack_attr_dir_stuff[] = { |
|---|
| 2804 | + ATTR("smack", "current", 0666), |
|---|
| 2805 | +}; |
|---|
| 2806 | +LSM_DIR_OPS(smack); |
|---|
| 2807 | +#endif |
|---|
| 2808 | + |
|---|
| 2809 | +#ifdef CONFIG_SECURITY_APPARMOR |
|---|
| 2810 | +static const struct pid_entry apparmor_attr_dir_stuff[] = { |
|---|
| 2811 | + ATTR("apparmor", "current", 0666), |
|---|
| 2812 | + ATTR("apparmor", "prev", 0444), |
|---|
| 2813 | + ATTR("apparmor", "exec", 0666), |
|---|
| 2814 | +}; |
|---|
| 2815 | +LSM_DIR_OPS(apparmor); |
|---|
| 2816 | +#endif |
|---|
| 2817 | + |
|---|
| 2632 | 2818 | static const struct pid_entry attr_dir_stuff[] = { |
|---|
| 2633 | | - REG("current", S_IRUGO|S_IWUGO, proc_pid_attr_operations), |
|---|
| 2634 | | - REG("prev", S_IRUGO, proc_pid_attr_operations), |
|---|
| 2635 | | - REG("exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations), |
|---|
| 2636 | | - REG("fscreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), |
|---|
| 2637 | | - REG("keycreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), |
|---|
| 2638 | | - REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), |
|---|
| 2819 | + ATTR(NULL, "current", 0666), |
|---|
| 2820 | + ATTR(NULL, "prev", 0444), |
|---|
| 2821 | + ATTR(NULL, "exec", 0666), |
|---|
| 2822 | + ATTR(NULL, "fscreate", 0666), |
|---|
| 2823 | + ATTR(NULL, "keycreate", 0666), |
|---|
| 2824 | + ATTR(NULL, "sockcreate", 0666), |
|---|
| 2825 | +#ifdef CONFIG_SECURITY_SMACK |
|---|
| 2826 | + DIR("smack", 0555, |
|---|
| 2827 | + proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops), |
|---|
| 2828 | +#endif |
|---|
| 2829 | +#ifdef CONFIG_SECURITY_APPARMOR |
|---|
| 2830 | + DIR("apparmor", 0555, |
|---|
| 2831 | + proc_apparmor_attr_dir_inode_ops, proc_apparmor_attr_dir_ops), |
|---|
| 2832 | +#endif |
|---|
| 2639 | 2833 | }; |
|---|
| 2640 | 2834 | |
|---|
| 2641 | 2835 | static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) |
|---|
| .. | .. |
|---|
| 2654 | 2848 | struct dentry *dentry, unsigned int flags) |
|---|
| 2655 | 2849 | { |
|---|
| 2656 | 2850 | return proc_pident_lookup(dir, dentry, |
|---|
| 2657 | | - attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff)); |
|---|
| 2851 | + attr_dir_stuff, |
|---|
| 2852 | + attr_dir_stuff + ARRAY_SIZE(attr_dir_stuff)); |
|---|
| 2658 | 2853 | } |
|---|
| 2659 | 2854 | |
|---|
| 2660 | 2855 | static const struct inode_operations proc_attr_dir_inode_operations = { |
|---|
| .. | .. |
|---|
| 2749 | 2944 | unsigned long flags; |
|---|
| 2750 | 2945 | int result; |
|---|
| 2751 | 2946 | |
|---|
| 2752 | | - result = mutex_lock_killable(&task->signal->cred_guard_mutex); |
|---|
| 2947 | + result = down_read_killable(&task->signal->exec_update_lock); |
|---|
| 2753 | 2948 | if (result) |
|---|
| 2754 | 2949 | return result; |
|---|
| 2755 | 2950 | |
|---|
| .. | .. |
|---|
| 2785 | 2980 | result = 0; |
|---|
| 2786 | 2981 | |
|---|
| 2787 | 2982 | out_unlock: |
|---|
| 2788 | | - mutex_unlock(&task->signal->cred_guard_mutex); |
|---|
| 2983 | + up_read(&task->signal->exec_update_lock); |
|---|
| 2789 | 2984 | return result; |
|---|
| 2790 | 2985 | } |
|---|
| 2791 | 2986 | |
|---|
| .. | .. |
|---|
| 2954 | 3149 | } |
|---|
| 2955 | 3150 | #endif /* CONFIG_LIVEPATCH */ |
|---|
| 2956 | 3151 | |
|---|
| 3152 | +#ifdef CONFIG_STACKLEAK_METRICS |
|---|
| 3153 | +static int proc_stack_depth(struct seq_file *m, struct pid_namespace *ns, |
|---|
| 3154 | + struct pid *pid, struct task_struct *task) |
|---|
| 3155 | +{ |
|---|
| 3156 | + unsigned long prev_depth = THREAD_SIZE - |
|---|
| 3157 | + (task->prev_lowest_stack & (THREAD_SIZE - 1)); |
|---|
| 3158 | + unsigned long depth = THREAD_SIZE - |
|---|
| 3159 | + (task->lowest_stack & (THREAD_SIZE - 1)); |
|---|
| 3160 | + |
|---|
| 3161 | + seq_printf(m, "previous stack depth: %lu\nstack depth: %lu\n", |
|---|
| 3162 | + prev_depth, depth); |
|---|
| 3163 | + return 0; |
|---|
| 3164 | +} |
|---|
| 3165 | +#endif /* CONFIG_STACKLEAK_METRICS */ |
|---|
| 3166 | + |
|---|
| 2957 | 3167 | /* |
|---|
| 2958 | 3168 | * Thread groups |
|---|
| 2959 | 3169 | */ |
|---|
| .. | .. |
|---|
| 2964 | 3174 | DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), |
|---|
| 2965 | 3175 | DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), |
|---|
| 2966 | 3176 | DIR("map_files", S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations), |
|---|
| 2967 | | - DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), |
|---|
| 3177 | + DIR("fdinfo", S_IRUGO|S_IXUGO, proc_fdinfo_inode_operations, proc_fdinfo_operations), |
|---|
| 2968 | 3178 | DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), |
|---|
| 2969 | 3179 | #ifdef CONFIG_NET |
|---|
| 2970 | 3180 | DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), |
|---|
| .. | .. |
|---|
| 2979 | 3189 | #endif |
|---|
| 2980 | 3190 | #ifdef CONFIG_SCHED_AUTOGROUP |
|---|
| 2981 | 3191 | REG("autogroup", S_IRUGO|S_IWUSR, proc_pid_sched_autogroup_operations), |
|---|
| 3192 | +#endif |
|---|
| 3193 | +#ifdef CONFIG_TIME_NS |
|---|
| 3194 | + REG("timens_offsets", S_IRUGO|S_IWUSR, proc_timens_offsets_operations), |
|---|
| 2982 | 3195 | #endif |
|---|
| 2983 | 3196 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
|---|
| 2984 | 3197 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
|---|
| .. | .. |
|---|
| 3025 | 3238 | #ifdef CONFIG_CGROUPS |
|---|
| 3026 | 3239 | ONE("cgroup", S_IRUGO, proc_cgroup_show), |
|---|
| 3027 | 3240 | #endif |
|---|
| 3241 | +#ifdef CONFIG_PROC_CPU_RESCTRL |
|---|
| 3242 | + ONE("cpu_resctrl_groups", S_IRUGO, proc_resctrl_show), |
|---|
| 3243 | +#endif |
|---|
| 3028 | 3244 | ONE("oom_score", S_IRUGO, proc_oom_score), |
|---|
| 3029 | 3245 | REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), |
|---|
| 3030 | 3246 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), |
|---|
| 3031 | | -#ifdef CONFIG_AUDITSYSCALL |
|---|
| 3247 | +#ifdef CONFIG_AUDIT |
|---|
| 3032 | 3248 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), |
|---|
| 3033 | 3249 | REG("sessionid", S_IRUGO, proc_sessionid_operations), |
|---|
| 3034 | 3250 | #endif |
|---|
| .. | .. |
|---|
| 3058 | 3274 | #ifdef CONFIG_CPU_FREQ_TIMES |
|---|
| 3059 | 3275 | ONE("time_in_state", 0444, proc_time_in_state_show), |
|---|
| 3060 | 3276 | #endif |
|---|
| 3277 | +#ifdef CONFIG_STACKLEAK_METRICS |
|---|
| 3278 | + ONE("stack_depth", S_IRUGO, proc_stack_depth), |
|---|
| 3279 | +#endif |
|---|
| 3280 | +#ifdef CONFIG_PROC_PID_ARCH_STATUS |
|---|
| 3281 | + ONE("arch_status", S_IRUGO, proc_pid_arch_status), |
|---|
| 3282 | +#endif |
|---|
| 3061 | 3283 | }; |
|---|
| 3062 | 3284 | |
|---|
| 3063 | 3285 | static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) |
|---|
| .. | .. |
|---|
| 3074 | 3296 | |
|---|
| 3075 | 3297 | struct pid *tgid_pidfd_to_pid(const struct file *file) |
|---|
| 3076 | 3298 | { |
|---|
| 3077 | | - if (!d_is_dir(file->f_path.dentry) || |
|---|
| 3078 | | - (file->f_op != &proc_tgid_base_operations)) |
|---|
| 3299 | + if (file->f_op != &proc_tgid_base_operations) |
|---|
| 3079 | 3300 | return ERR_PTR(-EBADF); |
|---|
| 3080 | 3301 | |
|---|
| 3081 | 3302 | return proc_pid(file_inode(file)); |
|---|
| .. | .. |
|---|
| 3084 | 3305 | static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) |
|---|
| 3085 | 3306 | { |
|---|
| 3086 | 3307 | return proc_pident_lookup(dir, dentry, |
|---|
| 3087 | | - tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); |
|---|
| 3308 | + tgid_base_stuff, |
|---|
| 3309 | + tgid_base_stuff + ARRAY_SIZE(tgid_base_stuff)); |
|---|
| 3088 | 3310 | } |
|---|
| 3089 | 3311 | |
|---|
| 3090 | 3312 | static const struct inode_operations proc_tgid_base_inode_operations = { |
|---|
| .. | .. |
|---|
| 3094 | 3316 | .permission = proc_pid_permission, |
|---|
| 3095 | 3317 | }; |
|---|
| 3096 | 3318 | |
|---|
| 3097 | | -static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) |
|---|
| 3098 | | -{ |
|---|
| 3099 | | - struct dentry *dentry, *leader, *dir; |
|---|
| 3100 | | - char buf[10 + 1]; |
|---|
| 3101 | | - struct qstr name; |
|---|
| 3102 | | - |
|---|
| 3103 | | - name.name = buf; |
|---|
| 3104 | | - name.len = snprintf(buf, sizeof(buf), "%u", pid); |
|---|
| 3105 | | - /* no ->d_hash() rejects on procfs */ |
|---|
| 3106 | | - dentry = d_hash_and_lookup(mnt->mnt_root, &name); |
|---|
| 3107 | | - if (dentry) { |
|---|
| 3108 | | - d_invalidate(dentry); |
|---|
| 3109 | | - dput(dentry); |
|---|
| 3110 | | - } |
|---|
| 3111 | | - |
|---|
| 3112 | | - if (pid == tgid) |
|---|
| 3113 | | - return; |
|---|
| 3114 | | - |
|---|
| 3115 | | - name.name = buf; |
|---|
| 3116 | | - name.len = snprintf(buf, sizeof(buf), "%u", tgid); |
|---|
| 3117 | | - leader = d_hash_and_lookup(mnt->mnt_root, &name); |
|---|
| 3118 | | - if (!leader) |
|---|
| 3119 | | - goto out; |
|---|
| 3120 | | - |
|---|
| 3121 | | - name.name = "task"; |
|---|
| 3122 | | - name.len = strlen(name.name); |
|---|
| 3123 | | - dir = d_hash_and_lookup(leader, &name); |
|---|
| 3124 | | - if (!dir) |
|---|
| 3125 | | - goto out_put_leader; |
|---|
| 3126 | | - |
|---|
| 3127 | | - name.name = buf; |
|---|
| 3128 | | - name.len = snprintf(buf, sizeof(buf), "%u", pid); |
|---|
| 3129 | | - dentry = d_hash_and_lookup(dir, &name); |
|---|
| 3130 | | - if (dentry) { |
|---|
| 3131 | | - d_invalidate(dentry); |
|---|
| 3132 | | - dput(dentry); |
|---|
| 3133 | | - } |
|---|
| 3134 | | - |
|---|
| 3135 | | - dput(dir); |
|---|
| 3136 | | -out_put_leader: |
|---|
| 3137 | | - dput(leader); |
|---|
| 3138 | | -out: |
|---|
| 3139 | | - return; |
|---|
| 3140 | | -} |
|---|
| 3141 | | - |
|---|
| 3142 | 3319 | /** |
|---|
| 3143 | | - * proc_flush_task - Remove dcache entries for @task from the /proc dcache. |
|---|
| 3144 | | - * @task: task that should be flushed. |
|---|
| 3320 | + * proc_flush_pid - Remove dcache entries for @pid from the /proc dcache. |
|---|
| 3321 | + * @pid: pid that should be flushed. |
|---|
| 3145 | 3322 | * |
|---|
| 3146 | | - * When flushing dentries from proc, one needs to flush them from global |
|---|
| 3147 | | - * proc (proc_mnt) and from all the namespaces' procs this task was seen |
|---|
| 3148 | | - * in. This call is supposed to do all of this job. |
|---|
| 3149 | | - * |
|---|
| 3150 | | - * Looks in the dcache for |
|---|
| 3151 | | - * /proc/@pid |
|---|
| 3152 | | - * /proc/@tgid/task/@pid |
|---|
| 3153 | | - * if either directory is present flushes it and all of it'ts children |
|---|
| 3154 | | - * from the dcache. |
|---|
| 3323 | + * This function walks a list of inodes (that belong to any proc |
|---|
| 3324 | + * filesystem) that are attached to the pid and flushes them from |
|---|
| 3325 | + * the dentry cache. |
|---|
| 3155 | 3326 | * |
|---|
| 3156 | 3327 | * It is safe and reasonable to cache /proc entries for a task until |
|---|
| 3157 | 3328 | * that task exits. After that they just clog up the dcache with |
|---|
| 3158 | 3329 | * useless entries, possibly causing useful dcache entries to be |
|---|
| 3159 | | - * flushed instead. This routine is proved to flush those useless |
|---|
| 3160 | | - * dcache entries at process exit time. |
|---|
| 3330 | + * flushed instead. This routine is provided to flush those useless |
|---|
| 3331 | + * dcache entries when a process is reaped. |
|---|
| 3161 | 3332 | * |
|---|
| 3162 | 3333 | * NOTE: This routine is just an optimization so it does not guarantee |
|---|
| 3163 | | - * that no dcache entries will exist at process exit time it |
|---|
| 3164 | | - * just makes it very unlikely that any will persist. |
|---|
| 3334 | + * that no dcache entries will exist after a process is reaped |
|---|
| 3335 | + * it just makes it very unlikely that any will persist. |
|---|
| 3165 | 3336 | */ |
|---|
| 3166 | 3337 | |
|---|
| 3167 | | -void proc_flush_task(struct task_struct *task) |
|---|
| 3338 | +void proc_flush_pid(struct pid *pid) |
|---|
| 3168 | 3339 | { |
|---|
| 3169 | | - int i; |
|---|
| 3170 | | - struct pid *pid, *tgid; |
|---|
| 3171 | | - struct upid *upid; |
|---|
| 3172 | | - |
|---|
| 3173 | | - pid = task_pid(task); |
|---|
| 3174 | | - tgid = task_tgid(task); |
|---|
| 3175 | | - |
|---|
| 3176 | | - for (i = 0; i <= pid->level; i++) { |
|---|
| 3177 | | - upid = &pid->numbers[i]; |
|---|
| 3178 | | - proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, |
|---|
| 3179 | | - tgid->numbers[i].nr); |
|---|
| 3180 | | - } |
|---|
| 3340 | + proc_invalidate_siblings_dcache(&pid->inodes, &pid->lock); |
|---|
| 3181 | 3341 | } |
|---|
| 3182 | 3342 | |
|---|
| 3183 | 3343 | static struct dentry *proc_pid_instantiate(struct dentry * dentry, |
|---|
| .. | .. |
|---|
| 3200 | 3360 | return d_splice_alias(inode, dentry); |
|---|
| 3201 | 3361 | } |
|---|
| 3202 | 3362 | |
|---|
| 3203 | | -struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) |
|---|
| 3363 | +struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags) |
|---|
| 3204 | 3364 | { |
|---|
| 3205 | 3365 | struct task_struct *task; |
|---|
| 3206 | 3366 | unsigned tgid; |
|---|
| 3367 | + struct proc_fs_info *fs_info; |
|---|
| 3207 | 3368 | struct pid_namespace *ns; |
|---|
| 3208 | 3369 | struct dentry *result = ERR_PTR(-ENOENT); |
|---|
| 3209 | 3370 | |
|---|
| .. | .. |
|---|
| 3211 | 3372 | if (tgid == ~0U) |
|---|
| 3212 | 3373 | goto out; |
|---|
| 3213 | 3374 | |
|---|
| 3214 | | - ns = dentry->d_sb->s_fs_info; |
|---|
| 3375 | + fs_info = proc_sb_info(dentry->d_sb); |
|---|
| 3376 | + ns = fs_info->pid_ns; |
|---|
| 3215 | 3377 | rcu_read_lock(); |
|---|
| 3216 | 3378 | task = find_task_by_pid_ns(tgid, ns); |
|---|
| 3217 | 3379 | if (task) |
|---|
| .. | .. |
|---|
| 3220 | 3382 | if (!task) |
|---|
| 3221 | 3383 | goto out; |
|---|
| 3222 | 3384 | |
|---|
| 3385 | + /* Limit procfs to only ptraceable tasks */ |
|---|
| 3386 | + if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE) { |
|---|
| 3387 | + if (!has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS)) |
|---|
| 3388 | + goto out_put_task; |
|---|
| 3389 | + } |
|---|
| 3390 | + |
|---|
| 3223 | 3391 | result = proc_pid_instantiate(dentry, task, NULL); |
|---|
| 3392 | +out_put_task: |
|---|
| 3224 | 3393 | put_task_struct(task); |
|---|
| 3225 | 3394 | out: |
|---|
| 3226 | 3395 | return result; |
|---|
| .. | .. |
|---|
| 3246 | 3415 | pid = find_ge_pid(iter.tgid, ns); |
|---|
| 3247 | 3416 | if (pid) { |
|---|
| 3248 | 3417 | iter.tgid = pid_nr_ns(pid, ns); |
|---|
| 3249 | | - iter.task = pid_task(pid, PIDTYPE_PID); |
|---|
| 3250 | | - /* What we to know is if the pid we have find is the |
|---|
| 3251 | | - * pid of a thread_group_leader. Testing for task |
|---|
| 3252 | | - * being a thread_group_leader is the obvious thing |
|---|
| 3253 | | - * todo but there is a window when it fails, due to |
|---|
| 3254 | | - * the pid transfer logic in de_thread. |
|---|
| 3255 | | - * |
|---|
| 3256 | | - * So we perform the straight forward test of seeing |
|---|
| 3257 | | - * if the pid we have found is the pid of a thread |
|---|
| 3258 | | - * group leader, and don't worry if the task we have |
|---|
| 3259 | | - * found doesn't happen to be a thread group leader. |
|---|
| 3260 | | - * As we don't care in the case of readdir. |
|---|
| 3261 | | - */ |
|---|
| 3262 | | - if (!iter.task || !has_group_leader_pid(iter.task)) { |
|---|
| 3418 | + iter.task = pid_task(pid, PIDTYPE_TGID); |
|---|
| 3419 | + if (!iter.task) { |
|---|
| 3263 | 3420 | iter.tgid += 1; |
|---|
| 3264 | 3421 | goto retry; |
|---|
| 3265 | 3422 | } |
|---|
| .. | .. |
|---|
| 3275 | 3432 | int proc_pid_readdir(struct file *file, struct dir_context *ctx) |
|---|
| 3276 | 3433 | { |
|---|
| 3277 | 3434 | struct tgid_iter iter; |
|---|
| 3278 | | - struct pid_namespace *ns = proc_pid_ns(file_inode(file)); |
|---|
| 3435 | + struct proc_fs_info *fs_info = proc_sb_info(file_inode(file)->i_sb); |
|---|
| 3436 | + struct pid_namespace *ns = proc_pid_ns(file_inode(file)->i_sb); |
|---|
| 3279 | 3437 | loff_t pos = ctx->pos; |
|---|
| 3280 | 3438 | |
|---|
| 3281 | 3439 | if (pos >= PID_MAX_LIMIT + TGID_OFFSET) |
|---|
| 3282 | 3440 | return 0; |
|---|
| 3283 | 3441 | |
|---|
| 3284 | 3442 | if (pos == TGID_OFFSET - 2) { |
|---|
| 3285 | | - struct inode *inode = d_inode(ns->proc_self); |
|---|
| 3443 | + struct inode *inode = d_inode(fs_info->proc_self); |
|---|
| 3286 | 3444 | if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK)) |
|---|
| 3287 | 3445 | return 0; |
|---|
| 3288 | 3446 | ctx->pos = pos = pos + 1; |
|---|
| 3289 | 3447 | } |
|---|
| 3290 | 3448 | if (pos == TGID_OFFSET - 1) { |
|---|
| 3291 | | - struct inode *inode = d_inode(ns->proc_thread_self); |
|---|
| 3449 | + struct inode *inode = d_inode(fs_info->proc_thread_self); |
|---|
| 3292 | 3450 | if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK)) |
|---|
| 3293 | 3451 | return 0; |
|---|
| 3294 | 3452 | ctx->pos = pos = pos + 1; |
|---|
| .. | .. |
|---|
| 3302 | 3460 | unsigned int len; |
|---|
| 3303 | 3461 | |
|---|
| 3304 | 3462 | cond_resched(); |
|---|
| 3305 | | - if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE)) |
|---|
| 3463 | + if (!has_pid_permissions(fs_info, iter.task, HIDEPID_INVISIBLE)) |
|---|
| 3306 | 3464 | continue; |
|---|
| 3307 | 3465 | |
|---|
| 3308 | 3466 | len = snprintf(name, sizeof(name), "%u", iter.tgid); |
|---|
| .. | .. |
|---|
| 3360 | 3518 | */ |
|---|
| 3361 | 3519 | static const struct pid_entry tid_base_stuff[] = { |
|---|
| 3362 | 3520 | DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), |
|---|
| 3363 | | - DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), |
|---|
| 3521 | + DIR("fdinfo", S_IRUGO|S_IXUGO, proc_fdinfo_inode_operations, proc_fdinfo_operations), |
|---|
| 3364 | 3522 | DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), |
|---|
| 3365 | 3523 | #ifdef CONFIG_NET |
|---|
| 3366 | 3524 | DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), |
|---|
| .. | .. |
|---|
| 3422 | 3580 | #ifdef CONFIG_CGROUPS |
|---|
| 3423 | 3581 | ONE("cgroup", S_IRUGO, proc_cgroup_show), |
|---|
| 3424 | 3582 | #endif |
|---|
| 3583 | +#ifdef CONFIG_PROC_CPU_RESCTRL |
|---|
| 3584 | + ONE("cpu_resctrl_groups", S_IRUGO, proc_resctrl_show), |
|---|
| 3585 | +#endif |
|---|
| 3425 | 3586 | ONE("oom_score", S_IRUGO, proc_oom_score), |
|---|
| 3426 | 3587 | REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), |
|---|
| 3427 | 3588 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), |
|---|
| 3428 | | -#ifdef CONFIG_AUDITSYSCALL |
|---|
| 3589 | +#ifdef CONFIG_AUDIT |
|---|
| 3429 | 3590 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), |
|---|
| 3430 | 3591 | REG("sessionid", S_IRUGO, proc_sessionid_operations), |
|---|
| 3431 | 3592 | #endif |
|---|
| .. | .. |
|---|
| 3445 | 3606 | #ifdef CONFIG_LIVEPATCH |
|---|
| 3446 | 3607 | ONE("patch_state", S_IRUSR, proc_pid_patch_state), |
|---|
| 3447 | 3608 | #endif |
|---|
| 3609 | +#ifdef CONFIG_PROC_PID_ARCH_STATUS |
|---|
| 3610 | + ONE("arch_status", S_IRUGO, proc_pid_arch_status), |
|---|
| 3611 | +#endif |
|---|
| 3448 | 3612 | #ifdef CONFIG_CPU_FREQ_TIMES |
|---|
| 3449 | 3613 | ONE("time_in_state", 0444, proc_time_in_state_show), |
|---|
| 3450 | 3614 | #endif |
|---|
| .. | .. |
|---|
| 3459 | 3623 | static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) |
|---|
| 3460 | 3624 | { |
|---|
| 3461 | 3625 | return proc_pident_lookup(dir, dentry, |
|---|
| 3462 | | - tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); |
|---|
| 3626 | + tid_base_stuff, |
|---|
| 3627 | + tid_base_stuff + ARRAY_SIZE(tid_base_stuff)); |
|---|
| 3463 | 3628 | } |
|---|
| 3464 | 3629 | |
|---|
| 3465 | 3630 | static const struct file_operations proc_tid_base_operations = { |
|---|
| .. | .. |
|---|
| 3498 | 3663 | struct task_struct *task; |
|---|
| 3499 | 3664 | struct task_struct *leader = get_proc_task(dir); |
|---|
| 3500 | 3665 | unsigned tid; |
|---|
| 3666 | + struct proc_fs_info *fs_info; |
|---|
| 3501 | 3667 | struct pid_namespace *ns; |
|---|
| 3502 | 3668 | struct dentry *result = ERR_PTR(-ENOENT); |
|---|
| 3503 | 3669 | |
|---|
| .. | .. |
|---|
| 3508 | 3674 | if (tid == ~0U) |
|---|
| 3509 | 3675 | goto out; |
|---|
| 3510 | 3676 | |
|---|
| 3511 | | - ns = dentry->d_sb->s_fs_info; |
|---|
| 3677 | + fs_info = proc_sb_info(dentry->d_sb); |
|---|
| 3678 | + ns = fs_info->pid_ns; |
|---|
| 3512 | 3679 | rcu_read_lock(); |
|---|
| 3513 | 3680 | task = find_task_by_pid_ns(tid, ns); |
|---|
| 3514 | 3681 | if (task) |
|---|
| .. | .. |
|---|
| 3622 | 3789 | /* f_version caches the tgid value that the last readdir call couldn't |
|---|
| 3623 | 3790 | * return. lseek aka telldir automagically resets f_version to 0. |
|---|
| 3624 | 3791 | */ |
|---|
| 3625 | | - ns = proc_pid_ns(inode); |
|---|
| 3792 | + ns = proc_pid_ns(inode->i_sb); |
|---|
| 3626 | 3793 | tid = (int)file->f_version; |
|---|
| 3627 | 3794 | file->f_version = 0; |
|---|
| 3628 | 3795 | for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns); |
|---|