diff options
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/avc.c | 36 | ||||
-rw-r--r-- | security/selinux/hooks.c | 27 | ||||
-rw-r--r-- | security/selinux/include/avc.h | 18 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 10 |
4 files changed, 61 insertions, 30 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 9da6420e205..1d027e29ce8 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -471,6 +471,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) * @avd: access vector decisions * @result: result from avc_has_perm_noaudit * @a: auxiliary audit data + * @flags: VFS walk flags * * Audit the granting or denial of permissions in accordance * with the policy. This function is typically called by @@ -481,9 +482,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) * be performed under a lock, to allow the lock to be released * before calling the auditing code. */ -void avc_audit(u32 ssid, u32 tsid, +int avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct av_decision *avd, int result, struct common_audit_data *a) + struct av_decision *avd, int result, struct common_audit_data *a, + unsigned flags) { struct common_audit_data stack_data; u32 denied, audited; @@ -515,11 +517,24 @@ void avc_audit(u32 ssid, u32 tsid, else audited = requested & avd->auditallow; if (!audited) - return; + return 0; + if (!a) { a = &stack_data; COMMON_AUDIT_DATA_INIT(a, NONE); } + + /* + * When in a RCU walk do the audit on the RCU retry. This is because + * the collection of the dname in an inode audit message is not RCU + * safe. Note this may drop some audits when the situation changes + * during retry. However this is logically just as if the operation + * happened a little later. + */ + if ((a->type == LSM_AUDIT_DATA_FS) && + (flags & IPERM_FLAG_RCU)) + return -ECHILD; + a->selinux_audit_data.tclass = tclass; a->selinux_audit_data.requested = requested; a->selinux_audit_data.ssid = ssid; @@ -529,6 +544,7 @@ void avc_audit(u32 ssid, u32 tsid, a->lsm_pre_audit = avc_audit_pre_callback; a->lsm_post_audit = avc_audit_post_callback; common_lsm_audit(a); + return 0; } /** @@ -793,6 +809,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, * @tclass: target security class * @requested: requested permissions, interpreted based on @tclass * @auditdata: auxiliary audit data + * @flags: VFS walk flags * * Check the AVC to determine whether the @requested permissions are granted * for the SID pair (@ssid, @tsid), interpreting the permissions @@ -802,14 +819,19 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, * permissions are granted, -%EACCES if any permissions are denied, or * another -errno upon other errors. */ -int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, - u32 requested, struct common_audit_data *auditdata) +int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass, + u32 requested, struct common_audit_data *auditdata, + unsigned flags) { struct av_decision avd; - int rc; + int rc, rc2; rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); - avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); + + rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, + flags); + if (rc2) + return rc2; return rc; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f9c3764e485..8fb24884300 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1446,8 +1446,11 @@ static int task_has_capability(struct task_struct *tsk, } rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); - if (audit == SECURITY_CAP_AUDIT) - avc_audit(sid, sid, sclass, av, &avd, rc, &ad); + if (audit == SECURITY_CAP_AUDIT) { + int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0); + if (rc2) + return rc2; + } return rc; } @@ -1467,7 +1470,8 @@ static int task_has_system(struct task_struct *tsk, static int inode_has_perm(const struct cred *cred, struct inode *inode, u32 perms, - struct common_audit_data *adp) + struct common_audit_data *adp, + unsigned flags) { struct inode_security_struct *isec; struct common_audit_data ad; @@ -1487,7 +1491,7 @@ static int inode_has_perm(const struct cred *cred, ad.u.fs.inode = inode; } - return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); + return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); } /* Same as inode_has_perm, but pass explicit audit data containing @@ -1504,7 +1508,7 @@ static inline int dentry_has_perm(const struct cred *cred, COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.mnt = mnt; ad.u.fs.path.dentry = dentry; - return inode_has_perm(cred, inode, av, &ad); + return inode_has_perm(cred, inode, av, &ad, 0); } /* Check whether a task can use an open file descriptor to @@ -1540,7 +1544,7 @@ static int file_has_perm(const struct cred *cred, /* av is zero if only checking access to the descriptor. */ rc = 0; if (av) - rc = inode_has_perm(cred, inode, av, &ad); + rc = inode_has_perm(cred, inode, av, &ad, 0); out: return rc; @@ -1574,7 +1578,8 @@ static int may_create(struct inode *dir, return rc; if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { - rc = security_transition_sid(sid, dsec->sid, tclass, NULL, &newsid); + rc = security_transition_sid(sid, dsec->sid, tclass, + &dentry->d_name, &newsid); if (rc) return rc; } @@ -2103,7 +2108,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, file = file_priv->file; inode = file->f_path.dentry->d_inode; if (inode_has_perm(cred, inode, - FILE__READ | FILE__WRITE, NULL)) { + FILE__READ | FILE__WRITE, NULL, 0)) { drop_tty = 1; } } @@ -2635,7 +2640,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na return dentry_has_perm(cred, NULL, dentry, FILE__READ); } -static int selinux_inode_permission(struct inode *inode, int mask) +static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) { const struct cred *cred = current_cred(); struct common_audit_data ad; @@ -2657,7 +2662,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) perms = file_mask_to_av(inode->i_mode, mask); - return inode_has_perm(cred, inode, perms, &ad); + return inode_has_perm(cred, inode, perms, &ad, flags); } static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) @@ -3205,7 +3210,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) * new inode label or new policy. * This check is not redundant - do not remove. */ - return inode_has_perm(cred, inode, open_file_to_av(file), NULL); + return inode_has_perm(cred, inode, open_file_to_av(file), NULL, 0); } /* task security operations */ diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 5615081b73e..e77b2ac2908 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -54,11 +54,11 @@ struct avc_cache_stats { void __init avc_init(void); -void avc_audit(u32 ssid, u32 tsid, +int avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd, int result, - struct common_audit_data *a); + struct common_audit_data *a, unsigned flags); #define AVC_STRICT 1 /* Ignore permissive mode. */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, @@ -66,9 +66,17 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, unsigned flags, struct av_decision *avd); -int avc_has_perm(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct common_audit_data *auditdata); +int avc_has_perm_flags(u32 ssid, u32 tsid, + u16 tclass, u32 requested, + struct common_audit_data *auditdata, + unsigned); + +static inline int avc_has_perm(u32 ssid, u32 tsid, + u16 tclass, u32 requested, + struct common_audit_data *auditdata) +{ + return avc_has_perm_flags(ssid, tsid, tclass, requested, auditdata, 0); +} u32 avc_policy_seqno(void); diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index e7b850ad57e..7102457661d 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -502,7 +502,7 @@ static int policydb_index(struct policydb *p) goto out; rc = flex_array_prealloc(p->type_val_to_struct_array, 0, - p->p_types.nprim - 1, GFP_KERNEL | __GFP_ZERO); + p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); if (rc) goto out; @@ -519,7 +519,7 @@ static int policydb_index(struct policydb *p) goto out; rc = flex_array_prealloc(p->sym_val_to_name[i], - 0, p->symtab[i].nprim - 1, + 0, p->symtab[i].nprim, GFP_KERNEL | __GFP_ZERO); if (rc) goto out; @@ -1819,8 +1819,6 @@ static int filename_trans_read(struct policydb *p, void *fp) goto out; nel = le32_to_cpu(buf[0]); - printk(KERN_ERR "%s: nel=%d\n", __func__, nel); - last = p->filename_trans; while (last && last->next) last = last->next; @@ -1857,8 +1855,6 @@ static int filename_trans_read(struct policydb *p, void *fp) goto out; name[len] = 0; - printk(KERN_ERR "%s: ft=%p ft->name=%p ft->name=%s\n", __func__, ft, ft->name, ft->name); - rc = next_entry(buf, fp, sizeof(u32) * 4); if (rc) goto out; @@ -2375,7 +2371,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; /* preallocate so we don't have to worry about the put ever failing */ - rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1, + rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); if (rc) goto bad; |