Commit f72dae20 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull selinux updates from Paul Moore:
 "We've got a few SELinux patches for the v5.2 merge window, the
  highlights are below:

   - Add LSM hooks, and the SELinux implementation, for proper labeling
     of kernfs. While we are only including the SELinux implementation
     here, the rest of the LSM folks have given the hooks a thumbs-up.

   - Update the SELinux mdp (Make Dummy Policy) script to actually work
     on a modern system.

   - Disallow userspace to change the LSM credentials via
     /proc/self/attr when the task's credentials are already overridden.

     The change was made in procfs because all the LSM folks agreed this
     was the Right Thing To Do and duplicating it across each LSM was
     going to be annoying"

* tag 'selinux-pr-20190507' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  proc: prevent changes to overridden credentials
  selinux: Check address length before reading address family
  kernfs: fix xattr name handling in LSM helpers
  MAINTAINERS: update SELinux file patterns
  selinux: avoid uninitialized variable warning
  selinux: remove useless assignments
  LSM: lsm_hooks.h - fix missing colon in docstring
  selinux: Make selinux_kernfs_init_security static
  kernfs: initialize security of newly created nodes
  selinux: implement the kernfs_init_security hook
  LSM: add new hook for kernfs node initialization
  kernfs: use simple_xattrs for security attributes
  selinux: try security xattr after genfs for kernfs filesystems
  kernfs: do not alloc iattrs in kernfs_xattr_get
  kernfs: clean up struct kernfs_iattrs
  scripts/selinux: fix build
  selinux: use kernel linux/socket.h for genheaders and mdp
  scripts/selinux: modernize mdp
parents 498e8631 35a196be
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -13994,7 +13994,7 @@ W: https://selinuxproject.org
W:	https://github.com/SELinuxProject
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
S:	Supported
F:	include/linux/selinux*
F:	include/uapi/linux/selinux_netlink.h
F:	security/selinux/
F:	scripts/selinux/
F:	Documentation/admin-guide/LSM/SELinux.rst
+13 −11
Original line number Diff line number Diff line
@@ -532,9 +532,6 @@ void kernfs_put(struct kernfs_node *kn)
	kfree_const(kn->name);

	if (kn->iattr) {
		if (kn->iattr->ia_secdata)
			security_release_secctx(kn->iattr->ia_secdata,
						kn->iattr->ia_secdata_len);
		simple_xattrs_free(&kn->iattr->xattrs);
		kmem_cache_free(kernfs_iattrs_cache, kn->iattr);
	}
@@ -618,6 +615,7 @@ struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry)
}

static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
					     struct kernfs_node *parent,
					     const char *name, umode_t mode,
					     kuid_t uid, kgid_t gid,
					     unsigned flags)
@@ -673,6 +671,12 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
			goto err_out3;
	}

	if (parent) {
		ret = security_kernfs_init_security(parent, kn);
		if (ret)
			goto err_out3;
	}

	return kn;

 err_out3:
