diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-21 16:54:54 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-21 16:54:54 -0800 |
| commit | d1fec2214bfbba5c759eb154b3744edb8c460384 (patch) | |
| tree | cf4cc0421252e8320207097c6f6c6dba13f4a518 /security/selinux/hooks.c | |
| parent | e210761fb3ba172ecb44b717711af1d1b5d27cbf (diff) | |
| parent | 365982aba1f264dba26f0908700d62bfa046918c (diff) | |
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
Diffstat (limited to 'security/selinux/hooks.c')
| -rw-r--r-- | security/selinux/hooks.c | 141 |
1 files changed, 115 insertions, 26 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 644b17ec9e63..af2994adf9dd 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -484,6 +484,55 @@ 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); + 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,30 +541,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); - 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; @@ -554,7 +582,6 @@ static int sb_finish_set_opts(struct super_block *sb) spin_lock(&sbsec->isec_lock); } spin_unlock(&sbsec->isec_lock); -out: return rc; } @@ -1120,7 +1147,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) @@ -2934,6 +2962,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); @@ -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) { 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; @@ -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_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), |
