diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 22:41:25 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 22:41:25 +0300 |
commit | b793c005ceabf6db0b17494b0ec67ade6796bb34 (patch) | |
tree | 080c884f04254403ec9564742f591a9fd9b7e95a /security/selinux/hooks.c | |
parent | 6f0a2fc1feb19bd142961a39dc118e7e55418b3f (diff) | |
parent | 07f081fb5057b2ea98baeca3a47bf0eb33e94aa1 (diff) | |
download | linux-b793c005ceabf6db0b17494b0ec67ade6796bb34.tar.xz |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"Highlights:
- PKCS#7 support added to support signed kexec, also utilized for
module signing. See comments in 3f1e1bea.
** NOTE: this requires linking against the OpenSSL library, which
must be installed, e.g. the openssl-devel on Fedora **
- Smack
- add IPv6 host labeling; ignore labels on kernel threads
- support smack labeling mounts which use binary mount data
- SELinux:
- add ioctl whitelisting (see
http://kernsec.org/files/lss2015/vanderstoep.pdf)
- fix mprotect PROT_EXEC regression caused by mm change
- Seccomp:
- add ptrace options for suspend/resume"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (57 commits)
PKCS#7: Add OIDs for sha224, sha284 and sha512 hash algos and use them
Documentation/Changes: Now need OpenSSL devel packages for module signing
scripts: add extract-cert and sign-file to .gitignore
modsign: Handle signing key in source tree
modsign: Use if_changed rule for extracting cert from module signing key
Move certificate handling to its own directory
sign-file: Fix warning about BIO_reset() return value
PKCS#7: Add MODULE_LICENSE() to test module
Smack - Fix build error with bringup unconfigured
sign-file: Document dependency on OpenSSL devel libraries
PKCS#7: Appropriately restrict authenticated attributes and content type
KEYS: Add a name for PKEY_ID_PKCS7
PKCS#7: Improve and export the X.509 ASN.1 time object decoder
modsign: Use extract-cert to process CONFIG_SYSTEM_TRUSTED_KEYS
extract-cert: Cope with multiple X.509 certificates in a single file
sign-file: Generate CMS message as signature instead of PKCS#7
PKCS#7: Support CMS messages also [RFC5652]
X.509: Change recorded SKID & AKID to not include Subject or Issuer
PKCS#7: Check content type and versions
MAINTAINERS: The keyrings mailing list has moved
...
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 147 |
1 files changed, 97 insertions, 50 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index cdf4c589a391..e4369d86e588 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -254,10 +254,21 @@ static void inode_free_security(struct inode *inode) struct inode_security_struct *isec = inode->i_security; struct superblock_security_struct *sbsec = inode->i_sb->s_security; - spin_lock(&sbsec->isec_lock); - if (!list_empty(&isec->list)) + /* + * As not all inode security structures are in a list, we check for + * empty list outside of the lock to make sure that we won't waste + * time taking a lock doing nothing. + * + * The list_del_init() function can be safely called more than once. + * It should not be possible for this function to be called with + * concurrent list_add(), but for better safety against future changes + * in the code, we use list_empty_careful() here. + */ + if (!list_empty_careful(&isec->list)) { + spin_lock(&sbsec->isec_lock); list_del_init(&isec->list); - spin_unlock(&sbsec->isec_lock); + spin_unlock(&sbsec->isec_lock); + } /* * The inode may still be referenced in a path walk and @@ -1698,6 +1709,32 @@ out: return rc; } +/* + * Determine the label for an inode that might be unioned. + */ +static int selinux_determine_inode_label(const struct inode *dir, + const struct qstr *name, + u16 tclass, + u32 *_new_isid) +{ + const struct superblock_security_struct *sbsec = dir->i_sb->s_security; + const struct inode_security_struct *dsec = dir->i_security; + const struct task_security_struct *tsec = current_security(); + + if ((sbsec->flags & SE_SBINITIALIZED) && + (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) { + *_new_isid = sbsec->mntpoint_sid; + } else if ((sbsec->flags & SBLABEL_MNT) && + tsec->create_sid) { + *_new_isid = tsec->create_sid; + } else { + return security_transition_sid(tsec->sid, dsec->sid, tclass, + name, _new_isid); + } + + return 0; +} + /* Check whether a task can create a file. */ static int may_create(struct inode *dir, struct dentry *dentry, @@ -1714,7 +1751,6 @@ static int may_create(struct inode *dir, sbsec = dir->i_sb->s_security; sid = tsec->sid; - newsid = tsec->create_sid; ad.type = LSM_AUDIT_DATA_DENTRY; ad.u.dentry = dentry; @@ -1725,12 +1761,10 @@ static int may_create(struct inode *dir, if (rc) return rc; - if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { - rc = security_transition_sid(sid, dsec->sid, tclass, - &dentry->d_name, &newsid); - if (rc) - return rc; - } + rc = selinux_determine_inode_label(dir, &dentry->d_name, tclass, + &newsid); + if (rc) + return rc; rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); if (rc) @@ -2704,32 +2738,14 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, struct qstr *name, void **ctx, u32 *ctxlen) { - const struct cred *cred = current_cred(); - struct task_security_struct *tsec; - struct inode_security_struct *dsec; - struct superblock_security_struct *sbsec; - struct inode *dir = d_backing_inode(dentry->d_parent); u32 newsid; int rc; - tsec = cred->security; - dsec = dir->i_security; - sbsec = dir->i_sb->s_security; - - if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { - newsid = tsec->create_sid; - } else { - rc = security_transition_sid(tsec->sid, dsec->sid, - inode_mode_to_security_class(mode), - name, - &newsid); - if (rc) { - printk(KERN_WARNING - "%s: security_transition_sid failed, rc=%d\n", - __func__, -rc); - return rc; - } - } + rc = selinux_determine_inode_label(d_inode(dentry->d_parent), name, + inode_mode_to_security_class(mode), + &newsid); + if (rc) + return rc; return security_sid_to_context(newsid, (char **)ctx, ctxlen); } @@ -2752,22 +2768,12 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, sid = tsec->sid; newsid = tsec->create_sid; - if ((sbsec->flags & SE_SBINITIALIZED) && - (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) - newsid = sbsec->mntpoint_sid; - else if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { - rc = security_transition_sid(sid, dsec->sid, - inode_mode_to_security_class(inode->i_mode), - qstr, &newsid); - if (rc) { - printk(KERN_WARNING "%s: " - "security_transition_sid failed, rc=%d (dev=%s " - "ino=%ld)\n", - __func__, - -rc, inode->i_sb->s_id, inode->i_ino); - return rc; - } - } + rc = selinux_determine_inode_label( + dir, qstr, + inode_mode_to_security_class(inode->i_mode), + &newsid); + if (rc) + return rc; /* Possibly defer initialization to selinux_complete_init. */ if (sbsec->flags & SE_SBINITIALIZED) { @@ -3228,6 +3234,46 @@ static void selinux_file_free_security(struct file *file) file_free_security(file); } +/* + * Check whether a task has the ioctl permission and cmd + * operation to an inode. + */ +int ioctl_has_perm(const struct cred *cred, struct file *file, + u32 requested, u16 cmd) +{ + struct common_audit_data ad; + struct file_security_struct *fsec = file->f_security; + struct inode *inode = file_inode(file); + struct inode_security_struct *isec = inode->i_security; + struct lsm_ioctlop_audit ioctl; + u32 ssid = cred_sid(cred); + int rc; + u8 driver = cmd >> 8; + u8 xperm = cmd & 0xff; + + ad.type = LSM_AUDIT_DATA_IOCTL_OP; + ad.u.op = &ioctl; + ad.u.op->cmd = cmd; + ad.u.op->path = file->f_path; + + if (ssid != fsec->sid) { + rc = avc_has_perm(ssid, fsec->sid, + SECCLASS_FD, + FD__USE, + &ad); + if (rc) + goto out; + } + + if (unlikely(IS_PRIVATE(inode))) + return 0; + + rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, + requested, driver, xperm, &ad); +out: + return rc; +} + static int selinux_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -3270,7 +3316,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, * to the file's ioctl() function. */ default: - error = file_has_perm(cred, file, FILE__IOCTL); + error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); } return error; } @@ -4520,6 +4566,7 @@ static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority sksec->peer_sid = SECINITSID_UNLABELED; sksec->sid = SECINITSID_UNLABELED; + sksec->sclass = SECCLASS_SOCKET; selinux_netlbl_sk_security_reset(sksec); sk->sk_security = sksec; |