Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

posix-cpu-timers: Use pids not tasks in lookup

The current posix-cpu-timer code uses pids when holding persistent
references in timers. However the lookups from clock_id_t still return
tasks that need to be converted into pids for use.

This results in usage being pid->task->pid and that can race with
release_task and de_thread. This can lead to some not wrong but
surprising results. Surprising enough that Oleg and I both thought
there were some bugs in the code for a while.

This set of changes modifies the code to just lookup, verify, and return
pids from the clockid_t lookups to remove those potentialy troublesome
races.

Eric W. Biederman (3):
posix-cpu-timers: Extend rcu_read_lock removing task_struct references
posix-cpu-timers: Replace cpu_timer_pid_type with clock_pid_type
posix-cpu-timers: Replace __get_task_for_clock with pid_for_clock

kernel/time/posix-cpu-timers.c | 102 ++++++++++++++++++-----------------------
1 file changed, 45 insertions(+), 57 deletions(-)

Suggested-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>

+51 -63
+51 -63
kernel/time/posix-cpu-timers.c
··· 47 47 /* 48 48 * Functions for validating access to tasks. 49 49 */ 50 - static struct task_struct *lookup_task(const pid_t pid, bool thread, 51 - bool gettime) 50 + static struct pid *pid_for_clock(const clockid_t clock, bool gettime) 52 51 { 53 - struct task_struct *p; 52 + const bool thread = !!CPUCLOCK_PERTHREAD(clock); 53 + const pid_t upid = CPUCLOCK_PID(clock); 54 + struct pid *pid; 55 + 56 + if (CPUCLOCK_WHICH(clock) >= CPUCLOCK_MAX) 57 + return NULL; 54 58 55 59 /* 56 60 * If the encoded PID is 0, then the timer is targeted at current 57 61 * or the process to which current belongs. 58 62 */ 63 + if (upid == 0) 64 + return thread ? task_pid(current) : task_tgid(current); 65 + 66 + pid = find_vpid(upid); 59 67 if (!pid) 60 - return thread ? current : current->group_leader; 61 - 62 - p = find_task_by_vpid(pid); 63 - if (!p) 64 - return p; 65 - 66 - if (thread) 67 - return same_thread_group(p, current) ? p : NULL; 68 - 69 - /* 70 - * For clock_gettime(PROCESS) the task does not need to be 71 - * the actual group leader. task->signal gives 72 - * access to the group's clock. 73 - */ 74 - if (gettime && (p == current)) 75 - return p; 76 - 77 - /* 78 - * For processes require that p is group leader. 79 - */ 80 - return thread_group_leader(p) ? p : NULL; 81 - } 82 - 83 - static struct task_struct *__get_task_for_clock(const clockid_t clock, 84 - bool getref, bool gettime) 85 - { 86 - const bool thread = !!CPUCLOCK_PERTHREAD(clock); 87 - const pid_t pid = CPUCLOCK_PID(clock); 88 - struct task_struct *p; 89 - 90 - if (CPUCLOCK_WHICH(clock) >= CPUCLOCK_MAX) 91 68 return NULL; 92 69 93 - rcu_read_lock(); 94 - p = lookup_task(pid, thread, gettime); 95 - if (p && getref) 96 - get_task_struct(p); 97 - rcu_read_unlock(); 98 - return p; 99 - } 70 + if (thread) { 71 + struct task_struct *tsk = pid_task(pid, PIDTYPE_PID); 72 + return (tsk && same_thread_group(tsk, current)) ? pid : NULL; 73 + } 100 74 101 - static inline struct task_struct *get_task_for_clock(const clockid_t clock) 102 - { 103 - return __get_task_for_clock(clock, true, false); 104 - } 75 + /* 76 + * For clock_gettime(PROCESS) allow finding the process by 77 + * with the pid of the current task. The code needs the tgid 78 + * of the process so that pid_task(pid, PIDTYPE_TGID) can be 79 + * used to find the process. 80 + */ 81 + if (gettime && (pid == task_pid(current))) 82 + return task_tgid(current); 105 83 106 - static inline struct task_struct *get_task_for_clock_get(const clockid_t clock) 107 - { 108 - return __get_task_for_clock(clock, true, true); 84 + /* 85 + * For processes require that pid identifies a process. 86 + */ 87 + return pid_has_task(pid, PIDTYPE_TGID) ? pid : NULL; 109 88 } 110 89 111 90 static inline int validate_clock_permissions(const clockid_t clock) 112 91 { 113 - return __get_task_for_clock(clock, false, false) ? 0 : -EINVAL; 92 + int ret; 93 + 94 + rcu_read_lock(); 95 + ret = pid_for_clock(clock, false) ? 0 : -EINVAL; 96 + rcu_read_unlock(); 97 + 98 + return ret; 114 99 } 115 100 116 - static inline enum pid_type cpu_timer_pid_type(struct k_itimer *timer) 101 + static inline enum pid_type clock_pid_type(const clockid_t clock) 117 102 { 118 - return CPUCLOCK_PERTHREAD(timer->it_clock) ? PIDTYPE_PID : PIDTYPE_TGID; 103 + return CPUCLOCK_PERTHREAD(clock) ? PIDTYPE_PID : PIDTYPE_TGID; 119 104 } 120 105 121 106 static inline struct task_struct *cpu_timer_task_rcu(struct k_itimer *timer) 122 107 { 123 - return pid_task(timer->it.cpu.pid, cpu_timer_pid_type(timer)); 108 + return pid_task(timer->it.cpu.pid, clock_pid_type(timer->it_clock)); 124 109 } 125 110 126 111 /* ··· 353 368 struct task_struct *tsk; 354 369 u64 t; 355 370 356 - tsk = get_task_for_clock_get(clock); 357 - if (!tsk) 371 + rcu_read_lock(); 372 + tsk = pid_task(pid_for_clock(clock, true), clock_pid_type(clock)); 373 + if (!tsk) { 374 + rcu_read_unlock(); 358 375 return -EINVAL; 376 + } 359 377 360 378 if (CPUCLOCK_PERTHREAD(clock)) 361 379 t = cpu_clock_sample(clkid, tsk); 362 380 else 363 381 t = cpu_clock_sample_group(clkid, tsk, false); 364 - put_task_struct(tsk); 382 + rcu_read_unlock(); 365 383 366 384 *tp = ns_to_timespec64(t); 367 385 return 0; ··· 377 389 */ 378 390 static int posix_cpu_timer_create(struct k_itimer *new_timer) 379 391 { 380 - struct task_struct *p = get_task_for_clock(new_timer->it_clock); 392 + struct pid *pid; 381 393 382 - if (!p) 394 + rcu_read_lock(); 395 + pid = pid_for_clock(new_timer->it_clock, false); 396 + if (!pid) { 397 + rcu_read_unlock(); 383 398 return -EINVAL; 399 + } 384 400 385 401 new_timer->kclock = &clock_posix_cpu; 386 402 timerqueue_init(&new_timer->it.cpu.node); 387 - new_timer->it.cpu.pid = get_task_pid(p, cpu_timer_pid_type(new_timer)); 388 - /* 389 - * get_task_for_clock() took a reference on @p. Drop it as the timer 390 - * holds a reference on the pid of @p. 391 - */ 392 - put_task_struct(p); 403 + new_timer->it.cpu.pid = get_pid(pid); 404 + rcu_read_unlock(); 393 405 return 0; 394 406 } 395 407