mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	pidfd: add PIDFD_SELF* sentinels to refer to own thread/process
It is useful to be able to utilise the pidfd mechanism to reference the current thread or process (from a userland point of view - thread group leader from the kernel's point of view). Therefore introduce PIDFD_SELF_THREAD to refer to the current thread, and PIDFD_SELF_THREAD_GROUP to refer to the current thread group leader. For convenience and to avoid confusion from userland's perspective we alias these: * PIDFD_SELF is an alias for PIDFD_SELF_THREAD - This is nearly always what the user will want to use, as they would find it surprising if for instance fd's were unshared()'d and they wanted to invoke pidfd_getfd() and that failed. * PIDFD_SELF_PROCESS is an alias for PIDFD_SELF_THREAD_GROUP - Most users have no concept of thread groups or what a thread group leader is, and from userland's perspective and nomenclature this is what userland considers to be a process. We adjust pidfd_get_task() and the pidfd_send_signal() system call with specific handling for this, implementing this functionality for process_madvise(), process_mrelease() (albeit, using it here wouldn't really make sense) and pidfd_send_signal(). Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Link: https://lore.kernel.org/r/24315a16a3d01a548dd45c7515f7d51c767e954e.1738268370.git.lorenzo.stoakes@oracle.com Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
		
							parent
							
								
									2014c95afe
								
							
						
					
					
						commit
						f08d0c3a71
					
				
					 3 changed files with 112 additions and 53 deletions
				
			
		|  | @ -23,6 +23,30 @@ | ||||||
| 
 | 
 | ||||||
| #define PIDFD_INFO_SIZE_VER0		64 /* sizeof first published struct */ | #define PIDFD_INFO_SIZE_VER0		64 /* sizeof first published struct */ | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * The concept of process and threads in userland and the kernel is a confusing | ||||||
|  |  * one - within the kernel every thread is a 'task' with its own individual PID, | ||||||
|  |  * however from userland's point of view threads are grouped by a single PID, | ||||||
|  |  * which is that of the 'thread group leader', typically the first thread | ||||||
|  |  * spawned. | ||||||
|  |  * | ||||||
|  |  * To cut the Gideon knot, for internal kernel usage, we refer to | ||||||
|  |  * PIDFD_SELF_THREAD to refer to the current thread (or task from a kernel | ||||||
|  |  * perspective), and PIDFD_SELF_THREAD_GROUP to refer to the current thread | ||||||
|  |  * group leader... | ||||||
|  |  */ | ||||||
|  | #define PIDFD_SELF_THREAD		-10000 /* Current thread. */ | ||||||
|  | #define PIDFD_SELF_THREAD_GROUP		-20000 /* Current thread group leader. */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * ...and for userland we make life simpler - PIDFD_SELF refers to the current | ||||||
|  |  * thread, PIDFD_SELF_PROCESS refers to the process thread group leader. | ||||||
|  |  * | ||||||
|  |  * For nearly all practical uses, a user will want to use PIDFD_SELF. | ||||||
|  |  */ | ||||||
|  | #define PIDFD_SELF		PIDFD_SELF_THREAD | ||||||
|  | #define PIDFD_SELF_PROCESS	PIDFD_SELF_THREAD_GROUP | ||||||
|  | 
 | ||||||
