Merge branch 'proc-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull proc updates from Eric Biederman:
 "This has four sets of changes:

   - modernize proc to support multiple private instances

   - ensure we see the exit of each process tid exactly

   - remove has_group_leader_pid

   - use pids not tasks in posix-cpu-timers lookup

  Alexey updated proc so each mount of proc uses a new superblock. This
  allows people to actually use mount options with proc with no fear of
  messing up another mount of proc. Given the kernel's internal mounts
  of proc for things like uml this was a real problem, and resulted in
  Android's hidepid mount options being ignored and introducing security
  issues.

  The rest of the changes are small cleanups and fixes that came out of
  my work to allow this change to proc. In essence it is swapping the
  pids in de_thread during exec which removes a special case the code
  had to handle. Then updating the code to stop handling that special
  case"

* 'proc-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  proc: proc_pid_ns takes super_block as an argument
  remove the no longer needed pid_alive() check in __task_pid_nr_ns()
  posix-cpu-timers: Replace __get_task_for_clock with pid_for_clock
  posix-cpu-timers: Replace cpu_timer_pid_type with clock_pid_type
  posix-cpu-timers: Extend rcu_read_lock removing task_struct references
  signal: Remove has_group_leader_pid
  exec: Remove BUG_ON(has_group_leader_pid)
  posix-cpu-timer:  Unify the now redundant code in lookup_task
  posix-cpu-timer: Tidy up group_leader logic in lookup_task
  proc: Ensure we see the exit of each process tid exactly once
  rculist: Add hlists_swap_heads_rcu
  proc: Use PIDTYPE_TGID in next_tgid
  Use proc_pid_ns() to get pid_namespace from the proc superblock
  proc: use named enums for better readability
  proc: use human-readable values for hidepid
  docs: proc: add documentation for "hidepid=4" and "subset=pid" options and new mount behavior
  proc: add option to mount only a pids subset
  proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option
  proc: allow to mount many instances of proc in one pid namespace
  proc: rename struct proc_fs_info to proc_fs_opts
