Commit d1fec221 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull selinux updates from Paul Moore:
 "We've got a good handful of patches for SELinux this time around; with
  everything passing the selinux-testsuite and applying cleanly to your
  tree as of a few minutes ago. The highlights are:

   - Add support for labeling anonymous inodes, and extend this new
     support to userfaultfd.

   - Fallback to SELinux genfs file labeling if the filesystem does not
     have xattr support. This is useful for virtiofs which can vary in
     its xattr support depending on the backing filesystem.

   - Classify and handle MPTCP the same as TCP in SELinux.

   - Ensure consistent behavior between inode_getxattr and
     inode_listsecurity when the SELinux policy is not loaded. This
     fixes a known problem with overlayfs.

   - A couple of patches to prune some unused variables from the SELinux
     code, mark private variables as static, and mark other variables as
     __ro_after_init or __read_mostly"

* tag 'selinux-pr-20210215' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  fs: anon_inodes: rephrase to appropriate kernel-doc
  userfaultfd: use secure anon inodes for userfaultfd
  selinux: teach SELinux about anonymous inodes
  fs: add LSM-supporting anon-inode interface
  security: add inode_init_security_anon() LSM hook
  selinux: fall back to SECURITY_FS_USE_GENFS if no xattr support
  selinux: mark selinux_xfrm_refcount as __read_mostly
  selinux: mark some global variables __ro_after_init
  selinux: make selinuxfs_mount static
  selinux: drop the unnecessary aurule_callback variable
  selinux: remove unused global variables
  selinux: fix inconsistency between inode_getxattr and inode_listsecurity
  selinux: handle MPTCP consistently with TCP
parents e210761f 365982ab
Loading
Loading
Loading
Loading
+117 −40
Original line number Diff line number Diff line
@@ -55,59 +55,77 @@ static struct file_system_type anon_inode_fs_type = {
	.kill_sb	= kill_anon_super,
};

/**
 * anon_inode_getfile - creates a new file instance by hooking it up to an
 *                      anonymous inode, and a dentry that describe the "class"
 *                      of the file
 *
 * @name:    [in]    name of the "class" of the new file
 * @fops:    [in]    file operations for the new file
 * @priv:    [in]    private data for the new file (will be file's private_data)
 * @flags:   [in]    flags
 *
 * Creates a new file by hooking it on a single inode. This is useful for files
 * that do not need to have a full-fledged inode in order to operate correctly.
 * All the files created with anon_inode_getfile() will share a single inode,
 * hence saving memory and avoiding code duplication for the file/inode/dentry
 * setup.  Returns the newly created file* or an error pointer.
 */
