Commit d1fec221 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'selinux-pr-20210215' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

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
...@@ -55,59 +55,77 @@ static struct file_system_type anon_inode_fs_type = { ...@@ -55,59 +55,77 @@ static struct file_system_type anon_inode_fs_type = {
.kill_sb = kill_anon_super, .kill_sb = kill_anon_super,
}; };
/** static struct inode *anon_inode_make_secure_inode(
* anon_inode_getfile - creates a new file instance by hooking it up to an const char *name,
* anonymous inode, and a dentry that describe the "class" const struct inode *context_inode)
* of the file {
* struct inode *inode;
* @name: [in] name of the "class" of the new file const struct qstr qname = QSTR_INIT(name, strlen(name));
* @fops: [in] file operations for the new file int error;
* @priv: [in] private data for the new file (will be file's private_data)
* @flags: [in] flags inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
* if (IS_ERR(inode))
* Creates a new file by hooking it on a single inode. This is useful for files return inode;
* that do not need to have a full-fledged inode in order to operate correctly. inode->i_flags &= ~S_PRIVATE;
* All the files created with anon_inode_getfile() will share a single inode, error = security_inode_init_security_anon(inode, &qname, context_inode);
* hence saving memory and avoiding code duplication for the file/inode/dentry if (error) {
* setup. Returns the newly created file* or an error pointer. iput(inode);
*/ return ERR_PTR(error);
struct file *anon_inode_getfile(const char *name, }
return inode;
}
static struct file *__anon_inode_getfile(const char *name,
const struct file_operations *fops, 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; struct file *file;
if (IS_ERR(anon_inode_inode))
return ERR_PTR(-ENODEV);
if (fops->owner && !try_module_get(fops->owner)) if (fops->owner && !try_module_get(fops->owner))
return ERR_PTR(-ENOENT); 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, * We know the anon_inode inode count is always
* so ihold() is safe. * greater than zero, so ihold() is safe.
*/ */
ihold(anon_inode_inode); ihold(inode);
file = alloc_file_pseudo(anon_inode_inode, anon_inode_mnt, name, }
file = alloc_file_pseudo(inode, anon_inode_mnt, name,
flags & (O_ACCMODE | O_NONBLOCK), fops); flags & (O_ACCMODE | O_NONBLOCK), fops);
if (IS_ERR(file)) 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; file->private_data = priv;
return file; return file;
err_iput:
iput(inode);
err: err:
iput(anon_inode_inode);
module_put(fops->owner); module_put(fops->owner);
return file; 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" * anonymous inode, and a dentry that describe the "class"
* of the file * of the file
* *
...@@ -118,12 +136,23 @@ EXPORT_SYMBOL_GPL(anon_inode_getfile); ...@@ -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 * 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. * 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 * 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) 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; int error, fd;
struct file *file; struct file *file;
...@@ -133,7 +162,8 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops, ...@@ -133,7 +162,8 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
return error; return error;
fd = 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)) { if (IS_ERR(file)) {
error = PTR_ERR(file); error = PTR_ERR(file);
goto err_put_unused_fd; goto err_put_unused_fd;
...@@ -146,8 +176,55 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops, ...@@ -146,8 +176,55 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
put_unused_fd(fd); put_unused_fd(fd);
return error; 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); 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) static int __init anon_inode_init(void)
{ {
anon_inode_mnt = kern_mount(&anon_inode_fs_type); anon_inode_mnt = kern_mount(&anon_inode_fs_type);
......
...@@ -1214,11 +1214,6 @@ static int anon_set_page_dirty(struct page *page) ...@@ -1214,11 +1214,6 @@ static int anon_set_page_dirty(struct page *page)
return 0; 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) struct inode *alloc_anon_inode(struct super_block *s)
{ {
static const struct address_space_operations anon_aops = { static const struct address_space_operations anon_aops = {
......
...@@ -979,14 +979,14 @@ static __poll_t userfaultfd_poll(struct file *file, poll_table *wait) ...@@ -979,14 +979,14 @@ static __poll_t userfaultfd_poll(struct file *file, poll_table *wait)
static const struct file_operations userfaultfd_fops; static const struct file_operations userfaultfd_fops;
static int resolve_userfault_fork(struct userfaultfd_ctx *ctx, static int resolve_userfault_fork(struct userfaultfd_ctx *new,
struct userfaultfd_ctx *new, struct inode *inode,
struct uffd_msg *msg) struct uffd_msg *msg)
{ {
int fd; int fd;
fd = anon_inode_getfd("[userfaultfd]", &userfaultfd_fops, new, fd = anon_inode_getfd_secure("[userfaultfd]", &userfaultfd_fops, new,
O_RDWR | (new->flags & UFFD_SHARED_FCNTL_FLAGS)); O_RDWR | (new->flags & UFFD_SHARED_FCNTL_FLAGS), inode);
if (fd < 0) if (fd < 0)
return fd; return fd;
...@@ -996,7 +996,7 @@ static int resolve_userfault_fork(struct userfaultfd_ctx *ctx, ...@@ -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, 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; ssize_t ret;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -1107,7 +1107,7 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait, ...@@ -1107,7 +1107,7 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait,
spin_unlock_irq(&ctx->fd_wqh.lock); spin_unlock_irq(&ctx->fd_wqh.lock);
if (!ret && msg->event == UFFD_EVENT_FORK) { 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); spin_lock_irq(&ctx->event_wqh.lock);
if (!list_empty(&fork_event)) { if (!list_empty(&fork_event)) {
/* /*
...@@ -1167,6 +1167,7 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf, ...@@ -1167,6 +1167,7 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf,
ssize_t _ret, ret = 0; ssize_t _ret, ret = 0;
struct uffd_msg msg; struct uffd_msg msg;
int no_wait = file->f_flags & O_NONBLOCK; int no_wait = file->f_flags & O_NONBLOCK;
struct inode *inode = file_inode(file);
if (ctx->state == UFFD_STATE_WAIT_API) if (ctx->state == UFFD_STATE_WAIT_API)
return -EINVAL; return -EINVAL;
...@@ -1174,7 +1175,7 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf, ...@@ -1174,7 +1175,7 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf,
for (;;) { for (;;) {
if (count < sizeof(msg)) if (count < sizeof(msg))
return ret ? ret : -EINVAL; return ret ? ret : -EINVAL;
_ret = userfaultfd_ctx_read(ctx, no_wait, &msg); _ret = userfaultfd_ctx_read(ctx, no_wait, &msg, inode);
if (_ret < 0) if (_ret < 0)
return ret ? ret : _ret; return ret ? ret : _ret;
if (copy_to_user((__u64 __user *) buf, &msg, sizeof(msg))) if (copy_to_user((__u64 __user *) buf, &msg, sizeof(msg)))
...@@ -1999,8 +2000,8 @@ SYSCALL_DEFINE1(userfaultfd, int, flags) ...@@ -1999,8 +2000,8 @@ SYSCALL_DEFINE1(userfaultfd, int, flags)
/* prevent the mm struct to be freed */ /* prevent the mm struct to be freed */
mmgrab(ctx->mm); mmgrab(ctx->mm);
fd = anon_inode_getfd("[userfaultfd]", &userfaultfd_fops, ctx, fd = anon_inode_getfd_secure("[userfaultfd]", &userfaultfd_fops, ctx,
O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS)); O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS), NULL);
if (fd < 0) { if (fd < 0) {
mmdrop(ctx->mm); mmdrop(ctx->mm);
kmem_cache_free(userfaultfd_ctx_cachep, ctx); kmem_cache_free(userfaultfd_ctx_cachep, ctx);
......
...@@ -10,12 +10,17 @@ ...@@ -10,12 +10,17 @@
#define _LINUX_ANON_INODES_H #define _LINUX_ANON_INODES_H
struct file_operations; struct file_operations;
struct inode;
struct file *anon_inode_getfile(const char *name, struct file *anon_inode_getfile(const char *name,
const struct file_operations *fops, const struct file_operations *fops,
void *priv, int flags); void *priv, int flags);
int anon_inode_getfd(const char *name, const struct file_operations *fops, int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv, int flags); 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 */ #endif /* _LINUX_ANON_INODES_H */
...@@ -113,6 +113,8 @@ LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode) ...@@ -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, LSM_HOOK(int, 0, inode_init_security, struct inode *inode,
struct inode *dir, const struct qstr *qstr, const char **name, struct inode *dir, const struct qstr *qstr, const char **name,
void **value, size_t *len) 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, LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
umode_t mode) umode_t mode)
LSM_HOOK(int, 0, inode_link, struct dentry *old_dentry, struct inode *dir, LSM_HOOK(int, 0, inode_link, struct dentry *old_dentry, struct inode *dir,
......
...@@ -233,6 +233,15 @@ ...@@ -233,6 +233,15 @@
* Returns 0 if @name and @value have been successfully set, * Returns 0 if @name and @value have been successfully set,
* -EOPNOTSUPP if no security attribute is needed, or * -EOPNOTSUPP if no security attribute is needed, or
* -ENOMEM on memory allocation failure. * -ENOMEM on memory allocation failure.
* @inode_init_security_anon:
* Set up the incore security field for the new anonymous inode
* and return whether the inode creation is permitted by the security
* module or not.
* @inode contains the inode structure
* @name name of the anonymous inode class
* @context_inode optional related inode
* Returns 0 on success, -EACCES if the security module denies the
* creation of this inode, or another -errno upon other errors.
* @inode_create: * @inode_create:
* Check permission to create a regular file. * Check permission to create a regular file.
* @dir contains inode structure of the parent of the new file. * @dir contains inode structure of the parent of the new file.
......
...@@ -324,6 +324,9 @@ void security_inode_free(struct inode *inode); ...@@ -324,6 +324,9 @@ void security_inode_free(struct inode *inode);
int security_inode_init_security(struct inode *inode, struct inode *dir, int security_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, const struct qstr *qstr,
initxattrs initxattrs, void *fs_data); initxattrs initxattrs, void *fs_data);
int security_inode_init_security_anon(struct inode *inode,
const struct qstr *name,
const struct inode *context_inode);
int security_old_inode_init_security(struct inode *inode, struct inode *dir, int security_old_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, const char **name, const struct qstr *qstr, const char **name,
void **value, size_t *len); void **value, size_t *len);
...@@ -738,6 +741,13 @@ static inline int security_inode_init_security(struct inode *inode, ...@@ -738,6 +741,13 @@ static inline int security_inode_init_security(struct inode *inode,
return 0; return 0;
} }
static inline int security_inode_init_security_anon(struct inode *inode,
const struct qstr *name,
const struct inode *context_inode)
{
return 0;
}
static inline int security_old_inode_init_security(struct inode *inode, static inline int security_old_inode_init_security(struct inode *inode,
struct inode *dir, struct inode *dir,
const struct qstr *qstr, const struct qstr *qstr,
......
...@@ -1059,6 +1059,14 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -1059,6 +1059,14 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
} }
EXPORT_SYMBOL(security_inode_init_security); EXPORT_SYMBOL(security_inode_init_security);
int security_inode_init_security_anon(struct inode *inode,
const struct qstr *name,
const struct inode *context_inode)
{
return call_int_hook(inode_init_security_anon, 0, inode, name,
context_inode);
}
int security_old_inode_init_security(struct inode *inode, struct inode *dir, int security_old_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, const char **name, const struct qstr *qstr, const char **name,
void **value, size_t *len) void **value, size_t *len)
......
...@@ -118,11 +118,11 @@ void avc_set_cache_threshold(struct selinux_avc *avc, ...@@ -118,11 +118,11 @@ void avc_set_cache_threshold(struct selinux_avc *avc,
avc->avc_cache_threshold = cache_threshold; avc->avc_cache_threshold = cache_threshold;
} }
static struct avc_callback_node *avc_callbacks; static struct avc_callback_node *avc_callbacks __ro_after_init;
static struct kmem_cache *avc_node_cachep; static struct kmem_cache *avc_node_cachep __ro_after_init;
static struct kmem_cache *avc_xperms_data_cachep; static struct kmem_cache *avc_xperms_data_cachep __ro_after_init;
static struct kmem_cache *avc_xperms_decision_cachep; static struct kmem_cache *avc_xperms_decision_cachep __ro_after_init;
static struct kmem_cache *avc_xperms_cachep; static struct kmem_cache *avc_xperms_cachep __ro_after_init;
static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
{ {
......
...@@ -484,39 +484,67 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) ...@@ -484,39 +484,67 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
} }
} }
static int sb_finish_set_opts(struct super_block *sb) static int sb_check_xattr_support(struct super_block *sb)
{ {
struct superblock_security_struct *sbsec = sb->s_security; struct superblock_security_struct *sbsec = sb->s_security;
struct dentry *root = sb->s_root; struct dentry *root = sb->s_root;
struct inode *root_inode = d_backing_inode(root); struct inode *root_inode = d_backing_inode(root);
int rc = 0; u32 sid;
int rc;
if (sbsec->behavior == SECURITY_FS_USE_XATTR) { /*
/* Make sure that the xattr handler exists and that no * Make sure that the xattr handler exists and that no
error other than -ENODATA is returned by getxattr on * error other than -ENODATA is returned by getxattr on
the root directory. -ENODATA is ok, as this may be * the root directory. -ENODATA is ok, as this may be
the first boot of the SELinux kernel before we have * the first boot of the SELinux kernel before we have
assigned xattr values to the filesystem. */ * assigned xattr values to the filesystem.
*/
if (!(root_inode->i_opflags & IOP_XATTR)) { if (!(root_inode->i_opflags & IOP_XATTR)) {
pr_warn("SELinux: (dev %s, type %s) has no " pr_warn("SELinux: (dev %s, type %s) has no xattr support\n",
"xattr support\n", sb->s_id, sb->s_type->name); sb->s_id, sb->s_type->name);
rc = -EOPNOTSUPP; goto fallback;
goto out;
} }
rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0); rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
if (rc < 0 && rc != -ENODATA) { if (rc < 0 && rc != -ENODATA) {
if (rc == -EOPNOTSUPP) if (rc == -EOPNOTSUPP) {
pr_warn("SELinux: (dev %s, type " pr_warn("SELinux: (dev %s, type %s) has no security xattr handler\n",
"%s) has no security xattr handler\n",
sb->s_id, sb->s_type->name); sb->s_id, sb->s_type->name);
else goto fallback;
pr_warn("SELinux: (dev %s, type " } else {
"%s) getxattr errno %d\n", sb->s_id, pr_warn("SELinux: (dev %s, type %s) getxattr errno %d\n",
sb->s_type->name, -rc); sb->s_id, sb->s_type->name, -rc);
goto out; return rc;
} }
} }
return 0;
fallback:
/* No xattr support - try to fallback to genfs if possible. */
rc = security_genfs_sid(&selinux_state, sb->s_type->name, "/",
SECCLASS_DIR, &sid);
if (rc)
return -EOPNOTSUPP;
pr_warn("SELinux: (dev %s, type %s) falling back to genfs\n",
sb->s_id, sb->s_type->name);
sbsec->behavior = SECURITY_FS_USE_GENFS;
sbsec->sid = sid;
return 0;
}
static int sb_finish_set_opts(struct super_block *sb)
{
struct superblock_security_struct *sbsec = sb->s_security;
struct dentry *root = sb->s_root;
struct inode *root_inode = d_backing_inode(root);
int rc = 0;
if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
rc = sb_check_xattr_support(sb);
if (rc)
return rc;
}
sbsec->flags |= SE_SBINITIALIZED; sbsec->flags |= SE_SBINITIALIZED;
...@@ -554,7 +582,6 @@ static int sb_finish_set_opts(struct super_block *sb) ...@@ -554,7 +582,6 @@ static int sb_finish_set_opts(struct super_block *sb)
spin_lock(&sbsec->isec_lock); spin_lock(&sbsec->isec_lock);
} }
spin_unlock(&sbsec->isec_lock); spin_unlock(&sbsec->isec_lock);
out:
return rc; return rc;
} }
...@@ -1120,7 +1147,8 @@ static inline u16 inode_mode_to_security_class(umode_t mode) ...@@ -1120,7 +1147,8 @@ static inline u16 inode_mode_to_security_class(umode_t mode)
static inline int default_protocol_stream(int protocol) static inline int default_protocol_stream(int protocol)
{ {
return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP); return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP ||
protocol == IPPROTO_MPTCP);
} }
static inline int default_protocol_dgram(int protocol) static inline int default_protocol_dgram(int protocol)
...@@ -2934,6 +2962,62 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -2934,6 +2962,62 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
return 0; return 0;
} }
static int selinux_inode_init_security_anon(struct inode *inode,
const struct qstr *name,
const struct inode *context_inode)
{
const struct task_security_struct *tsec = selinux_cred(current_cred());
struct common_audit_data ad;
struct inode_security_struct *isec;
int rc;
if (unlikely(!selinux_initialized(&selinux_state)))
return 0;
isec = selinux_inode(inode);
/*
* We only get here once per ephemeral inode. The inode has
* been initialized via inode_alloc_security but is otherwise
* untouched.
*/
if (context_inode) {
struct inode_security_struct *context_isec =
selinux_inode(context_inode);
if (context_isec->initialized != LABEL_INITIALIZED) {
pr_err("SELinux: context_inode is not initialized");
return -EACCES;
}
isec->sclass = context_isec->sclass;
isec->sid = context_isec->sid;
} else {
isec->sclass = SECCLASS_ANON_INODE;
rc = security_transition_sid(
&selinux_state, tsec->sid, tsec->sid,
isec->sclass, name, &isec->sid);
if (rc)
return rc;
}
isec->initialized = LABEL_INITIALIZED;
/*
* Now that we've initialized security, check whether we're
* allowed to actually create this type of anonymous inode.
*/
ad.type = LSM_AUDIT_DATA_INODE;
ad.u.inode = inode;
return avc_has_perm(&selinux_state,
tsec->sid,
isec->sid,
isec->sclass,
FILE__CREATE,
&ad);
}
static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode) static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
{ {
return may_create(dir, dentry, SECCLASS_FILE); return may_create(dir, dentry, SECCLASS_FILE);
...@@ -3413,6 +3497,10 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, ...@@ -3413,6 +3497,10 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size) static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
{ {
const int len = sizeof(XATTR_NAME_SELINUX); const int len = sizeof(XATTR_NAME_SELINUX);
if (!selinux_initialized(&selinux_state))
return 0;
if (buffer && len <= buffer_size) if (buffer && len <= buffer_size)
memcpy(buffer, XATTR_NAME_SELINUX, len); memcpy(buffer, XATTR_NAME_SELINUX, len);
return len; return len;
...@@ -7000,6 +7088,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { ...@@ -7000,6 +7088,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security), LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security),
LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security), LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security),
LSM_HOOK_INIT(inode_init_security_anon, selinux_inode_init_security_anon),
LSM_HOOK_INIT(inode_create, selinux_inode_create), LSM_HOOK_INIT(inode_create, selinux_inode_create),
LSM_HOOK_INIT(inode_link, selinux_inode_link), LSM_HOOK_INIT(inode_link, selinux_inode_link),
LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink), LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink),
......
...@@ -40,7 +40,6 @@ struct sel_ib_pkey { ...@@ -40,7 +40,6 @@ struct sel_ib_pkey {
struct rcu_head rcu; struct rcu_head rcu;
}; };
static LIST_HEAD(sel_ib_pkey_list);
static DEFINE_SPINLOCK(sel_ib_pkey_lock); static DEFINE_SPINLOCK(sel_ib_pkey_lock);
static struct sel_ib_pkey_bkt sel_ib_pkey_hash[SEL_PKEY_HASH_SIZE]; static struct sel_ib_pkey_bkt sel_ib_pkey_hash[SEL_PKEY_HASH_SIZE];
......
...@@ -249,6 +249,8 @@ struct security_class_mapping secclass_map[] = { ...@@ -249,6 +249,8 @@ struct security_class_mapping secclass_map[] = {
{"open", "cpu", "kernel", "tracepoint", "read", "write"} }, {"open", "cpu", "kernel", "tracepoint", "read", "write"} },
{ "lockdown", { "lockdown",
{ "integrity", "confidentiality", NULL } }, { "integrity", "confidentiality", NULL } },
{ "anon_inode",
{ COMMON_FILE_PERMS, NULL } },
{ NULL } { NULL }
}; };
......
...@@ -436,7 +436,6 @@ extern void selinux_complete_init(void); ...@@ -436,7 +436,6 @@ extern void selinux_complete_init(void);
extern int selinux_disable(struct selinux_state *state); extern int selinux_disable(struct selinux_state *state);
extern void exit_sel_fs(void); extern void exit_sel_fs(void);
extern struct path selinux_null; extern struct path selinux_null;
extern struct vfsmount *selinuxfs_mount;
extern void selnl_notify_setenforce(int val); extern void selnl_notify_setenforce(int val);
extern void selnl_notify_policyload(u32 seqno); extern void selnl_notify_policyload(u32 seqno);
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
......
...@@ -36,7 +36,6 @@ struct sel_netif { ...@@ -36,7 +36,6 @@ struct sel_netif {
}; };
static u32 sel_netif_total; static u32 sel_netif_total;
static LIST_HEAD(sel_netif_list);
static DEFINE_SPINLOCK(sel_netif_lock); static DEFINE_SPINLOCK(sel_netif_lock);
static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "security.h" #include "security.h"
static struct sock *selnl; static struct sock *selnl __ro_after_init;
static int selnl_msglen(int msgtype) static int selnl_msglen(int msgtype)
{ {
......
...@@ -54,7 +54,6 @@ struct sel_netnode { ...@@ -54,7 +54,6 @@ struct sel_netnode {
* if this becomes a problem we can always add a hash table for each address * if this becomes a problem we can always add a hash table for each address
* family later */ * family later */
static LIST_HEAD(sel_netnode_list);
static DEFINE_SPINLOCK(sel_netnode_lock); static DEFINE_SPINLOCK(sel_netnode_lock);
static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE]; static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
......
...@@ -53,7 +53,6 @@ struct sel_netport { ...@@ -53,7 +53,6 @@ struct sel_netport {
* if this becomes a problem we can always add a hash table for each address * if this becomes a problem we can always add a hash table for each address
* family later */ * family later */
static LIST_HEAD(sel_netport_list);
static DEFINE_SPINLOCK(sel_netport_lock); static DEFINE_SPINLOCK(sel_netport_lock);
static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE]; static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE];
......
...@@ -2204,8 +2204,8 @@ static struct file_system_type sel_fs_type = { ...@@ -2204,8 +2204,8 @@ static struct file_system_type sel_fs_type = {
.kill_sb = sel_kill_sb, .kill_sb = sel_kill_sb,
}; };
struct vfsmount *selinuxfs_mount; static struct vfsmount *selinuxfs_mount __ro_after_init;
struct path selinux_null; struct path selinux_null __ro_after_init;
static int __init init_sel_fs(void) static int __init init_sel_fs(void)
{ {
......
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
#include "avtab.h" #include "avtab.h"
#include "policydb.h" #include "policydb.h"
static struct kmem_cache *avtab_node_cachep; static struct kmem_cache *avtab_node_cachep __ro_after_init;
static struct kmem_cache *avtab_xperms_cachep; static struct kmem_cache *avtab_xperms_cachep __ro_after_init;
/* Based on MurmurHash3, written by Austin Appleby and placed in the /* Based on MurmurHash3, written by Austin Appleby and placed in the
* public domain. * public domain.
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#define BITS_PER_U64 (sizeof(u64) * 8) #define BITS_PER_U64 (sizeof(u64) * 8)
static struct kmem_cache *ebitmap_node_cachep; static struct kmem_cache *ebitmap_node_cachep __ro_after_init;
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
{ {
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include "hashtab.h" #include "hashtab.h"
static struct kmem_cache *hashtab_node_cachep; static struct kmem_cache *hashtab_node_cachep __ro_after_init;
/* /*
* Here we simply round the number of elements up to the nearest power of two. * Here we simply round the number of elements up to the nearest power of two.
......
...@@ -3693,15 +3693,11 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) ...@@ -3693,15 +3693,11 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
return match; return match;
} }
static int (*aurule_callback)(void) = audit_update_lsm_rules;
static int aurule_avc_callback(u32 event) static int aurule_avc_callback(u32 event)
{ {
int err = 0; if (event == AVC_CALLBACK_RESET)
return audit_update_lsm_rules();
if (event == AVC_CALLBACK_RESET && aurule_callback) return 0;
err = aurule_callback();
return err;
} }
static int __init aurule_init(void) static int __init aurule_init(void)
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
#include "xfrm.h" #include "xfrm.h"
/* Labeled XFRM instance counter */ /* Labeled XFRM instance counter */
atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0); atomic_t selinux_xfrm_refcount __read_mostly = ATOMIC_INIT(0);
/* /*
* Returns true if the context is an LSM/SELinux context. * Returns true if the context is an LSM/SELinux context.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment