mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	pselect6() and friends: take handling the combined 6th/7th args into helper
... and use unsafe_get_user(), while we are at it. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									b44f687386
								
							
						
					
					
						commit
						7e71609f64
					
				
					 1 changed files with 60 additions and 44 deletions
				
			
		
							
								
								
									
										104
									
								
								fs/select.c
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								fs/select.c
									
									
									
									
									
								
							|  | @ -766,22 +766,38 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp, | |||
|  * which has a pointer to the sigset_t itself followed by a size_t containing | ||||
|  * the sigset size. | ||||
|  */ | ||||
| struct sigset_argpack { | ||||
| 	sigset_t __user *p; | ||||
| 	size_t size; | ||||
| }; | ||||
| 
 | ||||
| static inline int get_sigset_argpack(struct sigset_argpack *to, | ||||
| 				     struct sigset_argpack __user *from) | ||||
| { | ||||
| 	// the path is hot enough for overhead of copy_from_user() to matter
 | ||||
| 	if (from) { | ||||
| 		if (!user_read_access_begin(from, sizeof(*from))) | ||||
| 			return -EFAULT; | ||||
| 		unsafe_get_user(to->p, &from->p, Efault); | ||||
| 		unsafe_get_user(to->size, &from->size, Efault); | ||||
| 		user_read_access_end(); | ||||
| 	} | ||||
| 	return 0; | ||||
| Efault: | ||||
| 	user_access_end(); | ||||
| 	return -EFAULT; | ||||
| } | ||||
| 
 | ||||
| SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp, | ||||
| 		fd_set __user *, exp, struct __kernel_timespec __user *, tsp, | ||||
| 		void __user *, sig) | ||||
| { | ||||
| 	size_t sigsetsize = 0; | ||||
| 	sigset_t __user *up = NULL; | ||||
| 	struct sigset_argpack x = {NULL, 0}; | ||||
| 
 | ||||
| 	if (sig) { | ||||
| 		if (!access_ok(sig, sizeof(void *)+sizeof(size_t)) | ||||
| 		    || __get_user(up, (sigset_t __user * __user *)sig) | ||||
| 		    || __get_user(sigsetsize, | ||||
| 				(size_t __user *)(sig+sizeof(void *)))) | ||||
| 			return -EFAULT; | ||||
| 	} | ||||
| 	if (get_sigset_argpack(&x, sig)) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize, PT_TIMESPEC); | ||||
| 	return do_pselect(n, inp, outp, exp, tsp, x.p, x.size, PT_TIMESPEC); | ||||
| } | ||||
| 
 | ||||
| #if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT) | ||||
|  | @ -790,18 +806,12 @@ SYSCALL_DEFINE6(pselect6_time32, int, n, fd_set __user *, inp, fd_set __user *, | |||
| 		fd_set __user *, exp, struct old_timespec32 __user *, tsp, | ||||
| 		void __user *, sig) | ||||
| { | ||||
| 	size_t sigsetsize = 0; | ||||
| 	sigset_t __user *up = NULL; | ||||
| 	struct sigset_argpack x = {NULL, 0}; | ||||
| 
 | ||||
| 	if (sig) { | ||||
| 		if (!access_ok(sig, sizeof(void *)+sizeof(size_t)) | ||||
| 		    || __get_user(up, (sigset_t __user * __user *)sig) | ||||
| 		    || __get_user(sigsetsize, | ||||
| 				(size_t __user *)(sig+sizeof(void *)))) | ||||
| 			return -EFAULT; | ||||
| 	} | ||||
| 	if (get_sigset_argpack(&x, sig)) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize, PT_OLD_TIMESPEC); | ||||
| 	return do_pselect(n, inp, outp, exp, tsp, x.p, x.size, PT_OLD_TIMESPEC); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1325,24 +1335,37 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp, | |||
| 	return poll_select_finish(&end_time, tsp, type, ret); | ||||
| } | ||||
| 
 | ||||
| struct compat_sigset_argpack { | ||||
| 	compat_uptr_t p; | ||||
| 	compat_size_t size; | ||||
| }; | ||||
| static inline int get_compat_sigset_argpack(struct compat_sigset_argpack *to, | ||||
| 					    struct compat_sigset_argpack __user *from) | ||||
| { | ||||
| 	if (from) { | ||||
| 		if (!user_read_access_begin(from, sizeof(*from))) | ||||
| 			return -EFAULT; | ||||
| 		unsafe_get_user(to->p, &from->p, Efault); | ||||
| 		unsafe_get_user(to->size, &from->size, Efault); | ||||
| 		user_read_access_end(); | ||||
| 	} | ||||
| 	return 0; | ||||
| Efault: | ||||
| 	user_access_end(); | ||||
| 	return -EFAULT; | ||||
| } | ||||
| 
 | ||||
| COMPAT_SYSCALL_DEFINE6(pselect6_time64, int, n, compat_ulong_t __user *, inp, | ||||
| 	compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, | ||||
| 	struct __kernel_timespec __user *, tsp, void __user *, sig) | ||||
| { | ||||
| 	compat_size_t sigsetsize = 0; | ||||
| 	compat_uptr_t up = 0; | ||||
| 	struct compat_sigset_argpack x = {0, 0}; | ||||
| 
 | ||||
| 	if (sig) { | ||||
| 		if (!access_ok(sig, | ||||
| 				sizeof(compat_uptr_t)+sizeof(compat_size_t)) || | ||||
| 				__get_user(up, (compat_uptr_t __user *)sig) || | ||||
| 				__get_user(sigsetsize, | ||||
| 				(compat_size_t __user *)(sig+sizeof(up)))) | ||||
| 			return -EFAULT; | ||||
| 	} | ||||
| 	if (get_compat_sigset_argpack(&x, sig)) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up), | ||||
| 				 sigsetsize, PT_TIMESPEC); | ||||
| 	return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(x.p), | ||||
| 				 x.size, PT_TIMESPEC); | ||||
| } | ||||
| 
 | ||||
| #if defined(CONFIG_COMPAT_32BIT_TIME) | ||||
|  | @ -1351,20 +1374,13 @@ COMPAT_SYSCALL_DEFINE6(pselect6_time32, int, n, compat_ulong_t __user *, inp, | |||
| 	compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, | ||||
| 	struct old_timespec32 __user *, tsp, void __user *, sig) | ||||
| { | ||||
| 	compat_size_t sigsetsize = 0; | ||||
| 	compat_uptr_t up = 0; | ||||
| 	struct compat_sigset_argpack x = {0, 0}; | ||||
| 
 | ||||
| 	if (sig) { | ||||
| 		if (!access_ok(sig, | ||||
| 				sizeof(compat_uptr_t)+sizeof(compat_size_t)) || | ||||
| 		    	__get_user(up, (compat_uptr_t __user *)sig) || | ||||
| 		    	__get_user(sigsetsize, | ||||
| 				(compat_size_t __user *)(sig+sizeof(up)))) | ||||
| 			return -EFAULT; | ||||
| 	} | ||||
| 	if (get_compat_sigset_argpack(&x, sig)) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up), | ||||
| 				 sigsetsize, PT_OLD_TIMESPEC); | ||||
| 	return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(x.p), | ||||
| 				 x.size, PT_OLD_TIMESPEC); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Al Viro
						Al Viro