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

Merge tag 'pidfd.v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux

Pull pidfd updates from Christian Brauner:
"Various places in the kernel have picked up pidfds.

The two most recent additions have probably been the ability to use
pidfds in bpf maps and the usage of pidfds in mm-based syscalls such
as process_mrelease() and process_madvise().

The same pattern to turn a pidfd into a struct task exists in two
places. One of those places used PIDTYPE_TGID while the other one used
PIDTYPE_PID even though it is clearly documented in all pidfd-helpers
that pidfds __currently__ only refer to thread-group leaders (subject
to change in the future if need be).

This isn't a bug per se but has the potential to be one if we allow
pidfds to refer to individual threads. If that happens we want to
audit all codepaths that make use of them to ensure they can deal with
pidfds refering to individual threads.

This adds a simple helper to turn a pidfd into a struct task making it
easy to grep for such places. Plus, it gets rid of code-duplication"

* tag 'pidfd.v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux:
mm: use pidfd_get_task()
pid: add pidfd_get_task() helper

+43 -24
+1
include/linux/pid.h
··· 78 78 79 79 extern struct pid *pidfd_pid(const struct file *file); 80 80 struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags); 81 + struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags); 81 82 int pidfd_create(struct pid *pid, unsigned int flags); 82 83 83 84 static inline struct pid *get_pid(struct pid *pid)
+36
kernel/pid.c
··· 540 540 } 541 541 542 542 /** 543 + * pidfd_get_task() - Get the task associated with a pidfd 544 + * 545 + * @pidfd: pidfd for which to get the task 546 + * @flags: flags associated with this pidfd 547 + * 548 + * Return the task associated with @pidfd. The function takes a reference on 549 + * the returned task. The caller is responsible for releasing that reference. 550 + * 551 + * Currently, the process identified by @pidfd is always a thread-group leader. 552 + * This restriction currently exists for all aspects of pidfds including pidfd 553 + * creation (CLONE_PIDFD cannot be used with CLONE_THREAD) and pidfd polling 554 + * (only supports thread group leaders). 555 + * 556 + * Return: On success, the task_struct associated with the pidfd. 557 + * On error, a negative errno number will be returned. 558 + */ 559 + struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags) 560 + { 561 + unsigned int f_flags; 562 + struct pid *pid; 563 + struct task_struct *task; 564 + 565 + pid = pidfd_get_pid(pidfd, &f_flags); 566 + if (IS_ERR(pid)) 567 + return ERR_CAST(pid); 568 + 569 + task = get_pid_task(pid, PIDTYPE_TGID); 570 + put_pid(pid); 571 + if (!task) 572 + return ERR_PTR(-ESRCH); 573 + 574 + *flags = f_flags; 575 + return task; 576 + } 577 + 578 + /** 543 579 * pidfd_create() - Create a new pid file descriptor. 544 580 * 545 581 * @pid: struct pid that the pidfd will reference
+3 -12
mm/madvise.c
··· 1235 1235 struct iovec iovstack[UIO_FASTIOV], iovec; 1236 1236 struct iovec *iov = iovstack; 1237 1237 struct iov_iter iter; 1238 - struct pid *pid; 1239 1238 struct task_struct *task; 1240 1239 struct mm_struct *mm; 1241 1240 size_t total_len; ··· 1249 1250 if (ret < 0) 1250 1251 goto out; 1251 1252 1252 - pid = pidfd_get_pid(pidfd, &f_flags); 1253 - if (IS_ERR(pid)) { 1254 - ret = PTR_ERR(pid); 1253 + task = pidfd_get_task(pidfd, &f_flags); 1254 + if (IS_ERR(task)) { 1255 + ret = PTR_ERR(task); 1255 1256 goto free_iov; 1256 - } 1257 - 1258 - task = get_pid_task(pid, PIDTYPE_PID); 1259 - if (!task) { 1260 - ret = -ESRCH; 1261 - goto put_pid; 1262 1257 } 1263 1258 1264 1259 if (!process_madvise_behavior_valid(behavior)) { ··· 1294 1301 mmput(mm); 1295 1302 release_task: 1296 1303 put_task_struct(task); 1297 - put_pid: 1298 - put_pid(pid); 1299 1304 free_iov: 1300 1305 kfree(iov); 1301 1306 out:
+3 -12
mm/oom_kill.c
··· 1150 1150 struct task_struct *p; 1151 1151 unsigned int f_flags; 1152 1152 bool reap = false; 1153 - struct pid *pid; 1154 1153 long ret = 0; 1155 1154 1156 1155 if (flags) 1157 1156 return -EINVAL; 1158 1157 1159 - pid = pidfd_get_pid(pidfd, &f_flags); 1160 - if (IS_ERR(pid)) 1161 - return PTR_ERR(pid); 1162 - 1163 - task = get_pid_task(pid, PIDTYPE_TGID); 1164 - if (!task) { 1165 - ret = -ESRCH; 1166 - goto put_pid; 1167 - } 1158 + task = pidfd_get_task(pidfd, &f_flags); 1159 + if (IS_ERR(task)) 1160 + return PTR_ERR(task); 1168 1161 1169 1162 /* 1170 1163 * Make sure to choose a thread which still has a reference to mm ··· 1197 1204 mmput(mm); 1198 1205 put_task: 1199 1206 put_task_struct(task); 1200 - put_pid: 1201 - put_pid(pid); 1202 1207 return ret; 1203 1208 #else 1204 1209 return -ENOSYS;