@@ -691,7 +695,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
{
	struct kernfs_node *kn;

	kn = __kernfs_new_node(kernfs_root(parent),
	kn = __kernfs_new_node(kernfs_root(parent), parent,
			       name, mode, uid, gid, flags);
	if (kn) {
		kernfs_get(parent);
@@ -794,9 +798,8 @@ int kernfs_add_one(struct kernfs_node *kn)
	/* Update timestamps on the parent */
	ps_iattr = parent->iattr;
	if (ps_iattr) {
		struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
		ktime_get_real_ts64(&ps_iattrs->ia_ctime);
		ps_iattrs->ia_mtime = ps_iattrs->ia_ctime;
		ktime_get_real_ts64(&ps_iattr->ia_ctime);
		ps_iattr->ia_mtime = ps_iattr->ia_ctime;
	}

	mutex_unlock(&kernfs_mutex);
@@ -961,7 +964,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
	INIT_LIST_HEAD(&root->supers);
	root->next_generation = 1;

	kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO,
	kn = __kernfs_new_node(root, NULL, "", S_IFDIR | S_IRUGO | S_IXUGO,
			       GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
			       KERNFS_DIR);
	if (!kn) {
@@ -1328,9 +1331,8 @@ static void __kernfs_remove(struct kernfs_node *kn)

			/* update timestamps on the parent */
			if (ps_iattr) {
				ktime_get_real_ts64(&ps_iattr->ia_iattr.ia_ctime);
				ps_iattr->ia_iattr.ia_mtime =
					ps_iattr->ia_iattr.ia_ctime;
				ktime_get_real_ts64(&ps_iattr->ia_ctime);
				ps_iattr->ia_mtime = ps_iattr->ia_ctime;
			}

			kernfs_put(pos);
+62 −100
Original line number Diff line number Diff line
@@ -31,30 +31,27 @@ static const struct inode_operations kernfs_iops = {
	.listxattr	= kernfs_iop_listxattr,
};

static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
static struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, int alloc)
{
	static DEFINE_MUTEX(iattr_mutex);
	struct kernfs_iattrs *ret;
	struct iattr *iattrs;

	mutex_lock(&iattr_mutex);

	if (kn->iattr)
	if (kn->iattr || !alloc)
		goto out_unlock;

	kn->iattr = kmem_cache_zalloc(kernfs_iattrs_cache, GFP_KERNEL);
	if (!kn->iattr)
		goto out_unlock;
	iattrs = &kn->iattr->ia_iattr;

	/* assign default attributes */
	iattrs->ia_mode = kn->mode;
	iattrs->ia_uid = GLOBAL_ROOT_UID;
	iattrs->ia_gid = GLOBAL_ROOT_GID;
	kn->iattr->ia_uid = GLOBAL_ROOT_UID;
	kn->iattr->ia_gid = GLOBAL_ROOT_GID;

	ktime_get_real_ts64(&iattrs->ia_atime);
	iattrs->ia_mtime = iattrs->ia_atime;
	iattrs->ia_ctime = iattrs->ia_atime;
	ktime_get_real_ts64(&kn->iattr->ia_atime);
	kn->iattr->ia_mtime = kn->iattr->ia_atime;
	kn->iattr->ia_ctime = kn->iattr->ia_atime;

	simple_xattrs_init(&kn->iattr->xattrs);
out_unlock:
@@ -63,32 +60,37 @@ out_unlock:
	return ret;
}

static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
{
	return __kernfs_iattrs(kn, 1);
}

static struct kernfs_iattrs *kernfs_iattrs_noalloc(struct kernfs_node *kn)
{
	return __kernfs_iattrs(kn, 0);
}

int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
{
	struct kernfs_iattrs *attrs;
	struct iattr *iattrs;
	unsigned int ia_valid = iattr->ia_valid;

	attrs = kernfs_iattrs(kn);
	if (!attrs)
		return -ENOMEM;

	iattrs = &attrs->ia_iattr;

	if (ia_valid & ATTR_UID)
		iattrs->ia_uid = iattr->ia_uid;
		attrs->ia_uid = iattr->ia_uid;
	if (ia_valid & ATTR_GID)
		iattrs->ia_gid = iattr->ia_gid;
		attrs->ia_gid = iattr->ia_gid;
	if (ia_valid & ATTR_ATIME)
		iattrs->ia_atime = iattr->ia_atime;
		attrs->ia_atime = iattr->ia_atime;
	if (ia_valid & ATTR_MTIME)
		iattrs->ia_mtime = iattr->ia_mtime;
		attrs->ia_mtime = iattr->ia_mtime;
	if (ia_valid & ATTR_CTIME)
		iattrs->ia_ctime = iattr->ia_ctime;
	if (ia_valid & ATTR_MODE) {
		umode_t mode = iattr->ia_mode;
		iattrs->ia_mode = kn->mode = mode;
	}
		attrs->ia_ctime = iattr->ia_ctime;
	if (ia_valid & ATTR_MODE)
		kn->mode = iattr->ia_mode;
	return 0;
}

@@ -135,23 +137,6 @@ out:
	return error;
}

static int kernfs_node_setsecdata(struct kernfs_iattrs *attrs, void **secdata,
				  u32 *secdata_len)
{
	void *old_secdata;
	size_t old_secdata_len;

	old_secdata = attrs->ia_secdata;
	old_secdata_len = attrs->ia_secdata_len;

	attrs->ia_secdata = *secdata;
	attrs->ia_secdata_len = *secdata_len;

	*secdata = old_secdata;
	*secdata_len = old_secdata_len;
	return 0;
}

ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
{
	struct kernfs_node *kn = kernfs_dentry_node(dentry);
@@ -171,14 +156,15 @@ static inline void set_default_inode_attr(struct inode *inode, umode_t mode)
		inode->i_ctime = current_time(inode);
}

static inline void set_inode_attr(struct inode *inode, struct iattr *iattr)
static inline void set_inode_attr(struct inode *inode,
				  struct kernfs_iattrs *attrs)
{
	struct super_block *sb = inode->i_sb;
	inode->i_uid = iattr->ia_uid;
	inode->i_gid = iattr->ia_gid;
	inode->i_atime = timespec64_trunc(iattr->ia_atime, sb->s_time_gran);
	inode->i_mtime = timespec64_trunc(iattr->ia_mtime, sb->s_time_gran);
	inode->i_ctime = timespec64_trunc(iattr->ia_ctime, sb->s_time_gran);
	inode->i_uid = attrs->ia_uid;
	inode->i_gid = attrs->ia_gid;
	inode->i_atime = timespec64_trunc(attrs->ia_atime, sb->s_time_gran);
	inode->i_mtime = timespec64_trunc(attrs->ia_mtime, sb->s_time_gran);
	inode->i_ctime = timespec64_trunc(attrs->ia_ctime, sb->s_time_gran);
}

static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
@@ -186,15 +172,12 @@ static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
	struct kernfs_iattrs *attrs = kn->iattr;

	inode->i_mode = kn->mode;
	if (attrs) {
	if (attrs)
		/*
		 * kernfs_node has non-default attributes get them from
		 * persistent copy in kernfs_node.
		 */
		set_inode_attr(inode, &attrs->ia_iattr);
		security_inode_notifysecctx(inode, attrs->ia_secdata,
					    attrs->ia_secdata_len);
	}
		set_inode_attr(inode, attrs);

	if (kernfs_type(kn) == KERNFS_DIR)
		set_nlink(inode, kn->dir.subdirs + 2);
@@ -305,78 +288,57 @@ int kernfs_iop_permission(struct inode *inode, int mask)
	return generic_permission(inode, mask);
}

static int kernfs_xattr_get(const struct xattr_handler *handler,
			    struct dentry *unused, struct inode *inode,
			    const char *suffix, void *value, size_t size)
int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
		     void *value, size_t size)
{
	const char *name = xattr_full_name(handler, suffix);
	struct kernfs_node *kn = inode->i_private;
	struct kernfs_iattrs *attrs;

	attrs = kernfs_iattrs(kn);
	struct kernfs_iattrs *attrs = kernfs_iattrs_noalloc(kn);
	if (!attrs)
		return -ENOMEM;
		return -ENODATA;

	return simple_xattr_get(&attrs->xattrs, name, value, size);
}

