Merge d1fec2214b
("Merge tag 'selinux-pr-20210215' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux") into android-mainline
Steps on the way to 5.12-rc1 Resolves conflicts in: security/selinux/hooks.c security/selinux/include/classmap.h Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I5aedc69f0f2b3b16351b1f39ed69994ca1ba59a5
This commit is contained in:
commit
84645f0a33
171
fs/anon_inodes.c
171
fs/anon_inodes.c
@ -55,6 +55,75 @@ static struct file_system_type anon_inode_fs_type = {
|
||||
.kill_sb = kill_anon_super,
|
||||
};
|
||||
|
||||
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,
|
||||
const struct inode *context_inode,
|
||||
bool secure)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct file *file;
|
||||
|
||||
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.
|
||||
*/
|
||||
ihold(inode);
|
||||
}
|
||||
|
||||
file = alloc_file_pseudo(inode, anon_inode_mnt, name,
|
||||
flags & (O_ACCMODE | O_NONBLOCK), fops);
|
||||
if (IS_ERR(file))
|
||||
goto err_iput;
|
||||
|
||||
file->f_mapping = inode->i_mapping;
|
||||
|
||||
file->private_data = priv;
|
||||
|
||||
return file;
|
||||
|
||||
err_iput:
|
||||
iput(inode);
|
||||
err:
|
||||
module_put(fops->owner);
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* anon_inode_getfile - creates a new file instance by hooking it up to an
|
||||
* anonymous inode, and a dentry that describe the "class"
|
||||
@ -75,55 +144,15 @@ struct file *anon_inode_getfile(const char *name,
|
||||
const struct file_operations *fops,
|
||||
void *priv, int flags)
|
||||
{
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
flags & (O_ACCMODE | O_NONBLOCK), fops);
|
||||
if (IS_ERR(file))
|
||||
goto err;
|
||||
|
||||
file->f_mapping = anon_inode_inode->i_mapping;
|
||||
|
||||
file->private_data = priv;
|
||||
|
||||
return file;
|
||||
|
||||
err:
|
||||
iput(anon_inode_inode);
|
||||
module_put(fops->owner);
|
||||
return file;
|
||||
return __anon_inode_getfile(name, fops, priv, flags, NULL, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(anon_inode_getfile);
|
||||
|
||||
/**
|
||||
* 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 share a single inode,
|
||||
* hence saving memory and avoiding code duplication for the file/inode/dentry
|
||||
* setup. Returns new descriptor or an error code.
|
||||
*/
|
||||
int anon_inode_getfd(const char *name, const struct file_operations *fops,
|
||||
void *priv, int flags)
|
||||
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);
|
||||
|
@ -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 = {
|
||||
|
@ -980,14 +980,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;
|
||||
|
||||
@ -997,7 +997,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);
|
||||
@ -1108,7 +1108,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)) {
|
||||
/*
|
||||
@ -1168,6 +1168,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;
|
||||
@ -1175,7 +1176,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)))
|
||||
@ -2002,8 +2003,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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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,
|
||||
|
@ -233,6 +233,15 @@
|
||||
* Returns 0 if @name and @value have been successfully set,
|
||||
* -EOPNOTSUPP if no security attribute is needed, or
|
||||
* -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:
|
||||
* Check permission to create a regular file.
|
||||
* @dir contains inode structure of the parent of the new file.
|
||||
|
@ -322,6 +322,9 @@ void security_inode_free(struct inode *inode);
|
||||
int security_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
const struct qstr *qstr,
|
||||
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,
|
||||
const struct qstr *qstr, const char **name,
|
||||
void **value, size_t *len);
|
||||
@ -736,6 +739,13 @@ static inline int security_inode_init_security(struct inode *inode,
|
||||
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,
|
||||
struct inode *dir,
|
||||
const struct qstr *qstr,
|
||||
|
@ -1059,6 +1059,14 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
}
|
||||
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,
|
||||
const struct qstr *qstr, const char **name,
|
||||
void **value, size_t *len)
|
||||
|
@ -118,11 +118,11 @@ void avc_set_cache_threshold(struct selinux_avc *avc,
|
||||
avc->avc_cache_threshold = cache_threshold;
|
||||
}
|
||||
|
||||
static struct avc_callback_node *avc_callbacks;
|
||||
static struct kmem_cache *avc_node_cachep;
|
||||
static struct kmem_cache *avc_xperms_data_cachep;
|
||||
static struct kmem_cache *avc_xperms_decision_cachep;
|
||||
static struct kmem_cache *avc_xperms_cachep;
|
||||
static struct avc_callback_node *avc_callbacks __ro_after_init;
|
||||
static struct kmem_cache *avc_node_cachep __ro_after_init;
|
||||
static struct kmem_cache *avc_xperms_data_cachep __ro_after_init;
|
||||
static struct kmem_cache *avc_xperms_decision_cachep __ro_after_init;
|
||||
static struct kmem_cache *avc_xperms_cachep __ro_after_init;
|
||||
|
||||
static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
|
||||
{
|
||||
|
@ -484,6 +484,56 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
|
||||
}
|
||||
}
|
||||
|
||||
static int sb_check_xattr_support(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);
|
||||
u32 sid;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Make sure that the xattr handler exists and that no
|
||||
* error other than -ENODATA is returned by getxattr on
|
||||
* the root directory. -ENODATA is ok, as this may be
|
||||
* the first boot of the SELinux kernel before we have
|
||||
* assigned xattr values to the filesystem.
|
||||
*/
|
||||
if (!(root_inode->i_opflags & IOP_XATTR)) {
|
||||
pr_warn("SELinux: (dev %s, type %s) has no xattr support\n",
|
||||
sb->s_id, sb->s_type->name);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0,
|
||||
XATTR_NOSECURITY);
|
||||
if (rc < 0 && rc != -ENODATA) {
|
||||
if (rc == -EOPNOTSUPP) {
|
||||
pr_warn("SELinux: (dev %s, type %s) has no security xattr handler\n",
|
||||
sb->s_id, sb->s_type->name);
|
||||
goto fallback;
|
||||
} else {
|
||||
pr_warn("SELinux: (dev %s, type %s) getxattr errno %d\n",
|
||||
sb->s_id, sb->s_type->name, -rc);
|
||||
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;
|
||||
@ -492,31 +542,9 @@ static int sb_finish_set_opts(struct super_block *sb)
|
||||
int rc = 0;
|
||||
|
||||
if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
|
||||
/* Make sure that the xattr handler exists and that no
|
||||
error other than -ENODATA is returned by getxattr on
|
||||
the root directory. -ENODATA is ok, as this may be
|
||||
the first boot of the SELinux kernel before we have
|
||||
assigned xattr values to the filesystem. */
|
||||
if (!(root_inode->i_opflags & IOP_XATTR)) {
|
||||
pr_warn("SELinux: (dev %s, type %s) has no "
|
||||
"xattr support\n", sb->s_id, sb->s_type->name);
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL,
|
||||
0, XATTR_NOSECURITY);
|
||||
if (rc < 0 && rc != -ENODATA) {
|
||||
if (rc == -EOPNOTSUPP)
|
||||
pr_warn("SELinux: (dev %s, type "
|
||||
"%s) has no security xattr handler\n",
|
||||
sb->s_id, sb->s_type->name);
|
||||
else
|
||||
pr_warn("SELinux: (dev %s, type "
|
||||
"%s) getxattr errno %d\n", sb->s_id,
|
||||
sb->s_type->name, -rc);
|
||||
goto out;
|
||||
}
|
||||
rc = sb_check_xattr_support(sb);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
sbsec->flags |= SE_SBINITIALIZED;
|
||||
@ -555,7 +583,6 @@ static int sb_finish_set_opts(struct super_block *sb)
|
||||
spin_lock(&sbsec->isec_lock);
|
||||
}
|
||||
spin_unlock(&sbsec->isec_lock);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1121,7 +1148,8 @@ static inline u16 inode_mode_to_security_class(umode_t mode)
|
||||
|
||||
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)
|
||||
@ -2937,6 +2965,62 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
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)
|
||||
{
|
||||
return may_create(dir, dentry, SECCLASS_FILE);
|
||||
@ -3416,6 +3500,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)
|
||||
{
|
||||
const int len = sizeof(XATTR_NAME_SELINUX);
|
||||
|
||||
if (!selinux_initialized(&selinux_state))
|
||||
return 0;
|
||||
|
||||
if (buffer && len <= buffer_size)
|
||||
memcpy(buffer, XATTR_NAME_SELINUX, len);
|
||||
return len;
|
||||
@ -6975,6 +7063,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_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_link, selinux_inode_link),
|
||||
LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink),
|
||||
|
@ -40,7 +40,6 @@ struct sel_ib_pkey {
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
static LIST_HEAD(sel_ib_pkey_list);
|
||||
static DEFINE_SPINLOCK(sel_ib_pkey_lock);
|
||||
static struct sel_ib_pkey_bkt sel_ib_pkey_hash[SEL_PKEY_HASH_SIZE];
|
||||
|
||||
|
@ -247,6 +247,8 @@ struct security_class_mapping secclass_map[] = {
|
||||
{ COMMON_SOCK_PERMS, NULL } },
|
||||
{ "perf_event",
|
||||
{"open", "cpu", "kernel", "tracepoint", "read", "write"} },
|
||||
{ "anon_inode",
|
||||
{ COMMON_FILE_PERMS, NULL } },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -444,7 +444,6 @@ extern void selinux_complete_init(void);
|
||||
extern int selinux_disable(struct selinux_state *state);
|
||||
extern void exit_sel_fs(void);
|
||||
extern struct path selinux_null;
|
||||
extern struct vfsmount *selinuxfs_mount;
|
||||
extern void selnl_notify_setenforce(int val);
|
||||
extern void selnl_notify_policyload(u32 seqno);
|
||||
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
|
||||
|
@ -36,7 +36,6 @@ struct sel_netif {
|
||||
};
|
||||
|
||||
static u32 sel_netif_total;
|
||||
static LIST_HEAD(sel_netif_list);
|
||||
static DEFINE_SPINLOCK(sel_netif_lock);
|
||||
static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "security.h"
|
||||
|
||||
static struct sock *selnl;
|
||||
static struct sock *selnl __ro_after_init;
|
||||
|
||||
static int selnl_msglen(int msgtype)
|
||||
{
|
||||
|
@ -54,7 +54,6 @@ struct sel_netnode {
|
||||
* if this becomes a problem we can always add a hash table for each address
|
||||
* family later */
|
||||
|
||||
static LIST_HEAD(sel_netnode_list);
|
||||
static DEFINE_SPINLOCK(sel_netnode_lock);
|
||||
static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
|
||||
|
||||
|
@ -53,7 +53,6 @@ struct sel_netport {
|
||||
* if this becomes a problem we can always add a hash table for each address
|
||||
* family later */
|
||||
|
||||
static LIST_HEAD(sel_netport_list);
|
||||
static DEFINE_SPINLOCK(sel_netport_lock);
|
||||
static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE];
|
||||
|
||||
|
@ -2204,8 +2204,8 @@ static struct file_system_type sel_fs_type = {
|
||||
.kill_sb = sel_kill_sb,
|
||||
};
|
||||
|
||||
struct vfsmount *selinuxfs_mount;
|
||||
struct path selinux_null;
|
||||
static struct vfsmount *selinuxfs_mount __ro_after_init;
|
||||
struct path selinux_null __ro_after_init;
|
||||
|
||||
static int __init init_sel_fs(void)
|
||||
{
|
||||
|
@ -23,8 +23,8 @@
|
||||
#include "avtab.h"
|
||||
#include "policydb.h"
|
||||
|
||||
static struct kmem_cache *avtab_node_cachep;
|
||||
static struct kmem_cache *avtab_xperms_cachep;
|
||||
static struct kmem_cache *avtab_node_cachep __ro_after_init;
|
||||
static struct kmem_cache *avtab_xperms_cachep __ro_after_init;
|
||||
|
||||
/* Based on MurmurHash3, written by Austin Appleby and placed in the
|
||||
* public domain.
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <linux/errno.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.
|
||||
|
@ -3696,15 +3696,11 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
|
||||
return match;
|
||||
}
|
||||
|
||||
static int (*aurule_callback)(void) = audit_update_lsm_rules;
|
||||
|
||||
static int aurule_avc_callback(u32 event)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (event == AVC_CALLBACK_RESET && aurule_callback)
|
||||
err = aurule_callback();
|
||||
return err;
|
||||
if (event == AVC_CALLBACK_RESET)
|
||||
return audit_update_lsm_rules();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init aurule_init(void)
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include "xfrm.h"
|
||||
|
||||
/* 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.
|
||||
|
@ -362,14 +362,14 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
|
||||
{
|
||||
u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
|
||||
->perm;
|
||||
u16 perm = *a_perm;
|
||||
u16 perm = READ_ONCE(*a_perm);
|
||||
const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
|
||||
|
||||
if (is_delete)
|
||||
perm &= ~b_perm;
|
||||
else
|
||||
perm |= b_perm;
|
||||
*a_perm = perm;
|
||||
WRITE_ONCE(*a_perm, perm);
|
||||
return !perm;
|
||||
}
|
||||
|
||||
@ -437,7 +437,7 @@ static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
|
||||
{
|
||||
u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
|
||||
head)->perm;
|
||||
u8 perm = *a_perm;
|
||||
u8 perm = READ_ONCE(*a_perm);
|
||||
const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
|
||||
->perm;
|
||||
|
||||
@ -445,7 +445,7 @@ static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
|
||||
perm &= ~b_perm;
|
||||
else
|
||||
perm |= b_perm;
|
||||
*a_perm = perm;
|
||||
WRITE_ONCE(*a_perm, perm);
|
||||
return !perm;
|
||||
}
|
||||
|
||||
@ -517,14 +517,14 @@ static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
|
||||
{
|
||||
u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
|
||||
->perm;
|
||||
u8 perm = *a_perm;
|
||||
u8 perm = READ_ONCE(*a_perm);
|
||||
const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
|
||||
|
||||
if (is_delete)
|
||||
perm &= ~b_perm;
|
||||
else
|
||||
perm |= b_perm;
|
||||
*a_perm = perm;
|
||||
WRITE_ONCE(*a_perm, perm);
|
||||
return !perm;
|
||||
}
|
||||
|
||||
@ -655,7 +655,7 @@ static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
|
||||
{
|
||||
u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
|
||||
head)->perm;
|
||||
u8 perm = *a_perm;
|
||||
u8 perm = READ_ONCE(*a_perm);
|
||||
const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
|
||||
->perm;
|
||||
|
||||
@ -663,7 +663,7 @@ static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
|
||||
perm &= ~b_perm;
|
||||
else
|
||||
perm |= b_perm;
|
||||
*a_perm = perm;
|
||||
WRITE_ONCE(*a_perm, perm);
|
||||
return !perm;
|
||||
}
|
||||
|
||||
|
@ -233,14 +233,14 @@ static bool tomoyo_merge_inet_acl(struct tomoyo_acl_info *a,
|
||||
{
|
||||
u8 * const a_perm =
|
||||
&container_of(a, struct tomoyo_inet_acl, head)->perm;
|
||||
u8 perm = *a_perm;
|
||||
u8 perm = READ_ONCE(*a_perm);
|
||||
const u8 b_perm = container_of(b, struct tomoyo_inet_acl, head)->perm;
|
||||
|
||||
if (is_delete)
|
||||
perm &= ~b_perm;
|
||||
else
|
||||
perm |= b_perm;
|
||||
*a_perm = perm;
|
||||
WRITE_ONCE(*a_perm, perm);
|
||||
return !perm;
|
||||
}
|
||||
|
||||
@ -259,14 +259,14 @@ static bool tomoyo_merge_unix_acl(struct tomoyo_acl_info *a,
|
||||
{
|
||||
u8 * const a_perm =
|
||||
&container_of(a, struct tomoyo_unix_acl, head)->perm;
|
||||
u8 perm = *a_perm;
|
||||
u8 perm = READ_ONCE(*a_perm);
|
||||
const u8 b_perm = container_of(b, struct tomoyo_unix_acl, head)->perm;
|
||||
|
||||
if (is_delete)
|
||||
perm &= ~b_perm;
|
||||
else
|
||||
perm |= b_perm;
|
||||
*a_perm = perm;
|
||||
WRITE_ONCE(*a_perm, perm);
|
||||
return !perm;
|
||||
}
|
||||
|
||||
@ -613,7 +613,7 @@ static int tomoyo_check_unix_address(struct sockaddr *addr,
|
||||
static bool tomoyo_kernel_service(void)
|
||||
{
|
||||
/* Nothing to do if I am a kernel service. */
|
||||
return uaccess_kernel();
|
||||
return (current->flags & (PF_KTHREAD | PF_IO_WORKER)) == PF_KTHREAD;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1058,30 +1058,30 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
|
||||
|
||||
if (ptr->is_deleted)
|
||||
continue;
|
||||
/*
|
||||
* Reading perm bitmap might race with tomoyo_merge_*() because
|
||||
* caller does not hold tomoyo_policy_lock mutex. But exceeding
|
||||
* max_learning_entry parameter by a few entries does not harm.
|
||||
*/
|
||||
switch (ptr->type) {
|
||||
case TOMOYO_TYPE_PATH_ACL:
|
||||
perm = container_of(ptr, struct tomoyo_path_acl, head)
|
||||
->perm;
|
||||
data_race(perm = container_of(ptr, struct tomoyo_path_acl, head)->perm);
|
||||
break;
|
||||
case TOMOYO_TYPE_PATH2_ACL:
|
||||
perm = container_of(ptr, struct tomoyo_path2_acl, head)
|
||||
->perm;
|
||||
data_race(perm = container_of(ptr, struct tomoyo_path2_acl, head)->perm);
|
||||
break;
|
||||
case TOMOYO_TYPE_PATH_NUMBER_ACL:
|
||||
perm = container_of(ptr, struct tomoyo_path_number_acl,
|
||||
head)->perm;
|
||||
data_race(perm = container_of(ptr, struct tomoyo_path_number_acl, head)
|
||||
->perm);
|
||||
break;
|
||||
case TOMOYO_TYPE_MKDEV_ACL:
|
||||
perm = container_of(ptr, struct tomoyo_mkdev_acl,
|
||||
head)->perm;
|
||||
data_race(perm = container_of(ptr, struct tomoyo_mkdev_acl, head)->perm);
|
||||
break;
|
||||
case TOMOYO_TYPE_INET_ACL:
|
||||
perm = container_of(ptr, struct tomoyo_inet_acl,
|
||||
head)->perm;
|
||||
data_race(perm = container_of(ptr, struct tomoyo_inet_acl, head)->perm);
|
||||
break;
|
||||
case TOMOYO_TYPE_UNIX_ACL:
|
||||
perm = container_of(ptr, struct tomoyo_unix_acl,
|
||||
head)->perm;
|
||||
data_race(perm = container_of(ptr, struct tomoyo_unix_acl, head)->perm);
|
||||
break;
|
||||
case TOMOYO_TYPE_MANUAL_TASK_ACL:
|
||||
perm = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user