diff options
Diffstat (limited to 'kernel/fork.c')
| -rw-r--r-- | kernel/fork.c | 24 | 
1 files changed, 17 insertions, 7 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 4385f3d639f2..48ed22774efa 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -2486,11 +2486,11 @@ long do_fork(unsigned long clone_flags,  	      int __user *child_tidptr)  {  	struct kernel_clone_args args = { -		.flags		= (clone_flags & ~CSIGNAL), +		.flags		= (lower_32_bits(clone_flags) & ~CSIGNAL),  		.pidfd		= parent_tidptr,  		.child_tid	= child_tidptr,  		.parent_tid	= parent_tidptr, -		.exit_signal	= (clone_flags & CSIGNAL), +		.exit_signal	= (lower_32_bits(clone_flags) & CSIGNAL),  		.stack		= stack_start,  		.stack_size	= stack_size,  	}; @@ -2508,8 +2508,9 @@ long do_fork(unsigned long clone_flags,  pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)  {  	struct kernel_clone_args args = { -		.flags		= ((flags | CLONE_VM | CLONE_UNTRACED) & ~CSIGNAL), -		.exit_signal	= (flags & CSIGNAL), +		.flags		= ((lower_32_bits(flags) | CLONE_VM | +				    CLONE_UNTRACED) & ~CSIGNAL), +		.exit_signal	= (lower_32_bits(flags) & CSIGNAL),  		.stack		= (unsigned long)fn,  		.stack_size	= (unsigned long)arg,  	}; @@ -2570,11 +2571,11 @@ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,  #endif  {  	struct kernel_clone_args args = { -		.flags		= (clone_flags & ~CSIGNAL), +		.flags		= (lower_32_bits(clone_flags) & ~CSIGNAL),  		.pidfd		= parent_tidptr,  		.child_tid	= child_tidptr,  		.parent_tid	= parent_tidptr, -		.exit_signal	= (clone_flags & CSIGNAL), +		.exit_signal	= (lower_32_bits(clone_flags) & CSIGNAL),  		.stack		= newsp,  		.tls		= tls,  	}; @@ -2605,6 +2606,14 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,  	struct clone_args args;  	pid_t *kset_tid = kargs->set_tid; +	BUILD_BUG_ON(offsetofend(struct clone_args, tls) != +		     CLONE_ARGS_SIZE_VER0); +	BUILD_BUG_ON(offsetofend(struct clone_args, set_tid_size) != +		     CLONE_ARGS_SIZE_VER1); +	BUILD_BUG_ON(offsetofend(struct clone_args, cgroup) != +		     CLONE_ARGS_SIZE_VER2); +	BUILD_BUG_ON(sizeof(struct clone_args) != CLONE_ARGS_SIZE_VER2); +  	if (unlikely(usize > PAGE_SIZE))  		return -E2BIG;  	if (unlikely(usize < CLONE_ARGS_SIZE_VER0)) @@ -2631,7 +2640,8 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,  		     !valid_signal(args.exit_signal)))  		return -EINVAL; -	if ((args.flags & CLONE_INTO_CGROUP) && args.cgroup < 0) +	if ((args.flags & CLONE_INTO_CGROUP) && +	    (args.cgroup > INT_MAX || usize < CLONE_ARGS_SIZE_VER2))  		return -EINVAL;  	*kargs = (struct kernel_clone_args){  | 