static int kernfs_xattr_set(const struct xattr_handler *handler,
			    struct dentry *unused, struct inode *inode,
			    const char *suffix, const void *value,
			    size_t size, int flags)
int kernfs_xattr_set(struct kernfs_node *kn, const char *name,
		     const void *value, size_t size, int flags)
{
	const char *name = xattr_full_name(handler, suffix);
	struct kernfs_node *kn = inode->i_private;
	struct kernfs_iattrs *attrs;

	attrs = kernfs_iattrs(kn);
	struct kernfs_iattrs *attrs = kernfs_iattrs(kn);
	if (!attrs)
		return -ENOMEM;

	return simple_xattr_set(&attrs->xattrs, name, value, size, flags);
}

static const struct xattr_handler kernfs_trusted_xattr_handler = {
	.prefix = XATTR_TRUSTED_PREFIX,
	.get = kernfs_xattr_get,
	.set = kernfs_xattr_set,
};
static int kernfs_vfs_xattr_get(const struct xattr_handler *handler,
				struct dentry *unused, struct inode *inode,
				const char *suffix, void *value, size_t size)
{
	const char *name = xattr_full_name(handler, suffix);
	struct kernfs_node *kn = inode->i_private;

	return kernfs_xattr_get(kn, name, value, size);
}

static int kernfs_security_xattr_set(const struct xattr_handler *handler,
static int kernfs_vfs_xattr_set(const struct xattr_handler *handler,
				struct dentry *unused, struct inode *inode,
				const char *suffix, const void *value,
				size_t size, int flags)
{
	const char *name = xattr_full_name(handler, suffix);
	struct kernfs_node *kn = inode->i_private;
	struct kernfs_iattrs *attrs;
	void *secdata;
	u32 secdata_len = 0;
	int error;

	attrs = kernfs_iattrs(kn);
	if (!attrs)
		return -ENOMEM;

	error = security_inode_setsecurity(inode, suffix, value, size, flags);
	if (error)
		return error;
	error = security_inode_getsecctx(inode, &secdata, &secdata_len);
	if (error)
		return error;

	mutex_lock(&kernfs_mutex);
	error = kernfs_node_setsecdata(attrs, &secdata, &secdata_len);
	mutex_unlock(&kernfs_mutex);

	if (secdata)
		security_release_secctx(secdata, secdata_len);
	return error;
	return kernfs_xattr_set(kn, name, value, size, flags);
}

static const struct xattr_handler kernfs_trusted_xattr_handler = {
	.prefix = XATTR_TRUSTED_PREFIX,
	.get = kernfs_vfs_xattr_get,
	.set = kernfs_vfs_xattr_set,
};

static const struct xattr_handler kernfs_security_xattr_handler = {
	.prefix = XATTR_SECURITY_PREFIX,
	.get = kernfs_xattr_get,
	.set = kernfs_security_xattr_set,
	.get = kernfs_vfs_xattr_get,
	.set = kernfs_vfs_xattr_set,
};

const struct xattr_handler *kernfs_xattr_handlers[] = {
+5 −3
Original line number Diff line number Diff line
@@ -20,9 +20,11 @@
#include <linux/fs_context.h>

struct kernfs_iattrs {
	struct iattr		ia_iattr;
	void			*ia_secdata;
	u32			ia_secdata_len;
	kuid_t			ia_uid;
	kgid_t			ia_gid;
	struct timespec64	ia_atime;
	struct timespec64	ia_mtime;
	struct timespec64	ia_ctime;

	struct simple_xattrs	xattrs;
};
+2 −2
Original line number Diff line number Diff line
@@ -33,8 +33,8 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
	kgid_t gid = GLOBAL_ROOT_GID;

	if (target->iattr) {
		uid = target->iattr->ia_iattr.ia_uid;
		gid = target->iattr->ia_iattr.ia_gid;
		uid = target->iattr->ia_uid;
		gid = target->iattr->ia_gid;
	}

	kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, uid, gid,
Loading