| struct pidfd_info { | struct pidfd_info { | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * This mask is similar to the request_mask in statx(2). | 	 * This mask is similar to the request_mask in statx(2). | ||||||
|  |  | ||||||
							
								
								
									
										24
									
								
								kernel/pid.c
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								kernel/pid.c
									
									
									
									
									
								
							|  | @ -564,15 +564,29 @@ struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags) | ||||||
|  */ |  */ | ||||||
| struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags) | struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags) | ||||||
| { | { | ||||||
| 	unsigned int f_flags; | 	unsigned int f_flags = 0; | ||||||
| 	struct pid *pid; | 	struct pid *pid; | ||||||
| 	struct task_struct *task; | 	struct task_struct *task; | ||||||
|  | 	enum pid_type type; | ||||||
| 
 | 
 | ||||||
| 	pid = pidfd_get_pid(pidfd, &f_flags); | 	switch (pidfd) { | ||||||
| 	if (IS_ERR(pid)) | 	case  PIDFD_SELF_THREAD: | ||||||
| 		return ERR_CAST(pid); | 		type = PIDTYPE_PID; | ||||||
|  | 		pid = get_task_pid(current, type); | ||||||
|  | 		break; | ||||||
|  | 	case  PIDFD_SELF_THREAD_GROUP: | ||||||
|  | 		type = PIDTYPE_TGID; | ||||||
|  | 		pid = get_task_pid(current, type); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		pid = pidfd_get_pid(pidfd, &f_flags); | ||||||
|  | 		if (IS_ERR(pid)) | ||||||
|  | 			return ERR_CAST(pid); | ||||||
|  | 		type = PIDTYPE_TGID; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	task = get_pid_task(pid, PIDTYPE_TGID); | 	task = get_pid_task(pid, type); | ||||||
| 	put_pid(pid); | 	put_pid(pid); | ||||||
| 	if (!task) | 	if (!task) | ||||||
| 		return ERR_PTR(-ESRCH); | 		return ERR_PTR(-ESRCH); | ||||||
|  |  | ||||||
							
								
								
									
										117
									
								
								kernel/signal.c
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								kernel/signal.c
									
									
									
									
									
								
							|  | @ -4009,56 +4009,12 @@ static struct pid *pidfd_to_pid(const struct file *file) | ||||||
| 	(PIDFD_SIGNAL_THREAD | PIDFD_SIGNAL_THREAD_GROUP | \ | 	(PIDFD_SIGNAL_THREAD | PIDFD_SIGNAL_THREAD_GROUP | \ | ||||||
| 	 PIDFD_SIGNAL_PROCESS_GROUP) | 	 PIDFD_SIGNAL_PROCESS_GROUP) | ||||||
| 
 | 
 | ||||||
| /**
 | static int do_pidfd_send_signal(struct pid *pid, int sig, enum pid_type type, | ||||||
|  * sys_pidfd_send_signal - Signal a process through a pidfd | 				siginfo_t __user *info, unsigned int flags) | ||||||
|  * @pidfd:  file descriptor of the process |  | ||||||
|  * @sig:    signal to send |  | ||||||
|  * @info:   signal info |  | ||||||
|  * @flags:  future flags |  | ||||||
|  * |  | ||||||
|  * Send the signal to the thread group or to the individual thread depending |  | ||||||
|  * on PIDFD_THREAD. |  | ||||||
|  * In the future extension to @flags may be used to override the default scope |  | ||||||
|  * of @pidfd. |  | ||||||
|  * |  | ||||||
|  * Return: 0 on success, negative errno on failure |  | ||||||
|  */ |  | ||||||
| SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig, |  | ||||||
| 		siginfo_t __user *, info, unsigned int, flags) |  | ||||||
| { | { | ||||||
| 	int ret; |  | ||||||
| 	struct pid *pid; |  | ||||||
| 	kernel_siginfo_t kinfo; | 	kernel_siginfo_t kinfo; | ||||||
| 	enum pid_type type; |  | ||||||
| 
 |  | ||||||
| 	/* Enforce flags be set to 0 until we add an extension. */ |  | ||||||
| 	if (flags & ~PIDFD_SEND_SIGNAL_FLAGS) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	/* Ensure that only a single signal scope determining flag is set. */ |  | ||||||
| 	if (hweight32(flags & PIDFD_SEND_SIGNAL_FLAGS) > 1) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	CLASS(fd, f)(pidfd); |  | ||||||
| 	if (fd_empty(f)) |  | ||||||
| 		return -EBADF; |  | ||||||
| 
 |  | ||||||
| 	/* Is this a pidfd? */ |  | ||||||
| 	pid = pidfd_to_pid(fd_file(f)); |  | ||||||
| 	if (IS_ERR(pid)) |  | ||||||
| 		return PTR_ERR(pid); |  | ||||||
| 
 |  | ||||||
| 	if (!access_pidfd_pidns(pid)) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 | 
 | ||||||
| 	switch (flags) { | 	switch (flags) { | ||||||
| 	case 0: |  | ||||||
| 		/* Infer scope from the type of pidfd. */ |  | ||||||
| 		if (fd_file(f)->f_flags & PIDFD_THREAD) |  | ||||||
| 			type = PIDTYPE_PID; |  | ||||||
| 		else |  | ||||||
| 			type = PIDTYPE_TGID; |  | ||||||
| 		break; |  | ||||||
| 	case PIDFD_SIGNAL_THREAD: | 	case PIDFD_SIGNAL_THREAD: | ||||||
| 		type = PIDTYPE_PID; | 		type = PIDTYPE_PID; | ||||||
| 		break; | 		break; | ||||||
|  | @ -4071,6 +4027,8 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (info) { | 	if (info) { | ||||||
|  | 		int ret; | ||||||
|  | 
 | ||||||
| 		ret = copy_siginfo_from_user_any(&kinfo, info); | 		ret = copy_siginfo_from_user_any(&kinfo, info); | ||||||
| 		if (unlikely(ret)) | 		if (unlikely(ret)) | ||||||
| 			return ret; | 			return ret; | ||||||
|  | @ -4088,8 +4046,71 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig, | ||||||
| 
 | 
 | ||||||
| 	if (type == PIDTYPE_PGID) | 	if (type == PIDTYPE_PGID) | ||||||
| 		return kill_pgrp_info(sig, &kinfo, pid); | 		return kill_pgrp_info(sig, &kinfo, pid); | ||||||
| 	else | 
 | ||||||
| 		return kill_pid_info_type(sig, &kinfo, pid, type); | 	return kill_pid_info_type(sig, &kinfo, pid, type); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * sys_pidfd_send_signal - Signal a process through a pidfd | ||||||
|  |  * @pidfd:  file descriptor of the process | ||||||
|  |  * @sig:    signal to send | ||||||
|  |  * @info:   signal info | ||||||
|  |  * @flags:  future flags | ||||||
|  |  * | ||||||
|  |  * Send the signal to the thread group or to the individual thread depending | ||||||
|  |  * on PIDFD_THREAD. | ||||||
|  |  * In the future extension to @flags may be used to override the default scope | ||||||
|  |  * of @pidfd. | ||||||
|  |  * | ||||||
|  |  * Return: 0 on success, negative errno on failure | ||||||
|  |  */ | ||||||
|  | SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig, | ||||||
|  | 		siginfo_t __user *, info, unsigned int, flags) | ||||||
|  | { | ||||||
|  | 	struct pid *pid; | ||||||
|  | 	enum pid_type type; | ||||||
|  | 
 | ||||||
|  | 	/* Enforce flags be set to 0 until we add an extension. */ | ||||||
|  | 	if (flags & ~PIDFD_SEND_SIGNAL_FLAGS) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	/* Ensure that only a single signal scope determining flag is set. */ | ||||||
|  | 	if (hweight32(flags & PIDFD_SEND_SIGNAL_FLAGS) > 1) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	switch (pidfd) { | ||||||
|  | 	case PIDFD_SELF_THREAD: | ||||||
|  | 		pid = get_task_pid(current, PIDTYPE_PID); | ||||||
|  | 		type = PIDTYPE_PID; | ||||||
|  | 		break; | ||||||
|  | 	case PIDFD_SELF_THREAD_GROUP: | ||||||
|  | 		pid = get_task_pid(current, PIDTYPE_TGID); | ||||||
|  | 		type = PIDTYPE_TGID; | ||||||
|  | 		break; | ||||||
|  | 	default: { | ||||||
|  | 		CLASS(fd, f)(pidfd); | ||||||
|  | 		if (fd_empty(f)) | ||||||
|  | 			return -EBADF; | ||||||
|  | 
 | ||||||
|  | 		/* Is this a pidfd? */ | ||||||
|  | 		pid = pidfd_to_pid(fd_file(f)); | ||||||
|  | 		if (IS_ERR(pid)) | ||||||
|  | 			return PTR_ERR(pid); | ||||||
|  | 
 | ||||||
|  | 		if (!access_pidfd_pidns(pid)) | ||||||
|  | 			return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 		/* Infer scope from the type of pidfd. */ | ||||||
|  | 		if (fd_file(f)->f_flags & PIDFD_THREAD) | ||||||
|  | 			type = PIDTYPE_PID; | ||||||
|  | 		else | ||||||
|  | 			type = PIDTYPE_TGID; | ||||||
|  | 
 | ||||||
|  | 		return do_pidfd_send_signal(pid, sig, type, info, flags); | ||||||
|  | 	} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return do_pidfd_send_signal(pid, sig, type, info, flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Lorenzo Stoakes
						Lorenzo Stoakes