diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/capability.c | 227 | 
1 files changed, 23 insertions, 204 deletions
diff --git a/kernel/capability.c b/kernel/capability.c index adb262f83de..58b00519624 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -127,160 +127,6 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)  	return 0;  } -#ifndef CONFIG_SECURITY_FILE_CAPABILITIES - -/* - * Without filesystem capability support, we nominally support one process - * setting the capabilities of another - */ -static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, -				     kernel_cap_t *pIp, kernel_cap_t *pPp) -{ -	struct task_struct *target; -	int ret; - -	spin_lock(&task_capability_lock); -	read_lock(&tasklist_lock); - -	if (pid && pid != task_pid_vnr(current)) { -		target = find_task_by_vpid(pid); -		if (!target) { -			ret = -ESRCH; -			goto out; -		} -	} else -		target = current; - -	ret = security_capget(target, pEp, pIp, pPp); - -out: -	read_unlock(&tasklist_lock); -	spin_unlock(&task_capability_lock); - -	return ret; -} - -/* - * cap_set_pg - set capabilities for all processes in a given process - * group.  We call this holding task_capability_lock and tasklist_lock. - */ -static inline int cap_set_pg(int pgrp_nr, kernel_cap_t *effective, -			     kernel_cap_t *inheritable, -			     kernel_cap_t *permitted) -{ -	struct task_struct *g, *target; -	int ret = -EPERM; -	int found = 0; -	struct pid *pgrp; - -	spin_lock(&task_capability_lock); -	read_lock(&tasklist_lock); - -	pgrp = find_vpid(pgrp_nr); -	do_each_pid_task(pgrp, PIDTYPE_PGID, g) { -		target = g; -		while_each_thread(g, target) { -			if (!security_capset_check(target, effective, -						   inheritable, permitted)) { -				security_capset_set(target, effective, -						    inheritable, permitted); -				ret = 0; -			} -			found = 1; -		} -	} while_each_pid_task(pgrp, PIDTYPE_PGID, g); - -	read_unlock(&tasklist_lock); -	spin_unlock(&task_capability_lock); - -	if (!found) -		ret = 0; -	return ret; -} - -/* - * cap_set_all - set capabilities for all processes other than init - * and self.  We call this holding task_capability_lock and tasklist_lock. - */ -static inline int cap_set_all(kernel_cap_t *effective, -			      kernel_cap_t *inheritable, -			      kernel_cap_t *permitted) -{ -	struct task_struct *g, *target; -	int ret = -EPERM; -	int found = 0; - -	spin_lock(&task_capability_lock); -	read_lock(&tasklist_lock); - -	do_each_thread(g, target) { -		if (target == current -		    || is_container_init(target->group_leader)) -			continue; -		found = 1; -		if (security_capset_check(target, effective, inheritable, -					  permitted)) -			continue; -		ret = 0; -		security_capset_set(target, effective, inheritable, permitted); -	} while_each_thread(g, target); - -	read_unlock(&tasklist_lock); -	spin_unlock(&task_capability_lock); - -	if (!found) -		ret = 0; - -	return ret; -} - -/* - * Given the target pid does not refer to the current process we - * need more elaborate support... (This support is not present when - * filesystem capabilities are configured.) - */ -static inline int do_sys_capset_other_tasks(pid_t pid, kernel_cap_t *effective, -					    kernel_cap_t *inheritable, -					    kernel_cap_t *permitted) -{ -	struct task_struct *target; -	int ret; - -	if (!capable(CAP_SETPCAP)) -		return -EPERM; - -	if (pid == -1)	          /* all procs other than current and init */ -		return cap_set_all(effective, inheritable, permitted); - -	else if (pid < 0)                    /* all procs in process group */ -		return cap_set_pg(-pid, effective, inheritable, permitted); - -	/* target != current */ -	spin_lock(&task_capability_lock); -	read_lock(&tasklist_lock); - -	target = find_task_by_vpid(pid); -	if (!target) -		ret = -ESRCH; -	else { -		ret = security_capset_check(target, effective, inheritable, -					    permitted); - -		/* having verified that the proposed changes are legal, -		   we now put them into effect. */ -		if (!ret) -			security_capset_set(target, effective, inheritable, -					    permitted); -	} - -	read_unlock(&tasklist_lock); -	spin_unlock(&task_capability_lock); - -	return ret; -} - -#else /* ie., def CONFIG_SECURITY_FILE_CAPABILITIES */ -  /*   * If we have configured with filesystem capability support, then the   * only thing that can change the capabilities of the current process @@ -315,22 +161,6 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,  }  /* - * With filesystem capability support configured, the kernel does not - * permit the changing of capabilities in one process by another - * process. (CAP_SETPCAP has much less broad semantics when configured - * this way.) - */ -static inline int do_sys_capset_other_tasks(pid_t pid, -					    kernel_cap_t *effective, -					    kernel_cap_t *inheritable, -					    kernel_cap_t *permitted) -{ -	return -EPERM; -} - -#endif /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */ - -/*   * Atomically modify the effective capabilities returning the original   * value. No permission check is performed here - it is assumed that the   * caller is permitted to set the desired effective capabilities. @@ -424,16 +254,14 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)   * @data: pointer to struct that contains the effective, permitted,   *	and inheritable capabilities   * - * Set capabilities for a given process, all processes, or all - * processes in a given process group. + * Set capabilities for the current process only.  The ability to any other + * process(es) has been deprecated and removed.   *   * The restrictions on setting capabilities are specified as:   * - * [pid is for the 'target' task.  'current' is the calling task.] - * - * I: any raised capabilities must be a subset of the (old current) permitted - * P: any raised capabilities must be a subset of the (old current) permitted - * E: must be set to a subset of (new target) permitted + * I: any raised capabilities must be a subset of the old permitted + * P: any raised capabilities must be a subset of the old permitted + * E: must be set to a subset of new permitted   *   * Returns 0 on success and < 0 on error.   */ @@ -452,10 +280,13 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)  	if (get_user(pid, &header->pid))  		return -EFAULT; +	/* may only affect current now */ +	if (pid != 0 && pid != task_pid_vnr(current)) +		return -EPERM; +  	if (copy_from_user(&kdata, data, tocopy -			   * sizeof(struct __user_cap_data_struct))) { +			   * sizeof(struct __user_cap_data_struct)))  		return -EFAULT; -	}  	for (i = 0; i < tocopy; i++) {  		effective.cap[i] = kdata[i].effective; @@ -473,32 +304,20 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)  	if (ret)  		return ret; -	if (pid && (pid != task_pid_vnr(current))) -		ret = do_sys_capset_other_tasks(pid, &effective, &inheritable, -						&permitted); -	else { -		/* -		 * This lock is required even when filesystem -		 * capability support is configured - it protects the -		 * sys_capget() call from returning incorrect data in -		 * the case that the targeted process is not the -		 * current one. -		 */ -		spin_lock(&task_capability_lock); - -		ret = security_capset_check(current, &effective, &inheritable, -					    &permitted); -		/* -		 * Having verified that the proposed changes are -		 * legal, we now put them into effect. -		 */ -		if (!ret) -			security_capset_set(current, &effective, &inheritable, -					    &permitted); -		spin_unlock(&task_capability_lock); -	} - +	/* This lock is required even when filesystem capability support is +	 * configured - it protects the sys_capget() call from returning +	 * incorrect data in the case that the targeted process is not the +	 * current one. +	 */ +	spin_lock(&task_capability_lock); +	ret = security_capset_check(&effective, &inheritable, &permitted); +	/* Having verified that the proposed changes are legal, we now put them +	 * into effect. +	 */ +	if (!ret) +		security_capset_set(&effective, &inheritable, &permitted); +	spin_unlock(&task_capability_lock);  	return ret;  }  |