2697 lines · 62.9 KB · C
RawDownload
			return -EFAULT; 		/* Last entry must be AT_NULL as specification requires */		user_auxv[AT_VECTOR_SIZE - 2] = AT_NULL;		user_auxv[AT_VECTOR_SIZE - 1] = AT_NULL;	} 	if (prctl_map.exe_fd != (u32)-1) {		/*		 * Check if the current user is checkpoint/restore capable.		 * At the time of this writing, it checks for CAP_SYS_ADMIN		 * or CAP_CHECKPOINT_RESTORE.		 * Note that a user with access to ptrace can masquerade an		 * arbitrary program as any executable, even setuid ones.		 * This may have implications in the tomoyo subsystem.		 */		if (!checkpoint_restore_ns_capable(current_user_ns()))			return -EPERM; 		error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd);		if (error)			return error;	} 	/*	 * arg_lock protects concurent updates but we still need mmap_lock for	 * read to exclude races with sys_brk.	 */	mmap_read_lock(mm); 	/*	 * We don't validate if these members are pointing to	 * real present VMAs because application may have correspond	 * VMAs already unmapped and kernel uses these members for statistics	 * output in procfs mostly, except	 *	 *  - @start_brk/@brk which are used in do_brk but kernel lookups	 *    for VMAs when updating these memvers so anything wrong written	 *    here cause kernel to swear at userspace program but won't lead	 *    to any problem in kernel itself	 */ 	spin_lock(&mm->arg_lock);	mm->start_code	= prctl_map.start_code;	mm->end_code	= prctl_map.end_code;	mm->start_data	= prctl_map.start_data;	mm->end_data	= prctl_map.end_data;	mm->start_brk	= prctl_map.start_brk;	mm->brk		= prctl_map.brk;	mm->start_stack	= prctl_map.start_stack;	mm->arg_start	= prctl_map.arg_start;	mm->arg_end	= prctl_map.arg_end;	mm->env_start	= prctl_map.env_start;	mm->env_end	= prctl_map.env_end;	spin_unlock(&mm->arg_lock); 	/*	 * Note this update of @saved_auxv is lockless thus	 * if someone reads this member in procfs while we're	 * updating -- it may get partly updated results. It's	 * known and acceptable trade off: we leave it as is to	 * not introduce additional locks here making the kernel	 * more complex.	 */	if (prctl_map.auxv_size)		memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv)); 	mmap_read_unlock(mm);	return 0;}#endif /* CONFIG_CHECKPOINT_RESTORE */ static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr,			  unsigned long len){	/*	 * This doesn't move the auxiliary vector itself since it's pinned to	 * mm_struct, but it permits filling the vector with new values.  It's	 * up to the caller to provide sane values here, otherwise userspace	 * tools which use this vector might be unhappy.	 */	unsigned long user_auxv[AT_VECTOR_SIZE]; 	if (len > sizeof(user_auxv))		return -EINVAL; 	if (copy_from_user(user_auxv, (const void __user *)addr, len))		return -EFAULT; 	/* Make sure the last entry is always AT_NULL */	user_auxv[AT_VECTOR_SIZE - 2] = 0;	user_auxv[AT_VECTOR_SIZE - 1] = 0; 	BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv)); 	task_lock(current);	memcpy(mm->saved_auxv, user_auxv, len);	task_unlock(current); 	return 0;} static int prctl_set_mm(int opt, unsigned long addr,			unsigned long arg4, unsigned long arg5){	struct mm_struct *mm = current->mm;	struct prctl_mm_map prctl_map = {		.auxv = NULL,		.auxv_size = 0,		.exe_fd = -1,	};	struct vm_area_struct *vma;	int error; 	if (arg5 || (arg4 && (opt != PR_SET_MM_AUXV &&			      opt != PR_SET_MM_MAP &&			      opt != PR_SET_MM_MAP_SIZE)))		return -EINVAL; #ifdef CONFIG_CHECKPOINT_RESTORE	if (opt == PR_SET_MM_MAP || opt == PR_SET_MM_MAP_SIZE)		return prctl_set_mm_map(opt, (const void __user *)addr, arg4);#endif 	if (!capable(CAP_SYS_RESOURCE))		return -EPERM; 	if (opt == PR_SET_MM_EXE_FILE)		return prctl_set_mm_exe_file(mm, (unsigned int)addr); 	if (opt == PR_SET_MM_AUXV)		return prctl_set_auxv(mm, addr, arg4); 	if (addr >= TASK_SIZE || addr < mmap_min_addr)		return -EINVAL; 	error = -EINVAL; 	/*	 * arg_lock protects concurent updates of arg boundaries, we need	 * mmap_lock for a) concurrent sys_brk, b) finding VMA for addr	 * validation.	 */	mmap_read_lock(mm);	vma = find_vma(mm, addr); 	spin_lock(&mm->arg_lock);	prctl_map.start_code	= mm->start_code;	prctl_map.end_code	= mm->end_code;	prctl_map.start_data	= mm->start_data;	prctl_map.end_data	= mm->end_data;	prctl_map.start_brk	= mm->start_brk;	prctl_map.brk		= mm->brk;	prctl_map.start_stack	= mm->start_stack;	prctl_map.arg_start	= mm->arg_start;	prctl_map.arg_end	= mm->arg_end;	prctl_map.env_start	= mm->env_start;	prctl_map.env_end	= mm->env_end; 	switch (opt) {	case PR_SET_MM_START_CODE:		prctl_map.start_code = addr;		break;	case PR_SET_MM_END_CODE:		prctl_map.end_code = addr;		break;	case PR_SET_MM_START_DATA:		prctl_map.start_data = addr;		break;	case PR_SET_MM_END_DATA:		prctl_map.end_data = addr;		break;	case PR_SET_MM_START_STACK:		prctl_map.start_stack = addr;		break;	case PR_SET_MM_START_BRK:		prctl_map.start_brk = addr;		break;	case PR_SET_MM_BRK:		prctl_map.brk = addr;		break;	case PR_SET_MM_ARG_START:		prctl_map.arg_start = addr;		break;	case PR_SET_MM_ARG_END:		prctl_map.arg_end = addr;		break;	case PR_SET_MM_ENV_START:		prctl_map.env_start = addr;		break;	case PR_SET_MM_ENV_END:		prctl_map.env_end = addr;		break;	default:		goto out;	} 	error = validate_prctl_map_addr(&prctl_map);	if (error)		goto out; 	switch (opt) {	/*	 * If command line arguments and environment	 * are placed somewhere else on stack, we can	 * set them up here, ARG_START/END to setup	 * command line argumets and ENV_START/END	 * for environment.	 */	case PR_SET_MM_START_STACK:	case PR_SET_MM_ARG_START:	case PR_SET_MM_ARG_END:	case PR_SET_MM_ENV_START:	case PR_SET_MM_ENV_END:		if (!vma) {			error = -EFAULT;			goto out;		}	} 	mm->start_code	= prctl_map.start_code;	mm->end_code	= prctl_map.end_code;	mm->start_data	= prctl_map.start_data;	mm->end_data	= prctl_map.end_data;	mm->start_brk	= prctl_map.start_brk;	mm->brk		= prctl_map.brk;	mm->start_stack	= prctl_map.start_stack;	mm->arg_start	= prctl_map.arg_start;	mm->arg_end	= prctl_map.arg_end;	mm->env_start	= prctl_map.env_start;	mm->env_end	= prctl_map.env_end; 	error = 0;out:	spin_unlock(&mm->arg_lock);	mmap_read_unlock(mm);	return error;} #ifdef CONFIG_CHECKPOINT_RESTOREstatic int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr){	return put_user(me->clear_child_tid, tid_addr);}#elsestatic int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr){	return -EINVAL;}#endif static int propagate_has_child_subreaper(struct task_struct *p, void *data){	/*	 * If task has has_child_subreaper - all its decendants	 * already have these flag too and new decendants will	 * inherit it on fork, skip them.	 *	 * If we've found child_reaper - skip descendants in	 * it's subtree as they will never get out pidns.	 */	if (p->signal->has_child_subreaper ||	    is_child_reaper(task_pid(p)))		return 0; 	p->signal->has_child_subreaper = 1;	return 1;} int __weak arch_prctl_spec_ctrl_get(struct task_struct *t, unsigned long which){	return -EINVAL;} int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which,				    unsigned long ctrl){	return -EINVAL;} #define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE) SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,		unsigned long, arg4, unsigned long, arg5){	struct task_struct *me = current;	unsigned char comm[sizeof(me->comm)];	long error; 	error = security_task_prctl(option, arg2, arg3, arg4, arg5);	if (error != -ENOSYS)		return error; 	error = 0;	switch (option) {	case PR_SET_PDEATHSIG:		if (!valid_signal(arg2)) {			error = -EINVAL;			break;		}		me->pdeath_signal = arg2;		break;	case PR_GET_PDEATHSIG:		error = put_user(me->pdeath_signal, (int __user *)arg2);		break;	case PR_GET_DUMPABLE:		error = get_dumpable(me->mm);		break;	case PR_SET_DUMPABLE:		if (arg2 != SUID_DUMP_DISABLE && arg2 != SUID_DUMP_USER) {			error = -EINVAL;			break;		}		set_dumpable(me->mm, arg2);		break; 	case PR_SET_UNALIGN:		error = SET_UNALIGN_CTL(me, arg2);		break;	case PR_GET_UNALIGN:		error = GET_UNALIGN_CTL(me, arg2);		break;	case PR_SET_FPEMU:		error = SET_FPEMU_CTL(me, arg2);		break;	case PR_GET_FPEMU:		error = GET_FPEMU_CTL(me, arg2);		break;	case PR_SET_FPEXC:		error = SET_FPEXC_CTL(me, arg2);		break;	case PR_GET_FPEXC:		error = GET_FPEXC_CTL(me, arg2);		break;	case PR_GET_TIMING:		error = PR_TIMING_STATISTICAL;		break;	case PR_SET_TIMING:		if (arg2 != PR_TIMING_STATISTICAL)			error = -EINVAL;		break;	case PR_SET_NAME:		comm[sizeof(me->comm) - 1] = 0;		if (strncpy_from_user(comm, (char __user *)arg2,				      sizeof(me->comm) - 1) < 0)			return -EFAULT;		set_task_comm(me, comm);		proc_comm_connector(me);		break;	case PR_GET_NAME:		get_task_comm(comm, me);		if (copy_to_user((char __user *)arg2, comm, sizeof(comm)))			return -EFAULT;		break;	case PR_GET_ENDIAN:		error = GET_ENDIAN(me, arg2);		break;	case PR_SET_ENDIAN:		error = SET_ENDIAN(me, arg2);		break;	case PR_GET_SECCOMP:		error = prctl_get_seccomp();		break;	case PR_SET_SECCOMP:		error = prctl_set_seccomp(arg2, (char __user *)arg3);		break;	case PR_GET_TSC:		error = GET_TSC_CTL(arg2);		break;	case PR_SET_TSC:		error = SET_TSC_CTL(arg2);		break;	case PR_TASK_PERF_EVENTS_DISABLE:		error = perf_event_task_disable();		break;	case PR_TASK_PERF_EVENTS_ENABLE:		error = perf_event_task_enable();		break;	case PR_GET_TIMERSLACK:		if (current->timer_slack_ns > ULONG_MAX)			error = ULONG_MAX;		else			error = current->timer_slack_ns;		break;	case PR_SET_TIMERSLACK:		if (arg2 <= 0)			current->timer_slack_ns =					current->default_timer_slack_ns;		else			current->timer_slack_ns = arg2;		break;	case PR_MCE_KILL:		if (arg4 | arg5)			return -EINVAL;		switch (arg2) {		case PR_MCE_KILL_CLEAR:			if (arg3 != 0)				return -EINVAL;			current->flags &= ~PF_MCE_PROCESS;			break;		case PR_MCE_KILL_SET:			current->flags |= PF_MCE_PROCESS;			if (arg3 == PR_MCE_KILL_EARLY)				current->flags |= PF_MCE_EARLY;			else if (arg3 == PR_MCE_KILL_LATE)				current->flags &= ~PF_MCE_EARLY;			else if (arg3 == PR_MCE_KILL_DEFAULT)				current->flags &=						~(PF_MCE_EARLY|PF_MCE_PROCESS);			else				return -EINVAL;			break;		default:			return -EINVAL;		}		break;	case PR_MCE_KILL_GET:		if (arg2 | arg3 | arg4 | arg5)			return -EINVAL;		if (current->flags & PF_MCE_PROCESS)			error = (current->flags & PF_MCE_EARLY) ?				PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE;		else			error = PR_MCE_KILL_DEFAULT;		break;	case PR_SET_MM:		error = prctl_set_mm(arg2, arg3, arg4, arg5);		break;	case PR_GET_TID_ADDRESS:		error = prctl_get_tid_address(me, (int __user **)arg2);		break;	case PR_SET_CHILD_SUBREAPER:		me->signal->is_child_subreaper = !!arg2;		if (!arg2)			break; 		walk_process_tree(me, propagate_has_child_subreaper, NULL);		break;	case PR_GET_CHILD_SUBREAPER:		error = put_user(me->signal->is_child_subreaper,				 (int __user *)arg2);		break;	case PR_SET_NO_NEW_PRIVS:		if (arg2 != 1 || arg3 || arg4 || arg5)			return -EINVAL; 		task_set_no_new_privs(current);		break;	case PR_GET_NO_NEW_PRIVS:		if (arg2 || arg3 || arg4 || arg5)			return -EINVAL;		return task_no_new_privs(current) ? 1 : 0;	case PR_GET_THP_DISABLE:		if (arg2 || arg3 || arg4 || arg5)			return -EINVAL;		error = !!test_bit(MMF_DISABLE_THP, &me->mm->flags);		break;	case PR_SET_THP_DISABLE:		if (arg3 || arg4 || arg5)			return -EINVAL;		if (mmap_write_lock_killable(me->mm))			return -EINTR;		if (arg2)			set_bit(MMF_DISABLE_THP, &me->mm->flags);		else			clear_bit(MMF_DISABLE_THP, &me->mm->flags);		mmap_write_unlock(me->mm);		break;	case PR_MPX_ENABLE_MANAGEMENT:	case PR_MPX_DISABLE_MANAGEMENT:		/* No longer implemented: */		return -EINVAL;	case PR_SET_FP_MODE:		error = SET_FP_MODE(me, arg2);		break;	case PR_GET_FP_MODE:		error = GET_FP_MODE(me);		break;	case PR_SVE_SET_VL:		error = SVE_SET_VL(arg2);		break;	case PR_SVE_GET_VL:		error = SVE_GET_VL();		break;	case PR_GET_SPECULATION_CTRL:		if (arg3 || arg4 || arg5)			return -EINVAL;		error = arch_prctl_spec_ctrl_get(me, arg2);		break;	case PR_SET_SPECULATION_CTRL:		if (arg4 || arg5)			return -EINVAL;		error = arch_prctl_spec_ctrl_set(me, arg2, arg3);		break;	case PR_PAC_RESET_KEYS:		if (arg3 || arg4 || arg5)			return -EINVAL;		error = PAC_RESET_KEYS(me, arg2);		break;	case PR_SET_TAGGED_ADDR_CTRL:

Lines 2001–2500 of 2697. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t