This commit is contained in:
Linus Torvalds
2020-06-04 13:54:34 -07:00
25 changed files with 493 additions and 207 deletions
+1 -1
View File
@@ -1759,7 +1759,7 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
pid_t nr = -1;
if (likely(pid_has_task(pid, PIDTYPE_PID))) {
ns = proc_pid_ns(file_inode(m->file));
ns = proc_pid_ns(file_inode(m->file)->i_sb);
nr = pid_nr_ns(pid, ns);
}
+20 -2
View File
@@ -363,6 +363,25 @@ void change_pid(struct task_struct *task, enum pid_type type,
attach_pid(task, type);
}
void exchange_tids(struct task_struct *left, struct task_struct *right)
{
struct pid *pid1 = left->thread_pid;
struct pid *pid2 = right->thread_pid;
struct hlist_head *head1 = &pid1->tasks[PIDTYPE_PID];
struct hlist_head *head2 = &pid2->tasks[PIDTYPE_PID];
/* Swap the single entry tid lists */
hlists_swap_heads_rcu(head1, head2);
/* Swap the per task_struct pid */
rcu_assign_pointer(left->thread_pid, pid2);
rcu_assign_pointer(right->thread_pid, pid1);
/* Swap the cached value */
WRITE_ONCE(left->pid, pid_nr(pid2));
WRITE_ONCE(right->pid, pid_nr(pid1));
}
/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */
void transfer_pid(struct task_struct *old, struct task_struct *new,
enum pid_type type)
@@ -476,8 +495,7 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
rcu_read_lock();
if (!ns)
ns = task_active_pid_ns(current);
if (likely(pid_alive(task)))
nr = pid_nr_ns(rcu_dereference(*task_pid_ptr(task, type)), ns);
nr = pid_nr_ns(rcu_dereference(*task_pid_ptr(task, type)), ns);
rcu_read_unlock();
return nr;
+49 -66
View File
@@ -47,85 +47,65 @@ void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new)
/*
* Functions for validating access to tasks.
*/
static struct task_struct *lookup_task(const pid_t pid, bool thread,
bool gettime)
static struct pid *pid_for_clock(const clockid_t clock, bool gettime)
{
struct task_struct *p;
const bool thread = !!CPUCLOCK_PERTHREAD(clock);
const pid_t upid = CPUCLOCK_PID(clock);
struct pid *pid;
if (CPUCLOCK_WHICH(clock) >= CPUCLOCK_MAX)
return NULL;
/*
* If the encoded PID is 0, then the timer is targeted at current
* or the process to which current belongs.
*/
if (upid == 0)
return thread ? task_pid(current) : task_tgid(current);
pid = find_vpid(upid);
if (!pid)
return thread ? current : current->group_leader;
return NULL;
p = find_task_by_vpid(pid);
if (!p)
return p;
if (thread)
return same_thread_group(p, current) ? p : NULL;
if (gettime) {
/*
* For clock_gettime(PROCESS) the task does not need to be
* the actual group leader. tsk->sighand gives
* access to the group's clock.
*
* Timers need the group leader because they take a
* reference on it and store the task pointer until the
* timer is destroyed.
*/
return (p == current || thread_group_leader(p)) ? p : NULL;
if (thread) {
struct task_struct *tsk = pid_task(pid, PIDTYPE_PID);
return (tsk && same_thread_group(tsk, current)) ? pid : NULL;
}
/*
* For processes require that p is group leader.
* For clock_gettime(PROCESS) allow finding the process by
* with the pid of the current task. The code needs the tgid
* of the process so that pid_task(pid, PIDTYPE_TGID) can be
* used to find the process.
*/
return has_group_leader_pid(p) ? p : NULL;
}
if (gettime && (pid == task_pid(current)))
return task_tgid(current);
static struct task_struct *__get_task_for_clock(const clockid_t clock,
bool getref, bool gettime)
{
const bool thread = !!CPUCLOCK_PERTHREAD(clock);
const pid_t pid = CPUCLOCK_PID(clock);
struct task_struct *p;
if (CPUCLOCK_WHICH(clock) >= CPUCLOCK_MAX)
return NULL;
rcu_read_lock();
p = lookup_task(pid, thread, gettime);
if (p && getref)
get_task_struct(p);
rcu_read_unlock();
return p;
}
static inline struct task_struct *get_task_for_clock(const clockid_t clock)
{
return __get_task_for_clock(clock, true, false);
}
static inline struct task_struct *get_task_for_clock_get(const clockid_t clock)
{
return __get_task_for_clock(clock, true, true);
/*
* For processes require that pid identifies a process.
*/
return pid_has_task(pid, PIDTYPE_TGID) ? pid : NULL;
}
static inline int validate_clock_permissions(const clockid_t clock)
{
return __get_task_for_clock(clock, false, false) ? 0 : -EINVAL;
int ret;
rcu_read_lock();
ret = pid_for_clock(clock, false) ? 0 : -EINVAL;
rcu_read_unlock();
return ret;
}
static inline enum pid_type cpu_timer_pid_type(struct k_itimer *timer)
static inline enum pid_type clock_pid_type(const clockid_t clock)
{
return CPUCLOCK_PERTHREAD(timer->it_clock) ? PIDTYPE_PID : PIDTYPE_TGID;
return CPUCLOCK_PERTHREAD(clock) ? PIDTYPE_PID : PIDTYPE_TGID;
}
static inline struct task_struct *cpu_timer_task_rcu(struct k_itimer *timer)
{
return pid_task(timer->it.cpu.pid, cpu_timer_pid_type(timer));
return pid_task(timer->it.cpu.pid, clock_pid_type(timer->it_clock));
}
/*
@@ -373,15 +353,18 @@ static int posix_cpu_clock_get(const clockid_t clock, struct timespec64 *tp)
struct task_struct *tsk;
u64 t;
tsk = get_task_for_clock_get(clock);
if (!tsk)
rcu_read_lock();
tsk = pid_task(pid_for_clock(clock, true), clock_pid_type(clock));
if (!tsk) {
rcu_read_unlock();
return -EINVAL;
}
if (CPUCLOCK_PERTHREAD(clock))
t = cpu_clock_sample(clkid, tsk);
else
t = cpu_clock_sample_group(clkid, tsk, false);
put_task_struct(tsk);
rcu_read_unlock();
*tp = ns_to_timespec64(t);
return 0;
@@ -394,19 +377,19 @@ static int posix_cpu_clock_get(const clockid_t clock, struct timespec64 *tp)
*/
static int posix_cpu_timer_create(struct k_itimer *new_timer)
{
struct task_struct *p = get_task_for_clock(new_timer->it_clock);
struct pid *pid;
if (!p)
rcu_read_lock();
pid = pid_for_clock(new_timer->it_clock, false);
if (!pid) {
rcu_read_unlock();
return -EINVAL;
}
new_timer->kclock = &clock_posix_cpu;
timerqueue_init(&new_timer->it.cpu.node);
new_timer->it.cpu.pid = get_task_pid(p, cpu_timer_pid_type(new_timer));
/*
* get_task_for_clock() took a reference on @p. Drop it as the timer
* holds a reference on the pid of @p.
*/
put_task_struct(p);
new_timer->it.cpu.pid = get_pid(pid);
rcu_read_unlock();
return 0;
}