1375 lines · 39.1 KB · C
RawDownload
/* Common capabilities, needed by capability.o. * *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License as published by *	the Free Software Foundation; either version 2 of the License, or *	(at your option) any later version. * */ #include <linux/capability.h>#include <linux/audit.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/lsm_hooks.h>#include <linux/file.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/pagemap.h>#include <linux/swap.h>#include <linux/skbuff.h>#include <linux/netlink.h>#include <linux/ptrace.h>#include <linux/xattr.h>#include <linux/hugetlb.h>#include <linux/mount.h>#include <linux/sched.h>#include <linux/prctl.h>#include <linux/securebits.h>#include <linux/user_namespace.h>#include <linux/binfmts.h>#include <linux/personality.h> /* * If a non-root user executes a setuid-root binary in * !secure(SECURE_NOROOT) mode, then we raise capabilities. * However if fE is also set, then the intent is for only * the file capabilities to be applied, and the setuid-root * bit is left on either to change the uid (plausible) or * to get full privilege on a kernel without file capabilities * support.  So in that case we do not raise capabilities. * * Warn if that happens, once per boot. */static void warn_setuid_and_fcaps_mixed(const char *fname){	static int warned;	if (!warned) {		printk(KERN_INFO "warning: `%s' has both setuid-root and"			" effective capabilities. Therefore not raising all"			" capabilities.\n", fname);		warned = 1;	}} /** * cap_capable - Determine whether a task has a particular effective capability * @cred: The credentials to use * @ns:  The user namespace in which we need the capability * @cap: The capability to check for * @audit: Whether to write an audit message or not * * Determine whether the nominated task has the specified capability amongst * its effective set, returning 0 if it does, -ve if it does not. * * NOTE WELL: cap_has_capability() cannot be used like the kernel's capable() * and has_capability() functions.  That is, it has the reverse semantics: * cap_has_capability() returns 0 when a task has a capability, but the * kernel's capable() and has_capability() returns 1 for this case. */int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,		int cap, int audit){	struct user_namespace *ns = targ_ns; 	/* See if cred has the capability in the target user namespace	 * by examining the target user namespace and all of the target	 * user namespace's parents.	 */	for (;;) {		/* Do we have the necessary capabilities? */		if (ns == cred->user_ns)			return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; 		/*		 * If we're already at a lower level than we're looking for,		 * we're done searching.		 */		if (ns->level <= cred->user_ns->level)			return -EPERM; 		/* 		 * The owner of the user namespace in the parent of the		 * user namespace has all caps.		 */		if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid))			return 0; 		/*		 * If you have a capability in a parent user ns, then you have		 * it over all children user namespaces as well.		 */		ns = ns->parent;	} 	/* We never get here */} /** * cap_settime - Determine whether the current process may set the system clock * @ts: The time to set * @tz: The timezone to set * * Determine whether the current process may set the system clock and timezone * information, returning 0 if permission granted, -ve if denied. */int cap_settime(const struct timespec64 *ts, const struct timezone *tz){	if (!capable(CAP_SYS_TIME))		return -EPERM;	return 0;} /** * cap_ptrace_access_check - Determine whether the current process may access *			   another * @child: The process to be accessed * @mode: The mode of attachment. * * If we are in the same or an ancestor user_ns and have all the target * task's capabilities, then ptrace access is allowed. * If we have the ptrace capability to the target user_ns, then ptrace * access is allowed. * Else denied. * * Determine whether a process may access another, returning 0 if permission * granted, -ve if denied. */int cap_ptrace_access_check(struct task_struct *child, unsigned int mode){	int ret = 0;	const struct cred *cred, *child_cred;	const kernel_cap_t *caller_caps; 	rcu_read_lock();	cred = current_cred();	child_cred = __task_cred(child);	if (mode & PTRACE_MODE_FSCREDS)		caller_caps = &cred->cap_effective;	else		caller_caps = &cred->cap_permitted;	if (cred->user_ns == child_cred->user_ns &&	    cap_issubset(child_cred->cap_permitted, *caller_caps))		goto out;	if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE))		goto out;	ret = -EPERM;out:	rcu_read_unlock();	return ret;} /** * cap_ptrace_traceme - Determine whether another process may trace the current * @parent: The task proposed to be the tracer * * If parent is in the same or an ancestor user_ns and has all current's * capabilities, then ptrace access is allowed. * If parent has the ptrace capability to current's user_ns, then ptrace * access is allowed. * Else denied. * * Determine whether the nominated task is permitted to trace the current * process, returning 0 if permission is granted, -ve if denied. */int cap_ptrace_traceme(struct task_struct *parent){	int ret = 0;	const struct cred *cred, *child_cred; 	rcu_read_lock();	cred = __task_cred(parent);	child_cred = current_cred();	if (cred->user_ns == child_cred->user_ns &&	    cap_issubset(child_cred->cap_permitted, cred->cap_permitted))		goto out;	if (has_ns_capability(parent, child_cred->user_ns, CAP_SYS_PTRACE))		goto out;	ret = -EPERM;out:	rcu_read_unlock();	return ret;} /** * cap_capget - Retrieve a task's capability sets * @target: The task from which to retrieve the capability sets * @effective: The place to record the effective set * @inheritable: The place to record the inheritable set * @permitted: The place to record the permitted set * * This function retrieves the capabilities of the nominated task and returns * them to the caller. */int cap_capget(struct task_struct *target, kernel_cap_t *effective,	       kernel_cap_t *inheritable, kernel_cap_t *permitted){	const struct cred *cred; 	/* Derived from kernel/capability.c:sys_capget. */	rcu_read_lock();	cred = __task_cred(target);	*effective   = cred->cap_effective;	*inheritable = cred->cap_inheritable;	*permitted   = cred->cap_permitted;	rcu_read_unlock();	return 0;} /* * Determine whether the inheritable capabilities are limited to the old * permitted set.  Returns 1 if they are limited, 0 if they are not. */static inline int cap_inh_is_capped(void){ 	/* they are so limited unless the current task has the CAP_SETPCAP	 * capability	 */	if (cap_capable(current_cred(), current_cred()->user_ns,			CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)		return 0;	return 1;} /** * cap_capset - Validate and apply proposed changes to current's capabilities * @new: The proposed new credentials; alterations should be made here * @old: The current task's current credentials * @effective: A pointer to the proposed new effective capabilities set * @inheritable: A pointer to the proposed new inheritable capabilities set * @permitted: A pointer to the proposed new permitted capabilities set * * This function validates and applies a proposed mass change to the current * process's capability sets.  The changes are made to the proposed new * credentials, and assuming no error, will be committed by the caller of LSM. */int cap_capset(struct cred *new,	       const struct cred *old,	       const kernel_cap_t *effective,	       const kernel_cap_t *inheritable,	       const kernel_cap_t *permitted){	if (cap_inh_is_capped() &&	    !cap_issubset(*inheritable,			  cap_combine(old->cap_inheritable,				      old->cap_permitted)))		/* incapable of using this inheritable set */		return -EPERM; 	if (!cap_issubset(*inheritable,			  cap_combine(old->cap_inheritable,				      old->cap_bset)))		/* no new pI capabilities outside bounding set */		return -EPERM; 	/* verify restrictions on target's new Permitted set */	if (!cap_issubset(*permitted, old->cap_permitted))		return -EPERM; 	/* verify the _new_Effective_ is a subset of the _new_Permitted_ */	if (!cap_issubset(*effective, *permitted))		return -EPERM; 	new->cap_effective   = *effective;	new->cap_inheritable = *inheritable;	new->cap_permitted   = *permitted; 	/*	 * Mask off ambient bits that are no longer both permitted and	 * inheritable.	 */	new->cap_ambient = cap_intersect(new->cap_ambient,					 cap_intersect(*permitted,						       *inheritable));	if (WARN_ON(!cap_ambient_invariant_ok(new)))		return -EINVAL;	return 0;} /** * cap_inode_need_killpriv - Determine if inode change affects privileges * @dentry: The inode/dentry in being changed with change marked ATTR_KILL_PRIV * * Determine if an inode having a change applied that's marked ATTR_KILL_PRIV * affects the security markings on that inode, and if it is, should * inode_killpriv() be invoked or the change rejected. * * Returns 1 if security.capability has a value, meaning inode_killpriv() * is required, 0 otherwise, meaning inode_killpriv() is not required. */int cap_inode_need_killpriv(struct dentry *dentry){	struct inode *inode = d_backing_inode(dentry);	int error; 	error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);	return error > 0;} /** * cap_inode_killpriv - Erase the security markings on an inode * @dentry: The inode/dentry to alter * * Erase the privilege-enhancing security markings on an inode. * * Returns 0 if successful, -ve on error. */int cap_inode_killpriv(struct dentry *dentry){	int error; 	error = __vfs_removexattr(dentry, XATTR_NAME_CAPS);	if (error == -EOPNOTSUPP)		error = 0;	return error;} static bool rootid_owns_currentns(kuid_t kroot){	struct user_namespace *ns; 	if (!uid_valid(kroot))		return false; 	for (ns = current_user_ns(); ; ns = ns->parent) {		if (from_kuid(ns, kroot) == 0)			return true;		if (ns == &init_user_ns)			break;	} 	return false;} static __u32 sansflags(__u32 m){	return m & ~VFS_CAP_FLAGS_EFFECTIVE;} static bool is_v2header(size_t size, const struct vfs_cap_data *cap){	if (size != XATTR_CAPS_SZ_2)		return false;	return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_2;} static bool is_v3header(size_t size, const struct vfs_cap_data *cap){	if (size != XATTR_CAPS_SZ_3)		return false;	return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_3;} /* * getsecurity: We are called for security.* before any attempt to read the * xattr from the inode itself. * * This gives us a chance to read the on-disk value and convert it.  If we * return -EOPNOTSUPP, then vfs_getxattr() will call the i_op handler. * * Note we are not called by vfs_getxattr_alloc(), but that is only called * by the integrity subsystem, which really wants the unconverted values - * so that's good. */int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,			  bool alloc){	int size, ret;	kuid_t kroot;	uid_t root, mappedroot;	char *tmpbuf = NULL;	struct vfs_cap_data *cap;	struct vfs_ns_cap_data *nscap;	struct dentry *dentry;	struct user_namespace *fs_ns; 	if (strcmp(name, "capability") != 0)		return -EOPNOTSUPP; 	dentry = d_find_alias(inode);	if (!dentry)		return -EINVAL; 	size = sizeof(struct vfs_ns_cap_data);	ret = (int) vfs_getxattr_alloc(dentry, XATTR_NAME_CAPS,				 &tmpbuf, size, GFP_NOFS);	dput(dentry); 	if (ret < 0)		return ret; 	fs_ns = inode->i_sb->s_user_ns;	cap = (struct vfs_cap_data *) tmpbuf;	if (is_v2header((size_t) ret, cap)) {		/* If this is sizeof(vfs_cap_data) then we're ok with the		 * on-disk value, so return that.  */		if (alloc)			*buffer = tmpbuf;		else			kfree(tmpbuf);		return ret;	} else if (!is_v3header((size_t) ret, cap)) {		kfree(tmpbuf);		return -EINVAL;	} 	nscap = (struct vfs_ns_cap_data *) tmpbuf;	root = le32_to_cpu(nscap->rootid);	kroot = make_kuid(fs_ns, root); 	/* If the root kuid maps to a valid uid in current ns, then return	 * this as a nscap. */	mappedroot = from_kuid(current_user_ns(), kroot);	if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) {		if (alloc) {			*buffer = tmpbuf;			nscap->rootid = cpu_to_le32(mappedroot);		} else			kfree(tmpbuf);		return size;	} 	if (!rootid_owns_currentns(kroot)) {		kfree(tmpbuf);		return -EOPNOTSUPP;	} 	/* This comes from a parent namespace.  Return as a v2 capability */	size = sizeof(struct vfs_cap_data);	if (alloc) {		*buffer = kmalloc(size, GFP_ATOMIC);		if (*buffer) {			struct vfs_cap_data *cap = *buffer;			__le32 nsmagic, magic;			magic = VFS_CAP_REVISION_2;			nsmagic = le32_to_cpu(nscap->magic_etc);			if (nsmagic & VFS_CAP_FLAGS_EFFECTIVE)				magic |= VFS_CAP_FLAGS_EFFECTIVE;			memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32);			cap->magic_etc = cpu_to_le32(magic);		} else {			size = -ENOMEM;		}	}	kfree(tmpbuf);	return size;} static kuid_t rootid_from_xattr(const void *value, size_t size,				struct user_namespace *task_ns){	const struct vfs_ns_cap_data *nscap = value;	uid_t rootid = 0; 	if (size == XATTR_CAPS_SZ_3)		rootid = le32_to_cpu(nscap->rootid); 	return make_kuid(task_ns, rootid);} static bool validheader(size_t size, const struct vfs_cap_data *cap){	return is_v2header(size, cap) || is_v3header(size, cap);} /* * User requested a write of security.capability.  If needed, update the * xattr to change from v2 to v3, or to fixup the v3 rootid. * * If all is ok, we return the new size, on error return < 0. */int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size){	struct vfs_ns_cap_data *nscap;	uid_t nsrootid;	const struct vfs_cap_data *cap = *ivalue;	__u32 magic, nsmagic;	struct inode *inode = d_backing_inode(dentry);	struct user_namespace *task_ns = current_user_ns(),		*fs_ns = inode->i_sb->s_user_ns;	kuid_t rootid;	size_t newsize; 	if (!*ivalue)		return -EINVAL;	if (!validheader(size, cap))		return -EINVAL;	if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP))		return -EPERM;

Lines 1–500 of 1375.