diff options
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/hooks.c | 28 | ||||
-rw-r--r-- | security/selinux/include/avc.h | 4 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 8 | ||||
-rw-r--r-- | security/selinux/include/security.h | 4 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 3 | ||||
-rw-r--r-- | security/selinux/ss/hashtab.c | 3 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 19 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 2 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 20 |
9 files changed, 86 insertions, 5 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 595ceb314aeb..c95a5874bf7d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3181,6 +3181,8 @@ static inline void task_avdcache_update(struct task_security_struct *tsec, tsec->avdcache.dir[spot].audited = audited; tsec->avdcache.dir[spot].allowed = avd->allowed; tsec->avdcache.dir[spot].permissive = avd->flags & AVD_FLAGS_PERMISSIVE; + tsec->avdcache.permissive_neveraudit = + (avd->flags == (AVD_FLAGS_PERMISSIVE|AVD_FLAGS_NEVERAUDIT)); } /** @@ -3207,10 +3209,13 @@ static int selinux_inode_permission(struct inode *inode, int requested) if (!mask) return 0; + tsec = selinux_cred(current_cred()); + if (task_avdcache_permnoaudit(tsec)) + return 0; + isec = inode_security_rcu(inode, requested & MAY_NOT_BLOCK); if (IS_ERR(isec)) return PTR_ERR(isec); - tsec = selinux_cred(current_cred()); perms = file_mask_to_av(inode->i_mode, mask); rc = task_avdcache_search(tsec, isec, &avdc); @@ -3274,6 +3279,13 @@ static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, static int selinux_inode_getattr(const struct path *path) { + struct task_security_struct *tsec; + + tsec = selinux_cred(current_cred()); + + if (task_avdcache_permnoaudit(tsec)) + return 0; + return path_has_perm(current_cred(), path, FILE__GETATTR); } @@ -3480,6 +3492,18 @@ static int selinux_inode_removexattr(struct mnt_idmap *idmap, return -EACCES; } +static int selinux_inode_file_setattr(struct dentry *dentry, + struct file_kattr *fa) +{ + return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); +} + +static int selinux_inode_file_getattr(struct dentry *dentry, + struct file_kattr *fa) +{ + return dentry_has_perm(current_cred(), dentry, FILE__GETATTR); +} + static int selinux_path_notify(const struct path *path, u64 mask, unsigned int obj_type) { @@ -7350,6 +7374,8 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr), LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr), LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr), + LSM_HOOK_INIT(inode_file_getattr, selinux_inode_file_getattr), + LSM_HOOK_INIT(inode_file_setattr, selinux_inode_file_setattr), LSM_HOOK_INIT(inode_set_acl, selinux_inode_set_acl), LSM_HOOK_INIT(inode_get_acl, selinux_inode_get_acl), LSM_HOOK_INIT(inode_remove_acl, selinux_inode_remove_acl), diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 281f40103663..01b5167fee1a 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -65,6 +65,10 @@ static inline u32 avc_audit_required(u32 requested, struct av_decision *avd, int result, u32 auditdeny, u32 *deniedp) { u32 denied, audited; + + if (avd->flags & AVD_FLAGS_NEVERAUDIT) + return 0; + denied = requested & ~avd->allowed; if (unlikely(denied)) { audited = denied & avd->auditdeny; diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 6ee7dc4dfd6e..1d7ac59015a1 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -49,9 +49,17 @@ struct task_security_struct { u32 seqno; /* AVC sequence number */ unsigned int dir_spot; /* dir cache index to check first */ struct avdc_entry dir[TSEC_AVDC_DIR_SIZE]; /* dir entries */ + bool permissive_neveraudit; /* permissive and neveraudit */ } avdcache; } __randomize_layout; +static inline bool task_avdcache_permnoaudit(struct task_security_struct *tsec) +{ + return (tsec->avdcache.permissive_neveraudit && + tsec->sid == tsec->avdcache.sid && + tsec->avdcache.seqno == avc_policy_seqno()); +} + enum label_initialized { LABEL_INVALID, /* invalid or not initialized */ LABEL_INITIALIZED, /* initialized */ diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 278c144c22d6..8201e6a3ac0f 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -47,10 +47,11 @@ #define POLICYDB_VERSION_GLBLUB 32 #define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */ #define POLICYDB_VERSION_COND_XPERMS 34 /* extended permissions in conditional policies */ +#define POLICYDB_VERSION_NEVERAUDIT 35 /* neveraudit types */ /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COND_XPERMS +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_NEVERAUDIT /* Mask for just the mount related flags */ #define SE_MNTMASK 0x0f @@ -260,6 +261,7 @@ struct extended_perms { /* definitions of av_decision.flags */ #define AVD_FLAGS_PERMISSIVE 0x0001 +#define AVD_FLAGS_NEVERAUDIT 0x0002 void security_compute_av(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index e67a8ce4b64c..9aa1d03ab612 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1072,6 +1072,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) pr_warn_ratelimited("SELinux: %s (%d) wrote to /sys/fs/selinux/user!" " This will not be supported in the future; please update your" " userspace.\n", current->comm, current->pid); + ssleep(5); length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__COMPUTE_USER, @@ -2097,8 +2098,6 @@ err: pr_err("SELinux: %s: failed while creating inodes\n", __func__); - selinux_fs_info_free(sb); - return ret; } diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 383fd2d70878..1382eb3bfde1 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -40,7 +40,8 @@ int hashtab_init(struct hashtab *h, u32 nel_hint) h->htable = NULL; if (size) { - h->htable = kcalloc(size, sizeof(*h->htable), GFP_KERNEL); + h->htable = kcalloc(size, sizeof(*h->htable), + GFP_KERNEL | __GFP_NOWARN); if (!h->htable) return -ENOMEM; h->size = size; diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 9ea971943713..91df3db6a88c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -160,6 +160,11 @@ static const struct policydb_compat_info policydb_compat[] = { .sym_num = SYM_NUM, .ocon_num = OCON_NUM, }, + { + .version = POLICYDB_VERSION_NEVERAUDIT, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, }; static const struct policydb_compat_info * @@ -531,6 +536,7 @@ static void policydb_init(struct policydb *p) ebitmap_init(&p->filename_trans_ttypes); ebitmap_init(&p->policycaps); ebitmap_init(&p->permissive_map); + ebitmap_init(&p->neveraudit_map); } /* @@ -852,6 +858,7 @@ void policydb_destroy(struct policydb *p) ebitmap_destroy(&p->filename_trans_ttypes); ebitmap_destroy(&p->policycaps); ebitmap_destroy(&p->permissive_map); + ebitmap_destroy(&p->neveraudit_map); } /* @@ -2538,6 +2545,12 @@ int policydb_read(struct policydb *p, struct policy_file *fp) goto bad; } + if (p->policyvers >= POLICYDB_VERSION_NEVERAUDIT) { + rc = ebitmap_read(&p->neveraudit_map, fp); + if (rc) + goto bad; + } + rc = -EINVAL; info = policydb_lookup_compat(p->policyvers); if (!info) { @@ -3723,6 +3736,12 @@ int policydb_write(struct policydb *p, struct policy_file *fp) return rc; } + if (p->policyvers >= POLICYDB_VERSION_NEVERAUDIT) { + rc = ebitmap_write(&p->neveraudit_map, fp); + if (rc) + return rc; + } + num_syms = info->sym_num; for (i = 0; i < num_syms; i++) { struct policy_data pd; diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 25650224b6e7..89a180b1742f 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -300,6 +300,8 @@ struct policydb { struct ebitmap permissive_map; + struct ebitmap neveraudit_map; + /* length of this policy when it was loaded */ size_t len; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d185754c2786..713130bd43c4 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1153,6 +1153,14 @@ void security_compute_av(u32 ssid, if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) avd->flags |= AVD_FLAGS_PERMISSIVE; + /* neveraudit domain? */ + if (ebitmap_get_bit(&policydb->neveraudit_map, scontext->type)) + avd->flags |= AVD_FLAGS_NEVERAUDIT; + + /* both permissive and neveraudit => allow */ + if (avd->flags == (AVD_FLAGS_PERMISSIVE|AVD_FLAGS_NEVERAUDIT)) + goto allow; + tcontext = sidtab_search(sidtab, tsid); if (!tcontext) { pr_err("SELinux: %s: unrecognized SID %d\n", @@ -1172,6 +1180,8 @@ void security_compute_av(u32 ssid, policydb->allow_unknown); out: rcu_read_unlock(); + if (avd->flags & AVD_FLAGS_NEVERAUDIT) + avd->auditallow = avd->auditdeny = 0; return; allow: avd->allowed = 0xffffffff; @@ -1208,6 +1218,14 @@ void security_compute_av_user(u32 ssid, if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) avd->flags |= AVD_FLAGS_PERMISSIVE; + /* neveraudit domain? */ + if (ebitmap_get_bit(&policydb->neveraudit_map, scontext->type)) + avd->flags |= AVD_FLAGS_NEVERAUDIT; + + /* both permissive and neveraudit => allow */ + if (avd->flags == (AVD_FLAGS_PERMISSIVE|AVD_FLAGS_NEVERAUDIT)) + goto allow; + tcontext = sidtab_search(sidtab, tsid); if (!tcontext) { pr_err("SELinux: %s: unrecognized SID %d\n", @@ -1225,6 +1243,8 @@ void security_compute_av_user(u32 ssid, NULL); out: rcu_read_unlock(); + if (avd->flags & AVD_FLAGS_NEVERAUDIT) + avd->auditallow = avd->auditdeny = 0; return; allow: avd->allowed = 0xffffffff; |