.. | .. |
---|
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 | |
---|
1746 | | -struct inode *proc_pid_make_inode(struct super_block * sb, |
---|
| 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 | + |
---|
| 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; |
---|
1771 | 1914 | |
---|
1772 | 1915 | task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); |
---|
1773 | 1916 | security_task_to_inode(task, inode); |
---|
.. | .. |
---|
1780 | 1923 | return NULL; |
---|
1781 | 1924 | } |
---|
1782 | 1925 | |
---|
| 1926 | +/* |
---|
| 1927 | + * Generating an inode and adding it into @pid->inodes, so that task will |
---|
| 1928 | + * invalidate inode's dentry before being released. |
---|
| 1929 | + * |
---|
| 1930 | + * This helper is used for creating dir-type entries under '/proc' and |
---|
| 1931 | + * '/proc/<tgid>/task'. Other entries(eg. fd, stat) under '/proc/<tgid>' |
---|
| 1932 | + * can be released by invalidating '/proc/<tgid>' dentry. |
---|
| 1933 | + * In theory, dentries under '/proc/<tgid>/task' can also be released by |
---|
| 1934 | + * invalidating '/proc/<tgid>' dentry, we reserve it to handle single |
---|
| 1935 | + * thread exiting situation: Any one of threads should invalidate its |
---|
| 1936 | + * '/proc/<tgid>/task/<pid>' dentry before released. |
---|
| 1937 | + */ |
---|
| 1938 | +static struct inode *proc_pid_make_base_inode(struct super_block *sb, |
---|
| 1939 | + struct task_struct *task, umode_t mode) |
---|
| 1940 | +{ |
---|
| 1941 | + struct inode *inode; |
---|
| 1942 | + struct proc_inode *ei; |
---|
| 1943 | + struct pid *pid; |
---|
| 1944 | + |
---|
| 1945 | + inode = proc_pid_make_inode(sb, task, mode); |
---|
| 1946 | + if (!inode) |
---|
| 1947 | + return NULL; |
---|
| 1948 | + |
---|
| 1949 | + /* Let proc_flush_pid find this directory inode */ |
---|
| 1950 | + ei = PROC_I(inode); |
---|
| 1951 | + pid = ei->pid; |
---|
| 1952 | + spin_lock(&pid->lock); |
---|
| 1953 | + hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes); |
---|
| 1954 | + spin_unlock(&pid->lock); |
---|
| 1955 | + |
---|
| 1956 | + return inode; |
---|
| 1957 | +} |
---|
| 1958 | + |
---|
1783 | 1959 | int pid_getattr(const struct path *path, struct kstat *stat, |
---|
1784 | 1960 | u32 request_mask, unsigned int query_flags) |
---|
1785 | 1961 | { |
---|
1786 | 1962 | struct inode *inode = d_inode(path->dentry); |
---|
1787 | | - struct pid_namespace *pid = proc_pid_ns(inode); |
---|
| 1963 | + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); |
---|
1788 | 1964 | struct task_struct *task; |
---|
1789 | 1965 | |
---|
1790 | 1966 | generic_fillattr(inode, stat); |
---|
.. | .. |
---|
1794 | 1970 | rcu_read_lock(); |
---|
1795 | 1971 | task = pid_task(proc_pid(inode), PIDTYPE_PID); |
---|
1796 | 1972 | if (task) { |
---|
1797 | | - if (!has_pid_permissions(pid, task, HIDEPID_INVISIBLE)) { |
---|
| 1973 | + if (!has_pid_permissions(fs_info, task, HIDEPID_INVISIBLE)) { |
---|
1798 | 1974 | rcu_read_unlock(); |
---|
1799 | 1975 | /* |
---|
1800 | 1976 | * This doesn't prevent learning whether PID exists, |
---|
.. | .. |
---|
1891 | 2067 | |
---|
1892 | 2068 | child = d_hash_and_lookup(dir, &qname); |
---|
1893 | 2069 | if (!child) { |
---|
1894 | | - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); |
---|
| 2070 | + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); |
---|
1895 | 2071 | child = d_alloc_parallel(dir, &qname, &wq); |
---|
1896 | 2072 | if (IS_ERR(child)) |
---|
1897 | 2073 | goto end_instantiate; |
---|
.. | .. |
---|
1979 | 2155 | goto out; |
---|
1980 | 2156 | |
---|
1981 | 2157 | if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) { |
---|
1982 | | - status = down_read_killable(&mm->mmap_sem); |
---|
| 2158 | + status = mmap_read_lock_killable(mm); |
---|
1983 | 2159 | if (!status) { |
---|
1984 | 2160 | exact_vma_exists = !!find_exact_vma(mm, vm_start, |
---|
1985 | 2161 | vm_end); |
---|
1986 | | - up_read(&mm->mmap_sem); |
---|
| 2162 | + mmap_read_unlock(mm); |
---|
1987 | 2163 | } |
---|
1988 | 2164 | } |
---|
1989 | 2165 | |
---|
.. | .. |
---|
2030 | 2206 | if (rc) |
---|
2031 | 2207 | goto out_mmput; |
---|
2032 | 2208 | |
---|
2033 | | - rc = down_read_killable(&mm->mmap_sem); |
---|
| 2209 | + rc = mmap_read_lock_killable(mm); |
---|
2034 | 2210 | if (rc) |
---|
2035 | 2211 | goto out_mmput; |
---|
2036 | 2212 | |
---|
.. | .. |
---|
2041 | 2217 | path_get(path); |
---|
2042 | 2218 | rc = 0; |
---|
2043 | 2219 | } |
---|
2044 | | - up_read(&mm->mmap_sem); |
---|
| 2220 | + mmap_read_unlock(mm); |
---|
2045 | 2221 | |
---|
2046 | 2222 | out_mmput: |
---|
2047 | 2223 | mmput(mm); |
---|
.. | .. |
---|
2056 | 2232 | }; |
---|
2057 | 2233 | |
---|
2058 | 2234 | /* |
---|
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. |
---|
| 2235 | + * Only allow CAP_SYS_ADMIN and CAP_CHECKPOINT_RESTORE to follow the links, due |
---|
| 2236 | + * to concerns about how the symlinks may be used to bypass permissions on |
---|
| 2237 | + * ancestor directories in the path to the file in question. |
---|
2062 | 2238 | */ |
---|
2063 | 2239 | static const char * |
---|
2064 | 2240 | proc_map_files_get_link(struct dentry *dentry, |
---|
2065 | 2241 | struct inode *inode, |
---|
2066 | 2242 | struct delayed_call *done) |
---|
2067 | 2243 | { |
---|
2068 | | - if (!capable(CAP_SYS_ADMIN)) |
---|
| 2244 | + if (!checkpoint_restore_ns_capable(&init_user_ns)) |
---|
2069 | 2245 | return ERR_PTR(-EPERM); |
---|
2070 | 2246 | |
---|
2071 | 2247 | return proc_pid_get_link(dentry, inode, done); |
---|
.. | .. |
---|
2131 | 2307 | goto out_put_task; |
---|
2132 | 2308 | |
---|
2133 | 2309 | result = ERR_PTR(-EINTR); |
---|
2134 | | - if (down_read_killable(&mm->mmap_sem)) |
---|
| 2310 | + if (mmap_read_lock_killable(mm)) |
---|
2135 | 2311 | goto out_put_mm; |
---|
2136 | 2312 | |
---|
2137 | 2313 | result = ERR_PTR(-ENOENT); |
---|
.. | .. |
---|
2144 | 2320 | (void *)(unsigned long)vma->vm_file->f_mode); |
---|
2145 | 2321 | |
---|
2146 | 2322 | out_no_vma: |
---|
2147 | | - up_read(&mm->mmap_sem); |
---|
| 2323 | + mmap_read_unlock(mm); |
---|
2148 | 2324 | out_put_mm: |
---|
2149 | 2325 | mmput(mm); |
---|
2150 | 2326 | out_put_task: |
---|
.. | .. |
---|
2166 | 2342 | struct task_struct *task; |
---|
2167 | 2343 | struct mm_struct *mm; |
---|
2168 | 2344 | unsigned long nr_files, pos, i; |
---|
2169 | | - struct flex_array *fa = NULL; |
---|
2170 | | - struct map_files_info info; |
---|
| 2345 | + GENRADIX(struct map_files_info) fa; |
---|
2171 | 2346 | struct map_files_info *p; |
---|
2172 | 2347 | int ret; |
---|
| 2348 | + |
---|
| 2349 | + genradix_init(&fa); |
---|
2173 | 2350 | |
---|
2174 | 2351 | ret = -ENOENT; |
---|
2175 | 2352 | task = get_proc_task(file_inode(file)); |
---|
.. | .. |
---|
2188 | 2365 | if (!mm) |
---|
2189 | 2366 | goto out_put_task; |
---|
2190 | 2367 | |
---|
2191 | | - ret = down_read_killable(&mm->mmap_sem); |
---|
| 2368 | + ret = mmap_read_lock_killable(mm); |
---|
2192 | 2369 | if (ret) { |
---|
2193 | 2370 | mmput(mm); |
---|
2194 | 2371 | goto out_put_task; |
---|
.. | .. |
---|
2199 | 2376 | /* |
---|
2200 | 2377 | * We need two passes here: |
---|
2201 | 2378 | * |
---|
2202 | | - * 1) Collect vmas of mapped files with mmap_sem taken |
---|
2203 | | - * 2) Release mmap_sem and instantiate entries |
---|
| 2379 | + * 1) Collect vmas of mapped files with mmap_lock taken |
---|
| 2380 | + * 2) Release mmap_lock and instantiate entries |
---|
2204 | 2381 | * |
---|
2205 | 2382 | * otherwise we get lockdep complained, since filldir() |
---|
2206 | | - * routine might require mmap_sem taken in might_fault(). |
---|
| 2383 | + * routine might require mmap_lock taken in might_fault(). |
---|
2207 | 2384 | */ |
---|
2208 | 2385 | |
---|
2209 | 2386 | for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) { |
---|
2210 | | - if (vma->vm_file && ++pos > ctx->pos) |
---|
2211 | | - nr_files++; |
---|
2212 | | - } |
---|
| 2387 | + if (!vma->vm_file) |
---|
| 2388 | + continue; |
---|
| 2389 | + if (++pos <= ctx->pos) |
---|
| 2390 | + continue; |
---|
2213 | 2391 | |
---|
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)) { |
---|
| 2392 | + p = genradix_ptr_alloc(&fa, nr_files++, GFP_KERNEL); |
---|
| 2393 | + if (!p) { |
---|
2219 | 2394 | ret = -ENOMEM; |
---|
2220 | | - if (fa) |
---|
2221 | | - flex_array_free(fa); |
---|
2222 | | - up_read(&mm->mmap_sem); |
---|
| 2395 | + mmap_read_unlock(mm); |
---|
2223 | 2396 | mmput(mm); |
---|
2224 | 2397 | goto out_put_task; |
---|
2225 | 2398 | } |
---|
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 | 2399 | |
---|
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 | | - } |
---|
| 2400 | + p->start = vma->vm_start; |
---|
| 2401 | + p->end = vma->vm_end; |
---|
| 2402 | + p->mode = vma->vm_file->f_mode; |
---|
2239 | 2403 | } |
---|
2240 | | - up_read(&mm->mmap_sem); |
---|
| 2404 | + mmap_read_unlock(mm); |
---|
2241 | 2405 | mmput(mm); |
---|
2242 | 2406 | |
---|
2243 | 2407 | for (i = 0; i < nr_files; i++) { |
---|
2244 | 2408 | char buf[4 * sizeof(long) + 2]; /* max: %lx-%lx\0 */ |
---|
2245 | 2409 | unsigned int len; |
---|
2246 | 2410 | |
---|
2247 | | - p = flex_array_get(fa, i); |
---|
| 2411 | + p = genradix_ptr(&fa, i); |
---|
2248 | 2412 | len = snprintf(buf, sizeof(buf), "%lx-%lx", p->start, p->end); |
---|
2249 | 2413 | if (!proc_fill_cache(file, ctx, |
---|
2250 | 2414 | buf, len, |
---|
.. | .. |
---|
2254 | 2418 | break; |
---|
2255 | 2419 | ctx->pos++; |
---|
2256 | 2420 | } |
---|
2257 | | - if (fa) |
---|
2258 | | - flex_array_free(fa); |
---|
2259 | 2421 | |
---|
2260 | 2422 | out_put_task: |
---|
2261 | 2423 | put_task_struct(task); |
---|
2262 | 2424 | out: |
---|
| 2425 | + genradix_free(&fa); |
---|
2263 | 2426 | return ret; |
---|
2264 | 2427 | } |
---|
2265 | 2428 | |
---|
.. | .. |
---|
2358 | 2521 | return -ENOMEM; |
---|
2359 | 2522 | |
---|
2360 | 2523 | tp->pid = proc_pid(inode); |
---|
2361 | | - tp->ns = proc_pid_ns(inode); |
---|
| 2524 | + tp->ns = proc_pid_ns(inode->i_sb); |
---|
2362 | 2525 | return 0; |
---|
2363 | 2526 | } |
---|
2364 | 2527 | |
---|
.. | .. |
---|
2387 | 2550 | return -ESRCH; |
---|
2388 | 2551 | |
---|
2389 | 2552 | if (p != current) { |
---|
2390 | | - if (!capable(CAP_SYS_NICE)) { |
---|
| 2553 | + rcu_read_lock(); |
---|
| 2554 | + if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) { |
---|
| 2555 | + rcu_read_unlock(); |
---|
2391 | 2556 | count = -EPERM; |
---|
2392 | 2557 | goto out; |
---|
2393 | 2558 | } |
---|
| 2559 | + rcu_read_unlock(); |
---|
2394 | 2560 | |
---|
2395 | 2561 | err = security_task_setscheduler(p); |
---|
2396 | 2562 | if (err) { |
---|
.. | .. |
---|
2423 | 2589 | return -ESRCH; |
---|
2424 | 2590 | |
---|
2425 | 2591 | if (p != current) { |
---|
2426 | | - |
---|
2427 | | - if (!capable(CAP_SYS_NICE)) { |
---|
| 2592 | + rcu_read_lock(); |
---|
| 2593 | + if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) { |
---|
| 2594 | + rcu_read_unlock(); |
---|
2428 | 2595 | err = -EPERM; |
---|
2429 | 2596 | goto out; |
---|
2430 | 2597 | } |
---|
| 2598 | + rcu_read_unlock(); |
---|
| 2599 | + |
---|
2431 | 2600 | err = security_task_getscheduler(p); |
---|
2432 | 2601 | if (err) |
---|
2433 | 2602 | goto out; |
---|
.. | .. |
---|
2482 | 2651 | |
---|
2483 | 2652 | static struct dentry *proc_pident_lookup(struct inode *dir, |
---|
2484 | 2653 | struct dentry *dentry, |
---|
2485 | | - const struct pid_entry *ents, |
---|
2486 | | - unsigned int nents) |
---|
| 2654 | + const struct pid_entry *p, |
---|
| 2655 | + const struct pid_entry *end) |
---|
2487 | 2656 | { |
---|
2488 | 2657 | struct task_struct *task = get_proc_task(dir); |
---|
2489 | | - const struct pid_entry *p, *last; |
---|
2490 | 2658 | struct dentry *res = ERR_PTR(-ENOENT); |
---|
2491 | 2659 | |
---|
2492 | 2660 | if (!task) |
---|
.. | .. |
---|
2496 | 2664 | * Yes, it does not scale. And it should not. Don't add |
---|
2497 | 2665 | * new entries into /proc/<tgid>/ without very good reasons. |
---|
2498 | 2666 | */ |
---|
2499 | | - last = &ents[nents]; |
---|
2500 | | - for (p = ents; p < last; p++) { |
---|
| 2667 | + for (; p < end; p++) { |
---|
2501 | 2668 | if (p->len != dentry->d_name.len) |
---|
2502 | 2669 | continue; |
---|
2503 | 2670 | if (!memcmp(dentry->d_name.name, p->name, p->len)) { |
---|
.. | .. |
---|
2555 | 2722 | if (!task) |
---|
2556 | 2723 | return -ESRCH; |
---|
2557 | 2724 | |
---|
2558 | | - length = security_getprocattr(task, |
---|
| 2725 | + length = security_getprocattr(task, PROC_I(inode)->op.lsm, |
---|
2559 | 2726 | (char*)file->f_path.dentry->d_name.name, |
---|
2560 | 2727 | &p); |
---|
2561 | 2728 | put_task_struct(task); |
---|
.. | .. |
---|
2613 | 2780 | if (rv < 0) |
---|
2614 | 2781 | goto out_free; |
---|
2615 | 2782 | |
---|
2616 | | - rv = security_setprocattr(file->f_path.dentry->d_name.name, page, count); |
---|
| 2783 | + rv = security_setprocattr(PROC_I(inode)->op.lsm, |
---|
| 2784 | + file->f_path.dentry->d_name.name, page, |
---|
| 2785 | + count); |
---|
2617 | 2786 | mutex_unlock(¤t->signal->cred_guard_mutex); |
---|
2618 | 2787 | out_free: |
---|
2619 | 2788 | kfree(page); |
---|
.. | .. |
---|
2629 | 2798 | .release = mem_release, |
---|
2630 | 2799 | }; |
---|
2631 | 2800 | |
---|
| 2801 | +#define LSM_DIR_OPS(LSM) \ |
---|
| 2802 | +static int proc_##LSM##_attr_dir_iterate(struct file *filp, \ |
---|
| 2803 | + struct dir_context *ctx) \ |
---|
| 2804 | +{ \ |
---|
| 2805 | + return proc_pident_readdir(filp, ctx, \ |
---|
| 2806 | + LSM##_attr_dir_stuff, \ |
---|
| 2807 | + ARRAY_SIZE(LSM##_attr_dir_stuff)); \ |
---|
| 2808 | +} \ |
---|
| 2809 | +\ |
---|
| 2810 | +static const struct file_operations proc_##LSM##_attr_dir_ops = { \ |
---|
| 2811 | + .read = generic_read_dir, \ |
---|
| 2812 | + .iterate = proc_##LSM##_attr_dir_iterate, \ |
---|
| 2813 | + .llseek = default_llseek, \ |
---|
| 2814 | +}; \ |
---|
| 2815 | +\ |
---|
| 2816 | +static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \ |
---|
| 2817 | + struct dentry *dentry, unsigned int flags) \ |
---|
| 2818 | +{ \ |
---|
| 2819 | + return proc_pident_lookup(dir, dentry, \ |
---|
| 2820 | + LSM##_attr_dir_stuff, \ |
---|
| 2821 | + LSM##_attr_dir_stuff + ARRAY_SIZE(LSM##_attr_dir_stuff)); \ |
---|
| 2822 | +} \ |
---|
| 2823 | +\ |
---|
| 2824 | +static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \ |
---|
| 2825 | + .lookup = proc_##LSM##_attr_dir_lookup, \ |
---|
| 2826 | + .getattr = pid_getattr, \ |
---|
| 2827 | + .setattr = proc_setattr, \ |
---|
| 2828 | +} |
---|
| 2829 | + |
---|
| 2830 | +#ifdef CONFIG_SECURITY_SMACK |
---|
| 2831 | +static const struct pid_entry smack_attr_dir_stuff[] = { |
---|
| 2832 | + ATTR("smack", "current", 0666), |
---|
| 2833 | +}; |
---|
| 2834 | +LSM_DIR_OPS(smack); |
---|
| 2835 | +#endif |
---|
| 2836 | + |
---|
| 2837 | +#ifdef CONFIG_SECURITY_APPARMOR |
---|
| 2838 | +static const struct pid_entry apparmor_attr_dir_stuff[] = { |
---|
| 2839 | + ATTR("apparmor", "current", 0666), |
---|
| 2840 | + ATTR("apparmor", "prev", 0444), |
---|
| 2841 | + ATTR("apparmor", "exec", 0666), |
---|
| 2842 | +}; |
---|
| 2843 | +LSM_DIR_OPS(apparmor); |
---|
| 2844 | +#endif |
---|
| 2845 | + |
---|
2632 | 2846 | 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), |
---|
| 2847 | + ATTR(NULL, "current", 0666), |
---|
| 2848 | + ATTR(NULL, "prev", 0444), |
---|
| 2849 | + ATTR(NULL, "exec", 0666), |
---|
| 2850 | + ATTR(NULL, "fscreate", 0666), |
---|
| 2851 | + ATTR(NULL, "keycreate", 0666), |
---|
| 2852 | + ATTR(NULL, "sockcreate", 0666), |
---|
| 2853 | +#ifdef CONFIG_SECURITY_SMACK |
---|
| 2854 | + DIR("smack", 0555, |
---|
| 2855 | + proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops), |
---|
| 2856 | +#endif |
---|
| 2857 | +#ifdef CONFIG_SECURITY_APPARMOR |
---|
| 2858 | + DIR("apparmor", 0555, |
---|
| 2859 | + proc_apparmor_attr_dir_inode_ops, proc_apparmor_attr_dir_ops), |
---|
| 2860 | +#endif |
---|
2639 | 2861 | }; |
---|
2640 | 2862 | |
---|
2641 | 2863 | static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) |
---|
.. | .. |
---|
2654 | 2876 | struct dentry *dentry, unsigned int flags) |
---|
2655 | 2877 | { |
---|
2656 | 2878 | return proc_pident_lookup(dir, dentry, |
---|
2657 | | - attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff)); |
---|
| 2879 | + attr_dir_stuff, |
---|
| 2880 | + attr_dir_stuff + ARRAY_SIZE(attr_dir_stuff)); |
---|
2658 | 2881 | } |
---|
2659 | 2882 | |
---|
2660 | 2883 | static const struct inode_operations proc_attr_dir_inode_operations = { |
---|
.. | .. |
---|
2749 | 2972 | unsigned long flags; |
---|
2750 | 2973 | int result; |
---|
2751 | 2974 | |
---|
2752 | | - result = mutex_lock_killable(&task->signal->cred_guard_mutex); |
---|
| 2975 | + result = down_read_killable(&task->signal->exec_update_lock); |
---|
2753 | 2976 | if (result) |
---|
2754 | 2977 | return result; |
---|
2755 | 2978 | |
---|
.. | .. |
---|
2785 | 3008 | result = 0; |
---|
2786 | 3009 | |
---|
2787 | 3010 | out_unlock: |
---|
2788 | | - mutex_unlock(&task->signal->cred_guard_mutex); |
---|
| 3011 | + up_read(&task->signal->exec_update_lock); |
---|
2789 | 3012 | return result; |
---|
2790 | 3013 | } |
---|
2791 | 3014 | |
---|
.. | .. |
---|
2954 | 3177 | } |
---|
2955 | 3178 | #endif /* CONFIG_LIVEPATCH */ |
---|
2956 | 3179 | |
---|
| 3180 | +#ifdef CONFIG_STACKLEAK_METRICS |
---|
| 3181 | +static int proc_stack_depth(struct seq_file *m, struct pid_namespace *ns, |
---|
| 3182 | + struct pid *pid, struct task_struct *task) |
---|
| 3183 | +{ |
---|
| 3184 | + unsigned long prev_depth = THREAD_SIZE - |
---|
| 3185 | + (task->prev_lowest_stack & (THREAD_SIZE - 1)); |
---|
| 3186 | + unsigned long depth = THREAD_SIZE - |
---|
| 3187 | + (task->lowest_stack & (THREAD_SIZE - 1)); |
---|
| 3188 | + |
---|
| 3189 | + seq_printf(m, "previous stack depth: %lu\nstack depth: %lu\n", |
---|
| 3190 | + prev_depth, depth); |
---|
| 3191 | + return 0; |
---|
| 3192 | +} |
---|
| 3193 | +#endif /* CONFIG_STACKLEAK_METRICS */ |
---|
| 3194 | + |
---|
2957 | 3195 | /* |
---|
2958 | 3196 | * Thread groups |
---|
2959 | 3197 | */ |
---|
.. | .. |
---|
2964 | 3202 | DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), |
---|
2965 | 3203 | DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), |
---|
2966 | 3204 | 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), |
---|
| 3205 | + DIR("fdinfo", S_IRUGO|S_IXUGO, proc_fdinfo_inode_operations, proc_fdinfo_operations), |
---|
2968 | 3206 | DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), |
---|
2969 | 3207 | #ifdef CONFIG_NET |
---|
2970 | 3208 | DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), |
---|
.. | .. |
---|
2979 | 3217 | #endif |
---|
2980 | 3218 | #ifdef CONFIG_SCHED_AUTOGROUP |
---|
2981 | 3219 | REG("autogroup", S_IRUGO|S_IWUSR, proc_pid_sched_autogroup_operations), |
---|
| 3220 | +#endif |
---|
| 3221 | +#ifdef CONFIG_TIME_NS |
---|
| 3222 | + REG("timens_offsets", S_IRUGO|S_IWUSR, proc_timens_offsets_operations), |
---|
2982 | 3223 | #endif |
---|
2983 | 3224 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
---|
2984 | 3225 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
---|
.. | .. |
---|
3025 | 3266 | #ifdef CONFIG_CGROUPS |
---|
3026 | 3267 | ONE("cgroup", S_IRUGO, proc_cgroup_show), |
---|
3027 | 3268 | #endif |
---|
| 3269 | +#ifdef CONFIG_PROC_CPU_RESCTRL |
---|
| 3270 | + ONE("cpu_resctrl_groups", S_IRUGO, proc_resctrl_show), |
---|
| 3271 | +#endif |
---|
3028 | 3272 | ONE("oom_score", S_IRUGO, proc_oom_score), |
---|
3029 | 3273 | REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), |
---|
3030 | 3274 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), |
---|
3031 | | -#ifdef CONFIG_AUDITSYSCALL |
---|
| 3275 | +#ifdef CONFIG_AUDIT |
---|
3032 | 3276 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), |
---|
3033 | 3277 | REG("sessionid", S_IRUGO, proc_sessionid_operations), |
---|
3034 | 3278 | #endif |
---|
.. | .. |
---|
3058 | 3302 | #ifdef CONFIG_CPU_FREQ_TIMES |
---|
3059 | 3303 | ONE("time_in_state", 0444, proc_time_in_state_show), |
---|
3060 | 3304 | #endif |
---|
| 3305 | +#ifdef CONFIG_STACKLEAK_METRICS |
---|
| 3306 | + ONE("stack_depth", S_IRUGO, proc_stack_depth), |
---|
| 3307 | +#endif |
---|
| 3308 | +#ifdef CONFIG_PROC_PID_ARCH_STATUS |
---|
| 3309 | + ONE("arch_status", S_IRUGO, proc_pid_arch_status), |
---|
| 3310 | +#endif |
---|
3061 | 3311 | }; |
---|
3062 | 3312 | |
---|
3063 | 3313 | static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) |
---|
.. | .. |
---|
3074 | 3324 | |
---|
3075 | 3325 | struct pid *tgid_pidfd_to_pid(const struct file *file) |
---|
3076 | 3326 | { |
---|
3077 | | - if (!d_is_dir(file->f_path.dentry) || |
---|
3078 | | - (file->f_op != &proc_tgid_base_operations)) |
---|
| 3327 | + if (file->f_op != &proc_tgid_base_operations) |
---|
3079 | 3328 | return ERR_PTR(-EBADF); |
---|
3080 | 3329 | |
---|
3081 | 3330 | return proc_pid(file_inode(file)); |
---|
.. | .. |
---|
3084 | 3333 | static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) |
---|
3085 | 3334 | { |
---|
3086 | 3335 | return proc_pident_lookup(dir, dentry, |
---|
3087 | | - tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); |
---|
| 3336 | + tgid_base_stuff, |
---|
| 3337 | + tgid_base_stuff + ARRAY_SIZE(tgid_base_stuff)); |
---|
3088 | 3338 | } |
---|
3089 | 3339 | |
---|
3090 | 3340 | static const struct inode_operations proc_tgid_base_inode_operations = { |
---|
.. | .. |
---|
3094 | 3344 | .permission = proc_pid_permission, |
---|
3095 | 3345 | }; |
---|
3096 | 3346 | |
---|
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 | 3347 | /** |
---|
3143 | | - * proc_flush_task - Remove dcache entries for @task from the /proc dcache. |
---|
3144 | | - * @task: task that should be flushed. |
---|
| 3348 | + * proc_flush_pid - Remove dcache entries for @pid from the /proc dcache. |
---|
| 3349 | + * @pid: pid that should be flushed. |
---|
3145 | 3350 | * |
---|
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. |
---|
| 3351 | + * This function walks a list of inodes (that belong to any proc |
---|
| 3352 | + * filesystem) that are attached to the pid and flushes them from |
---|
| 3353 | + * the dentry cache. |
---|
3155 | 3354 | * |
---|
3156 | 3355 | * It is safe and reasonable to cache /proc entries for a task until |
---|
3157 | 3356 | * that task exits. After that they just clog up the dcache with |
---|
3158 | 3357 | * 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. |
---|
| 3358 | + * flushed instead. This routine is provided to flush those useless |
---|
| 3359 | + * dcache entries when a process is reaped. |
---|
3161 | 3360 | * |
---|
3162 | 3361 | * 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. |
---|
| 3362 | + * that no dcache entries will exist after a process is reaped |
---|
| 3363 | + * it just makes it very unlikely that any will persist. |
---|
3165 | 3364 | */ |
---|
3166 | 3365 | |
---|
3167 | | -void proc_flush_task(struct task_struct *task) |
---|
| 3366 | +void proc_flush_pid(struct pid *pid) |
---|
3168 | 3367 | { |
---|
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 | | - } |
---|
| 3368 | + proc_invalidate_siblings_dcache(&pid->inodes, &pid->lock); |
---|
3181 | 3369 | } |
---|
3182 | 3370 | |
---|
3183 | 3371 | static struct dentry *proc_pid_instantiate(struct dentry * dentry, |
---|
.. | .. |
---|
3185 | 3373 | { |
---|
3186 | 3374 | struct inode *inode; |
---|
3187 | 3375 | |
---|
3188 | | - inode = proc_pid_make_inode(dentry->d_sb, task, S_IFDIR | S_IRUGO | S_IXUGO); |
---|
| 3376 | + inode = proc_pid_make_base_inode(dentry->d_sb, task, |
---|
| 3377 | + S_IFDIR | S_IRUGO | S_IXUGO); |
---|
3189 | 3378 | if (!inode) |
---|
3190 | 3379 | return ERR_PTR(-ENOENT); |
---|
3191 | 3380 | |
---|
.. | .. |
---|
3200 | 3389 | return d_splice_alias(inode, dentry); |
---|
3201 | 3390 | } |
---|
3202 | 3391 | |
---|
3203 | | -struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) |
---|
| 3392 | +struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags) |
---|
3204 | 3393 | { |
---|
3205 | 3394 | struct task_struct *task; |
---|
3206 | 3395 | unsigned tgid; |
---|
| 3396 | + struct proc_fs_info *fs_info; |
---|
3207 | 3397 | struct pid_namespace *ns; |
---|
3208 | 3398 | struct dentry *result = ERR_PTR(-ENOENT); |
---|
3209 | 3399 | |
---|
.. | .. |
---|
3211 | 3401 | if (tgid == ~0U) |
---|
3212 | 3402 | goto out; |
---|
3213 | 3403 | |
---|
3214 | | - ns = dentry->d_sb->s_fs_info; |
---|
| 3404 | + fs_info = proc_sb_info(dentry->d_sb); |
---|
| 3405 | + ns = fs_info->pid_ns; |
---|
3215 | 3406 | rcu_read_lock(); |
---|
3216 | 3407 | task = find_task_by_pid_ns(tgid, ns); |
---|
3217 | 3408 | if (task) |
---|
.. | .. |
---|
3220 | 3411 | if (!task) |
---|
3221 | 3412 | goto out; |
---|
3222 | 3413 | |
---|
| 3414 | + /* Limit procfs to only ptraceable tasks */ |
---|
| 3415 | + if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE) { |
---|
| 3416 | + if (!has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS)) |
---|
| 3417 | + goto out_put_task; |
---|
| 3418 | + } |
---|
| 3419 | + |
---|
3223 | 3420 | result = proc_pid_instantiate(dentry, task, NULL); |
---|
| 3421 | +out_put_task: |
---|
3224 | 3422 | put_task_struct(task); |
---|
3225 | 3423 | out: |
---|
3226 | 3424 | return result; |
---|
.. | .. |
---|
3246 | 3444 | pid = find_ge_pid(iter.tgid, ns); |
---|
3247 | 3445 | if (pid) { |
---|
3248 | 3446 | 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)) { |
---|
| 3447 | + iter.task = pid_task(pid, PIDTYPE_TGID); |
---|
| 3448 | + if (!iter.task) { |
---|
3263 | 3449 | iter.tgid += 1; |
---|
3264 | 3450 | goto retry; |
---|
3265 | 3451 | } |
---|
.. | .. |
---|
3275 | 3461 | int proc_pid_readdir(struct file *file, struct dir_context *ctx) |
---|
3276 | 3462 | { |
---|
3277 | 3463 | struct tgid_iter iter; |
---|
3278 | | - struct pid_namespace *ns = proc_pid_ns(file_inode(file)); |
---|
| 3464 | + struct proc_fs_info *fs_info = proc_sb_info(file_inode(file)->i_sb); |
---|
| 3465 | + struct pid_namespace *ns = proc_pid_ns(file_inode(file)->i_sb); |
---|
3279 | 3466 | loff_t pos = ctx->pos; |
---|
3280 | 3467 | |
---|
3281 | 3468 | if (pos >= PID_MAX_LIMIT + TGID_OFFSET) |
---|
3282 | 3469 | return 0; |
---|
3283 | 3470 | |
---|
3284 | 3471 | if (pos == TGID_OFFSET - 2) { |
---|
3285 | | - struct inode *inode = d_inode(ns->proc_self); |
---|
| 3472 | + struct inode *inode = d_inode(fs_info->proc_self); |
---|
3286 | 3473 | if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK)) |
---|
3287 | 3474 | return 0; |
---|
3288 | 3475 | ctx->pos = pos = pos + 1; |
---|
3289 | 3476 | } |
---|
3290 | 3477 | if (pos == TGID_OFFSET - 1) { |
---|
3291 | | - struct inode *inode = d_inode(ns->proc_thread_self); |
---|
| 3478 | + struct inode *inode = d_inode(fs_info->proc_thread_self); |
---|
3292 | 3479 | if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK)) |
---|
3293 | 3480 | return 0; |
---|
3294 | 3481 | ctx->pos = pos = pos + 1; |
---|
.. | .. |
---|
3302 | 3489 | unsigned int len; |
---|
3303 | 3490 | |
---|
3304 | 3491 | cond_resched(); |
---|
3305 | | - if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE)) |
---|
| 3492 | + if (!has_pid_permissions(fs_info, iter.task, HIDEPID_INVISIBLE)) |
---|
3306 | 3493 | continue; |
---|
3307 | 3494 | |
---|
3308 | 3495 | len = snprintf(name, sizeof(name), "%u", iter.tgid); |
---|
.. | .. |
---|
3352 | 3539 | } |
---|
3353 | 3540 | |
---|
3354 | 3541 | static const struct inode_operations proc_tid_comm_inode_operations = { |
---|
3355 | | - .permission = proc_tid_comm_permission, |
---|
| 3542 | + .setattr = proc_setattr, |
---|
| 3543 | + .permission = proc_tid_comm_permission, |
---|
3356 | 3544 | }; |
---|
3357 | 3545 | |
---|
3358 | 3546 | /* |
---|
.. | .. |
---|
3360 | 3548 | */ |
---|
3361 | 3549 | static const struct pid_entry tid_base_stuff[] = { |
---|
3362 | 3550 | 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), |
---|
| 3551 | + DIR("fdinfo", S_IRUGO|S_IXUGO, proc_fdinfo_inode_operations, proc_fdinfo_operations), |
---|
3364 | 3552 | DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), |
---|
3365 | 3553 | #ifdef CONFIG_NET |
---|
3366 | 3554 | DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), |
---|
.. | .. |
---|
3422 | 3610 | #ifdef CONFIG_CGROUPS |
---|
3423 | 3611 | ONE("cgroup", S_IRUGO, proc_cgroup_show), |
---|
3424 | 3612 | #endif |
---|
| 3613 | +#ifdef CONFIG_PROC_CPU_RESCTRL |
---|
| 3614 | + ONE("cpu_resctrl_groups", S_IRUGO, proc_resctrl_show), |
---|
| 3615 | +#endif |
---|
3425 | 3616 | ONE("oom_score", S_IRUGO, proc_oom_score), |
---|
3426 | 3617 | REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), |
---|
3427 | 3618 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), |
---|
3428 | | -#ifdef CONFIG_AUDITSYSCALL |
---|
| 3619 | +#ifdef CONFIG_AUDIT |
---|
3429 | 3620 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), |
---|
3430 | 3621 | REG("sessionid", S_IRUGO, proc_sessionid_operations), |
---|
3431 | 3622 | #endif |
---|
.. | .. |
---|
3445 | 3636 | #ifdef CONFIG_LIVEPATCH |
---|
3446 | 3637 | ONE("patch_state", S_IRUSR, proc_pid_patch_state), |
---|
3447 | 3638 | #endif |
---|
| 3639 | +#ifdef CONFIG_PROC_PID_ARCH_STATUS |
---|
| 3640 | + ONE("arch_status", S_IRUGO, proc_pid_arch_status), |
---|
| 3641 | +#endif |
---|
3448 | 3642 | #ifdef CONFIG_CPU_FREQ_TIMES |
---|
3449 | 3643 | ONE("time_in_state", 0444, proc_time_in_state_show), |
---|
3450 | 3644 | #endif |
---|
.. | .. |
---|
3459 | 3653 | static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) |
---|
3460 | 3654 | { |
---|
3461 | 3655 | return proc_pident_lookup(dir, dentry, |
---|
3462 | | - tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); |
---|
| 3656 | + tid_base_stuff, |
---|
| 3657 | + tid_base_stuff + ARRAY_SIZE(tid_base_stuff)); |
---|
3463 | 3658 | } |
---|
3464 | 3659 | |
---|
3465 | 3660 | static const struct file_operations proc_tid_base_operations = { |
---|
.. | .. |
---|
3478 | 3673 | struct task_struct *task, const void *ptr) |
---|
3479 | 3674 | { |
---|
3480 | 3675 | struct inode *inode; |
---|
3481 | | - inode = proc_pid_make_inode(dentry->d_sb, task, S_IFDIR | S_IRUGO | S_IXUGO); |
---|
| 3676 | + inode = proc_pid_make_base_inode(dentry->d_sb, task, |
---|
| 3677 | + S_IFDIR | S_IRUGO | S_IXUGO); |
---|
3482 | 3678 | if (!inode) |
---|
3483 | 3679 | return ERR_PTR(-ENOENT); |
---|
3484 | 3680 | |
---|
.. | .. |
---|
3498 | 3694 | struct task_struct *task; |
---|
3499 | 3695 | struct task_struct *leader = get_proc_task(dir); |
---|
3500 | 3696 | unsigned tid; |
---|
| 3697 | + struct proc_fs_info *fs_info; |
---|
3501 | 3698 | struct pid_namespace *ns; |
---|
3502 | 3699 | struct dentry *result = ERR_PTR(-ENOENT); |
---|
3503 | 3700 | |
---|
.. | .. |
---|
3508 | 3705 | if (tid == ~0U) |
---|
3509 | 3706 | goto out; |
---|
3510 | 3707 | |
---|
3511 | | - ns = dentry->d_sb->s_fs_info; |
---|
| 3708 | + fs_info = proc_sb_info(dentry->d_sb); |
---|
| 3709 | + ns = fs_info->pid_ns; |
---|
3512 | 3710 | rcu_read_lock(); |
---|
3513 | 3711 | task = find_task_by_pid_ns(tid, ns); |
---|
3514 | 3712 | if (task) |
---|
.. | .. |
---|
3622 | 3820 | /* f_version caches the tgid value that the last readdir call couldn't |
---|
3623 | 3821 | * return. lseek aka telldir automagically resets f_version to 0. |
---|
3624 | 3822 | */ |
---|
3625 | | - ns = proc_pid_ns(inode); |
---|
| 3823 | + ns = proc_pid_ns(inode->i_sb); |
---|
3626 | 3824 | tid = (int)file->f_version; |
---|
3627 | 3825 | file->f_version = 0; |
---|
3628 | 3826 | for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns); |
---|