struct file *anon_inode_getfile(const char *name,
static struct inode *anon_inode_make_secure_inode(
	const char *name,
	const struct inode *context_inode)
{
	struct inode *inode;
	const struct qstr qname = QSTR_INIT(name, strlen(name));
	int error;

	inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
	if (IS_ERR(inode))
		return inode;
	inode->i_flags &= ~S_PRIVATE;
	error =	security_inode_init_security_anon(inode, &qname, context_inode);
	if (error) {
		iput(inode);
		return ERR_PTR(error);
	}
	return inode;
}

static struct file *__anon_inode_getfile(const char *name,
					 const struct file_operations *fops,
				void *priv, int flags)
					 void *priv, int flags,
					 const struct inode *context_inode,
					 bool secure)
{
	struct inode *inode;
	struct file *file;

	if (IS_ERR(anon_inode_inode))
		return ERR_PTR(-ENODEV);

	if (fops->owner && !try_module_get(fops->owner))
		return ERR_PTR(-ENOENT);

	if (secure) {
		inode =	anon_inode_make_secure_inode(name, context_inode);
		if (IS_ERR(inode)) {
			file = ERR_CAST(inode);
			goto err;
		}
	} else {
		inode =	anon_inode_inode;
		if (IS_ERR(inode)) {
			file = ERR_PTR(-ENODEV);
			goto err;
		}
		/*
	 * We know the anon_inode inode count is always greater than zero,
	 * so ihold() is safe.
		 * We know the anon_inode inode count is always
		 * greater than zero, so ihold() is safe.
		 */
	ihold(anon_inode_inode);
	file = alloc_file_pseudo(anon_inode_inode, anon_inode_mnt, name,
		ihold(inode);
	}

	file = alloc_file_pseudo(inode, anon_inode_mnt, name,
				 flags & (O_ACCMODE | O_NONBLOCK), fops);
	if (IS_ERR(file))
		goto err;
		goto err_iput;

	file->f_mapping = anon_inode_inode->i_mapping;
	file->f_mapping = inode->i_mapping;

	file->private_data = priv;

	return file;

err_iput:
	iput(inode);
err:
	iput(anon_inode_inode);
	module_put(fops->owner);
	return file;
}
EXPORT_SYMBOL_GPL(anon_inode_getfile);

/**
 * anon_inode_getfd - creates a new file instance by hooking it up to an
 * anon_inode_getfile - creates a new file instance by hooking it up to an
 *                      anonymous inode, and a dentry that describe the "class"
 *                      of the file
 *
@@ -118,12 +136,23 @@ EXPORT_SYMBOL_GPL(anon_inode_getfile);
 *
 * Creates a new file by hooking it on a single inode. This is useful for files
 * that do not need to have a full-fledged inode in order to operate correctly.
 * All the files created with anon_inode_getfd() will share a single inode,
 * All the files created with anon_inode_getfile() will share a single inode,
 * hence saving memory and avoiding code duplication for the file/inode/dentry
 * setup.  Returns new descriptor or an error code.
 * setup.  Returns the newly created file* or an error pointer.
 */
int anon_inode_getfd(const char *name, const struct file_operations *fops,
struct file *anon_inode_getfile(const char *name,
				const struct file_operations *fops,
				void *priv, int flags)
{
	return __anon_inode_getfile(name, fops, priv, flags, NULL, false);
}
EXPORT_SYMBOL_GPL(anon_inode_getfile);

static int __anon_inode_getfd(const char *name,
			      const struct file_operations *fops,
			      void *priv, int flags,
			      const struct inode *context_inode,
			      bool secure)
{
	int error, fd;
	struct file *file;
@@ -133,7 +162,8 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
		return error;
	fd = error;

	file = anon_inode_getfile(name, fops, priv, flags);
	file = __anon_inode_getfile(name, fops, priv, flags, context_inode,
				    secure);
	if (IS_ERR(file)) {
		error = PTR_ERR(file);
		goto err_put_unused_fd;
@@ -146,8 +176,55 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
	put_unused_fd(fd);
	return error;
}

/**
 * anon_inode_getfd - creates a new file instance by hooking it up to
 *                    an anonymous inode and a dentry that describe
 *                    the "class" of the file
 *
 * @name:    [in]    name of the "class" of the new file
 * @fops:    [in]    file operations for the new file
 * @priv:    [in]    private data for the new file (will be file's private_data)
 * @flags:   [in]    flags
 *
 * Creates a new file by hooking it on a single inode. This is
 * useful for files that do not need to have a full-fledged inode in
 * order to operate correctly.  All the files created with
 * anon_inode_getfd() will use the same singleton inode, reducing
 * memory use and avoiding code duplication for the file/inode/dentry
 * setup.  Returns a newly created file descriptor or an error code.
 */
int anon_inode_getfd(const char *name, const struct file_operations *fops,
		     void *priv, int flags)
{
	return __anon_inode_getfd(name, fops, priv, flags, NULL, false);
}
EXPORT_SYMBOL_GPL(anon_inode_getfd);

/**
 * anon_inode_getfd_secure - Like anon_inode_getfd(), but creates a new
 * !S_PRIVATE anon inode rather than reuse the singleton anon inode, and calls
 * the inode_init_security_anon() LSM hook. This allows the inode to have its
 * own security context and for a LSM to reject creation of the inode.
 *
 * @name:    [in]    name of the "class" of the new file
 * @fops:    [in]    file operations for the new file
 * @priv:    [in]    private data for the new file (will be file's private_data)
 * @flags:   [in]    flags
 * @context_inode:
 *           [in]    the logical relationship with the new inode (optional)
 *
 * The LSM may use @context_inode in inode_init_security_anon(), but a
 * reference to it is not held.
 */
int anon_inode_getfd_secure(const char *name, const struct file_operations *fops,
			    void *priv, int flags,
			    const struct inode *context_inode)
{
	return __anon_inode_getfd(name, fops, priv, flags, context_inode, true);
}
EXPORT_SYMBOL_GPL(anon_inode_getfd_secure);

static int __init anon_inode_init(void)
{
	anon_inode_mnt = kern_mount(&anon_inode_fs_type);
+0 −5
Original line number Diff line number Diff line
@@ -1214,11 +1214,6 @@ static int anon_set_page_dirty(struct page *page)
	return 0;
};

/*
 * A single inode exists for all anon_inode files. Contrary to pipes,
 * anon_inode inodes have no associated per-instance data, so we need
 * only allocate one of them.
 */
struct inode *alloc_anon_inode(struct super_block *s)
{
	static const struct address_space_operations anon_aops = {
+10 −9
Original line number Diff line number Diff line
@@ -979,14 +979,14 @@ static __poll_t userfaultfd_poll(struct file *file, poll_table *wait)

static const struct file_operations userfaultfd_fops;

static int resolve_userfault_fork(struct userfaultfd_ctx *ctx,
				  struct userfaultfd_ctx *new,
static int resolve_userfault_fork(struct userfaultfd_ctx *new,
				  struct inode *inode,
				  struct uffd_msg *msg)
{
	int fd;

	fd = anon_inode_getfd("[userfaultfd]", &userfaultfd_fops, new,
			      O_RDWR | (new->flags & UFFD_SHARED_FCNTL_FLAGS));
	fd = anon_inode_getfd_secure("[userfaultfd]", &userfaultfd_fops, new,
			O_RDWR | (new->flags & UFFD_SHARED_FCNTL_FLAGS), inode);
	if (fd < 0)
		return fd;

@@ -996,7 +996,7 @@ static int resolve_userfault_fork(struct userfaultfd_ctx *ctx,
}

static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait,
				    struct uffd_msg *msg)
				    struct uffd_msg *msg, struct inode *inode)
{
	ssize_t ret;
	DECLARE_WAITQUEUE(wait, current);
@@ -1107,7 +1107,7 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait,
	spin_unlock_irq(&ctx->fd_wqh.lock);

	if (!ret && msg->event == UFFD_EVENT_FORK) {
		ret = resolve_userfault_fork(ctx, fork_nctx, msg);
		ret = resolve_userfault_fork(fork_nctx, inode, msg);
		spin_lock_irq(&ctx->event_wqh.lock);
		if (!list_empty(&fork_event)) {
			/*
@@ -1167,6 +1167,7 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf,
	ssize_t _ret, ret = 0;
	struct uffd_msg msg;
	int no_wait = file->f_flags & O_NONBLOCK;
	struct inode *inode = file_inode(file);

	if (ctx->state == UFFD_STATE_WAIT_API)
		return -EINVAL;
@@ -1174,7 +1175,7 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf,
	for (;;) {
		if (count < sizeof(msg))
			return ret ? ret : -EINVAL;
		_ret = userfaultfd_ctx_read(ctx, no_wait, &msg);
		_ret = userfaultfd_ctx_read(ctx, no_wait, &msg, inode);
		if (_ret < 0)
			return ret ? ret : _ret;
		if (copy_to_user((__u64 __user *) buf, &msg, sizeof(msg)))
@@ -1999,8 +2000,8 @@ SYSCALL_DEFINE1(userfaultfd, int, flags)
	/* prevent the mm struct to be freed */
	mmgrab(ctx->mm);

	fd = anon_inode_getfd("[userfaultfd]", &userfaultfd_fops, ctx,
			      O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS));
	fd = anon_inode_getfd_secure("[userfaultfd]", &userfaultfd_fops, ctx,
			O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS), NULL);
	if (fd < 0) {
		mmdrop(ctx->mm);
		kmem_cache_free(userfaultfd_ctx_cachep, ctx);
+5 −0
Original line number Diff line number Diff line
@@ -10,12 +10,17 @@
#define _LINUX_ANON_INODES_H

struct file_operations;
struct inode;

struct file *anon_inode_getfile(const char *name,
				const struct file_operations *fops,
				void *priv, int flags);
int anon_inode_getfd(const char *name, const struct file_operations *fops,
		     void *priv, int flags);
int anon_inode_getfd_secure(const char *name,
			    const struct file_operations *fops,
			    void *priv, int flags,
			    const struct inode *context_inode);

#endif /* _LINUX_ANON_INODES_H */
+2 −0
Original line number Diff line number Diff line
@@ -113,6 +113,8 @@ LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode)
LSM_HOOK(int, 0, inode_init_security, struct inode *inode,
	 struct inode *dir, const struct qstr *qstr, const char **name,
	 void **value, size_t *len)
LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode,
	 const struct qstr *name, const struct inode *context_inode)
LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
	 umode_t mode)
LSM_HOOK(int, 0, inode_link, struct dentry *old_dentry, struct inode *dir,
Loading