Loading security/selinux/avc.c +18 −410 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #include <linux/init.h> #include <linux/skbuff.h> #include <linux/percpu.h> #include <linux/list.h> #include <net/sock.h> #include <linux/un.h> #include <net/af_unix.h> Loading @@ -49,7 +48,6 @@ struct avc_entry { u32 tsid; u16 tclass; struct av_decision avd; struct avc_operation_node *ops_node; }; struct avc_node { Loading @@ -66,16 +64,6 @@ struct avc_cache { u32 latest_notif; /* latest revocation notification */ }; struct avc_operation_decision_node { struct operation_decision od; struct list_head od_list; }; struct avc_operation_node { struct operation ops; struct list_head od_head; /* list of operation_decision_node */ }; struct avc_callback_node { int (*callback) (u32 event); u32 events; Loading @@ -92,9 +80,6 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; static struct avc_cache avc_cache; static struct avc_callback_node *avc_callbacks; static struct kmem_cache *avc_node_cachep; static struct kmem_cache *avc_operation_decision_node_cachep; static struct kmem_cache *avc_operation_node_cachep; static struct kmem_cache *avc_operation_perm_cachep; static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) { Loading Loading @@ -186,16 +171,6 @@ void __init avc_init(void) avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), 0, SLAB_PANIC, NULL); avc_operation_node_cachep = kmem_cache_create("avc_operation_node", sizeof(struct avc_operation_node), 0, SLAB_PANIC, NULL); avc_operation_decision_node_cachep = kmem_cache_create( "avc_operation_decision_node", sizeof(struct avc_operation_decision_node), 0, SLAB_PANIC, NULL); avc_operation_perm_cachep = kmem_cache_create("avc_operation_perm", sizeof(struct operation_perm), 0, SLAB_PANIC, NULL); audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); } Loading Loading @@ -230,269 +205,9 @@ int avc_get_hash_stats(char *page) slots_used, AVC_CACHE_SLOTS, max_chain_len); } /* * using a linked list for operation_decision lookup because the list is * always small. i.e. less than 5, typically 1 */ static struct operation_decision *avc_operation_lookup(u8 type, struct avc_operation_node *ops_node) { struct avc_operation_decision_node *od_node; struct operation_decision *od = NULL; list_for_each_entry(od_node, &ops_node->od_head, od_list) { if (od_node->od.type != type) continue; od = &od_node->od; break; } return od; } static inline unsigned int avc_operation_has_perm(struct operation_decision *od, u16 cmd, u8 specified) { unsigned int rc = 0; u8 num = cmd & 0xff; if ((specified == OPERATION_ALLOWED) && (od->specified & OPERATION_ALLOWED)) rc = security_operation_test(od->allowed->perms, num); else if ((specified == OPERATION_AUDITALLOW) && (od->specified & OPERATION_AUDITALLOW)) rc = security_operation_test(od->auditallow->perms, num); else if ((specified == OPERATION_DONTAUDIT) && (od->specified & OPERATION_DONTAUDIT)) rc = security_operation_test(od->dontaudit->perms, num); return rc; } static void avc_operation_allow_perm(struct avc_operation_node *node, u16 cmd) { struct operation_decision *od; u8 type; u8 num; type = cmd >> 8; num = cmd & 0xff; security_operation_set(node->ops.type, type); od = avc_operation_lookup(type, node); if (od && od->allowed) security_operation_set(od->allowed->perms, num); } static void avc_operation_decision_free( struct avc_operation_decision_node *od_node) { struct operation_decision *od; od = &od_node->od; if (od->allowed) kmem_cache_free(avc_operation_perm_cachep, od->allowed); if (od->auditallow) kmem_cache_free(avc_operation_perm_cachep, od->auditallow); if (od->dontaudit) kmem_cache_free(avc_operation_perm_cachep, od->dontaudit); kmem_cache_free(avc_operation_decision_node_cachep, od_node); } static void avc_operation_free(struct avc_operation_node *ops_node) { struct avc_operation_decision_node *od_node; if (!ops_node) return; list_for_each_entry(od_node, &ops_node->od_head, od_list) avc_operation_decision_free(od_node); kmem_cache_free(avc_operation_node_cachep, ops_node); } static void avc_copy_operation_decision(struct operation_decision *dest, struct operation_decision *src) { dest->type = src->type; dest->specified = src->specified; if (dest->specified & OPERATION_ALLOWED) memcpy(dest->allowed->perms, src->allowed->perms, sizeof(src->allowed->perms)); if (dest->specified & OPERATION_AUDITALLOW) memcpy(dest->auditallow->perms, src->auditallow->perms, sizeof(src->auditallow->perms)); if (dest->specified & OPERATION_DONTAUDIT) memcpy(dest->dontaudit->perms, src->dontaudit->perms, sizeof(src->dontaudit->perms)); } /* * similar to avc_copy_operation_decision, but only copy decision * information relevant to this command */ static inline void avc_quick_copy_operation_decision(u16 cmd, struct operation_decision *dest, struct operation_decision *src) { /* * compute index of the u32 of the 256 bits (8 u32s) that contain this * command permission */ u8 i = (0xff & cmd) >> 5; dest->specified = src->specified; if (dest->specified & OPERATION_ALLOWED) dest->allowed->perms[i] = src->allowed->perms[i]; if (dest->specified & OPERATION_AUDITALLOW) dest->auditallow->perms[i] = src->auditallow->perms[i]; if (dest->specified & OPERATION_DONTAUDIT) dest->dontaudit->perms[i] = src->dontaudit->perms[i]; } static struct avc_operation_decision_node *avc_operation_decision_alloc(u8 specified) { struct avc_operation_decision_node *node; struct operation_decision *od; node = kmem_cache_zalloc(avc_operation_decision_node_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); if (!node) return NULL; od = &node->od; if (specified & OPERATION_ALLOWED) { od->allowed = kmem_cache_zalloc(avc_operation_perm_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); if (!od->allowed) goto error; } if (specified & OPERATION_AUDITALLOW) { od->auditallow = kmem_cache_zalloc(avc_operation_perm_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); if (!od->auditallow) goto error; } if (specified & OPERATION_DONTAUDIT) { od->dontaudit = kmem_cache_zalloc(avc_operation_perm_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); if (!od->dontaudit) goto error; } return node; error: avc_operation_decision_free(node); return NULL; } static int avc_add_operation(struct avc_node *node, struct operation_decision *od) { struct avc_operation_decision_node *dest_od; node->ae.ops_node->ops.len++; dest_od = avc_operation_decision_alloc(od->specified); if (!dest_od) return -ENOMEM; avc_copy_operation_decision(&dest_od->od, od); list_add(&dest_od->od_list, &node->ae.ops_node->od_head); return 0; } static struct avc_operation_node *avc_operation_alloc(void) { struct avc_operation_node *ops; ops = kmem_cache_zalloc(avc_operation_node_cachep, GFP_ATOMIC|__GFP_NOMEMALLOC); if (!ops) return ops; INIT_LIST_HEAD(&ops->od_head); return ops; } static int avc_operation_populate(struct avc_node *node, struct avc_operation_node *src) { struct avc_operation_node *dest; struct avc_operation_decision_node *dest_od; struct avc_operation_decision_node *src_od; if (src->ops.len == 0) return 0; dest = avc_operation_alloc(); if (!dest) return -ENOMEM; memcpy(dest->ops.type, &src->ops.type, sizeof(dest->ops.type)); dest->ops.len = src->ops.len; /* for each source od allocate a destination od and copy */ list_for_each_entry(src_od, &src->od_head, od_list) { dest_od = avc_operation_decision_alloc(src_od->od.specified); if (!dest_od) goto error; avc_copy_operation_decision(&dest_od->od, &src_od->od); list_add(&dest_od->od_list, &dest->od_head); } node->ae.ops_node = dest; return 0; error: avc_operation_free(dest); return -ENOMEM; } static inline u32 avc_operation_audit_required(u32 requested, struct av_decision *avd, struct operation_decision *od, u16 cmd, int result, u32 *deniedp) { u32 denied, audited; denied = requested & ~avd->allowed; if (unlikely(denied)) { audited = denied & avd->auditdeny; if (audited && od) { if (avc_operation_has_perm(od, cmd, OPERATION_DONTAUDIT)) audited &= ~requested; } } else if (result) { audited = denied = requested; } else { audited = requested & avd->auditallow; if (audited && od) { if (!avc_operation_has_perm(od, cmd, OPERATION_AUDITALLOW)) audited &= ~requested; } } *deniedp = denied; return audited; } static inline int avc_operation_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd, struct operation_decision *od, u16 cmd, int result, struct common_audit_data *ad) { u32 audited, denied; audited = avc_operation_audit_required( requested, avd, od, cmd, result, &denied); if (likely(!audited)) return 0; return slow_avc_audit(ssid, tsid, tclass, requested, audited, denied, result, ad, 0); } static void avc_node_free(struct rcu_head *rhead) { struct avc_node *node = container_of(rhead, struct avc_node, rhead); avc_operation_free(node->ae.ops_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); } Loading @@ -506,7 +221,6 @@ static void avc_node_delete(struct avc_node *node) static void avc_node_kill(struct avc_node *node) { avc_operation_free(node->ae.ops_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); atomic_dec(&avc_cache.active_nodes); Loading Loading @@ -653,7 +367,6 @@ static int avc_latest_notif_update(int seqno, int is_insert) * @tsid: target security identifier * @tclass: target security class * @avd: resulting av decision * @ops: resulting operation decisions * * Insert an AVC entry for the SID pair * (@ssid, @tsid) and class @tclass. Loading @@ -665,9 +378,7 @@ static int avc_latest_notif_update(int seqno, int is_insert) * the access vectors into a cache entry, returns * avc_node inserted. Otherwise, this function returns NULL. */ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct avc_operation_node *ops_node) static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) { struct avc_node *pos, *node = NULL; int hvalue; Loading @@ -680,15 +391,10 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, if (node) { struct hlist_head *head; spinlock_t *lock; int rc = 0; hvalue = avc_hash(ssid, tsid, tclass); avc_node_populate(node, ssid, tsid, tclass, avd); rc = avc_operation_populate(node, ops_node); if (rc) { kmem_cache_free(avc_node_cachep, node); return NULL; } head = &avc_cache.slots[hvalue]; lock = &avc_cache.slots_lock[hvalue]; Loading Loading @@ -837,17 +543,14 @@ static inline int avc_sidcmp(u32 x, u32 y) * @perms : Permission mask bits * @ssid,@tsid,@tclass : identifier of an AVC entry * @seqno : sequence number when decision was made * @od: operation_decision to be added to the node * * if a valid AVC entry doesn't exist,this function returns -ENOENT. * if kmalloc() called internal returns NULL, this function returns -ENOMEM. * otherwise, this function updates the AVC entry. The original AVC-entry object * will release later by RCU. */ static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, u16 tclass, u32 seqno, struct operation_decision *od, u32 flags) static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, u32 seqno) { int hvalue, rc = 0; unsigned long flag; Loading Loading @@ -891,19 +594,9 @@ static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); if (orig->ae.ops_node) { rc = avc_operation_populate(node, orig->ae.ops_node); if (rc) { kmem_cache_free(avc_node_cachep, node); goto out_unlock; } } switch (event) { case AVC_CALLBACK_GRANT: node->ae.avd.allowed |= perms; if (node->ae.ops_node && (flags & AVC_OPERATION_CMD)) avc_operation_allow_perm(node->ae.ops_node, cmd); break; case AVC_CALLBACK_TRY_REVOKE: case AVC_CALLBACK_REVOKE: Loading @@ -921,9 +614,6 @@ static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, case AVC_CALLBACK_AUDITDENY_DISABLE: node->ae.avd.auditdeny &= ~perms; break; case AVC_CALLBACK_ADD_OPERATION: avc_add_operation(node, od); break; } avc_node_replace(node, orig); out_unlock: Loading Loading @@ -995,19 +685,17 @@ int avc_ss_reset(u32 seqno) * results in a bigger stack frame. */ static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct avc_operation_node *ops_node) u16 tclass, struct av_decision *avd) { rcu_read_unlock(); INIT_LIST_HEAD(&ops_node->od_head); security_compute_av(ssid, tsid, tclass, avd, &ops_node->ops); security_compute_av(ssid, tsid, tclass, avd); rcu_read_lock(); return avc_insert(ssid, tsid, tclass, avd, ops_node); return avc_insert(ssid, tsid, tclass, avd); } static noinline int avc_denied(u32 ssid, u32 tsid, u16 tclass, u32 requested, u16 cmd, unsigned flags, unsigned flags, struct av_decision *avd) { if (flags & AVC_STRICT) Loading @@ -1016,92 +704,11 @@ static noinline int avc_denied(u32 ssid, u32 tsid, if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) return -EACCES; avc_update_node(AVC_CALLBACK_GRANT, requested, cmd, ssid, tsid, tclass, avd->seqno, NULL, flags); avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, tsid, tclass, avd->seqno); return 0; } /* * ioctl commands are comprised of four fields, direction, size, type, and * number. The avc operation logic filters based on two of them: * * type: or code, typically unique to each driver * number: or function * * For example, 0x89 is a socket type, and number 0x27 is the get hardware * address function. */ int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested, u16 cmd, struct common_audit_data *ad) { struct avc_node *node; struct av_decision avd; u32 denied; struct operation_decision *od = NULL; struct operation_decision od_local; struct operation_perm allowed; struct operation_perm auditallow; struct operation_perm dontaudit; struct avc_operation_node local_ops_node; struct avc_operation_node *ops_node; u8 type = cmd >> 8; int rc = 0, rc2; ops_node = &local_ops_node; BUG_ON(!requested); rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass); if (unlikely(!node)) { node = avc_compute_av(ssid, tsid, tclass, &avd, ops_node); } else { memcpy(&avd, &node->ae.avd, sizeof(avd)); ops_node = node->ae.ops_node; } /* if operations are not defined, only consider av_decision */ if (!ops_node || !ops_node->ops.len) goto decision; od_local.allowed = &allowed; od_local.auditallow = &auditallow; od_local.dontaudit = &dontaudit; /* lookup operation decision */ od = avc_operation_lookup(type, ops_node); if (unlikely(!od)) { /* Compute operation decision if type is flagged */ if (!security_operation_test(ops_node->ops.type, type)) { avd.allowed &= ~requested; goto decision; } rcu_read_unlock(); security_compute_operation(ssid, tsid, tclass, type, &od_local); rcu_read_lock(); avc_update_node(AVC_CALLBACK_ADD_OPERATION, requested, cmd, ssid, tsid, tclass, avd.seqno, &od_local, 0); } else { avc_quick_copy_operation_decision(cmd, &od_local, od); } od = &od_local; if (!avc_operation_has_perm(od, cmd, OPERATION_ALLOWED)) avd.allowed &= ~requested; decision: denied = requested & ~(avd.allowed); if (unlikely(denied)) rc = avc_denied(ssid, tsid, tclass, requested, cmd, AVC_OPERATION_CMD, &avd); rcu_read_unlock(); rc2 = avc_operation_audit(ssid, tsid, tclass, requested, &avd, od, cmd, rc, ad); if (rc2) return rc2; return rc; } /** * avc_has_perm_noaudit - Check permissions but perform no auditing. Loading Loading @@ -1129,7 +736,6 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, struct av_decision *avd) { struct avc_node *node; struct avc_operation_node ops_node; int rc = 0; u32 denied; Loading @@ -1138,14 +744,16 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass); if (unlikely(!node)) node = avc_compute_av(ssid, tsid, tclass, avd, &ops_node); else if (unlikely(!node)) { node = avc_compute_av(ssid, tsid, tclass, avd); } else { memcpy(avd, &node->ae.avd, sizeof(*avd)); avd = &node->ae.avd; } denied = requested & ~(avd->allowed); if (unlikely(denied)) rc = avc_denied(ssid, tsid, tclass, requested, 0, flags, avd); rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); rcu_read_unlock(); return rc; Loading security/selinux/hooks.c +1 −39 Original line number Diff line number Diff line Loading @@ -3241,44 +3241,6 @@ 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; 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_operation(ssid, isec->sid, isec->sclass, requested, cmd, &ad); out: return rc; } static int selinux_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { Loading Loading @@ -3321,7 +3283,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, * to the file's ioctl() function. */ default: error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); error = file_has_perm(cred, file, FILE__IOCTL); } return error; } Loading security/selinux/include/avc.h +0 −5 Original line number Diff line number Diff line Loading @@ -142,7 +142,6 @@ static inline int avc_audit(u32 ssid, u32 tsid, } #define AVC_STRICT 1 /* Ignore permissive mode. */ #define AVC_OPERATION_CMD 2 /* ignore command when updating operations */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested, unsigned flags, Loading @@ -152,9 +151,6 @@ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata); int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested, u16 cmd, struct common_audit_data *ad); u32 avc_policy_seqno(void); #define AVC_CALLBACK_GRANT 1 Loading @@ -165,7 +161,6 @@ u32 avc_policy_seqno(void); #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 #define AVC_CALLBACK_AUDITDENY_ENABLE 64 #define AVC_CALLBACK_AUDITDENY_DISABLE 128 #define AVC_CALLBACK_ADD_OPERATION 256 int avc_add_callback(int (*callback)(u32 event), u32 events); Loading security/selinux/include/security.h +2 −32 Original line number Diff line number Diff line Loading @@ -35,14 +35,13 @@ #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 #define POLICYDB_VERSION_DEFAULT_TYPE 28 #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 #define POLICYDB_VERSION_IOCTL_OPERATIONS 30 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE #else #define POLICYDB_VERSION_MAX POLICYDB_VERSION_IOCTL_OPERATIONS #define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES #endif /* Mask for just the mount related flags */ Loading Loading @@ -110,40 +109,11 @@ struct av_decision { u32 flags; }; #define security_operation_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f)) #define security_operation_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f))) struct operation_perm { u32 perms[8]; }; struct operation_decision { u8 type; u8 specified; struct operation_perm *allowed; struct operation_perm *auditallow; struct operation_perm *dontaudit; }; #define OPERATION_ALLOWED 1 #define OPERATION_AUDITALLOW 2 #define OPERATION_DONTAUDIT 4 #define OPERATION_ALL (OPERATION_ALLOWED | OPERATION_AUDITALLOW |\ OPERATION_DONTAUDIT) struct operation { u16 len; /* length of operation decision chain */ u32 type[8]; /* 256 types */ }; /* definitions of av_decision.flags */ #define AVD_FLAGS_PERMISSIVE 0x0001 void security_compute_av(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct operation *ops); void security_compute_operation(u32 ssid, u32 tsid, u16 tclass, u8 type, struct operation_decision *od); u16 tclass, struct av_decision *avd); void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd); Loading security/selinux/ss/avtab.c +15 −76 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ #include "policydb.h" static struct kmem_cache *avtab_node_cachep; static struct kmem_cache *avtab_operation_cachep; static inline int avtab_hash(struct avtab_key *keyp, u16 mask) { Loading @@ -38,24 +37,11 @@ avtab_insert_node(struct avtab *h, int hvalue, struct avtab_key *key, struct avtab_datum *datum) { struct avtab_node *newnode; struct avtab_operation *ops; newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); if (newnode == NULL) return NULL; newnode->key = *key; if (key->specified & AVTAB_OP) { ops = kmem_cache_zalloc(avtab_operation_cachep, GFP_KERNEL); if (ops == NULL) { kmem_cache_free(avtab_node_cachep, newnode); return NULL; } *ops = *(datum->u.ops); newnode->datum.u.ops = ops; } else { newnode->datum.u.data = datum->u.data; } newnode->datum = *datum; if (prev) { newnode->next = prev->next; prev->next = newnode; Loading Loading @@ -84,11 +70,8 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && (specified & cur->key.specified)) { if (specified & AVTAB_OPNUM) break; (specified & cur->key.specified)) return -EEXIST; } if (key->source_type < cur->key.source_type) break; if (key->source_type == cur->key.source_type && Loading Loading @@ -249,9 +232,6 @@ void avtab_destroy(struct avtab *h) while (cur) { temp = cur; cur = cur->next; if (temp->key.specified & AVTAB_OP) kmem_cache_free(avtab_operation_cachep, temp->datum.u.ops); kmem_cache_free(avtab_node_cachep, temp); } h->htable[i] = NULL; Loading Loading @@ -340,13 +320,7 @@ static uint16_t spec_order[] = { AVTAB_AUDITALLOW, AVTAB_TRANSITION, AVTAB_CHANGE, AVTAB_MEMBER, AVTAB_OPNUM_ALLOWED, AVTAB_OPNUM_AUDITALLOW, AVTAB_OPNUM_DONTAUDIT, AVTAB_OPTYPE_ALLOWED, AVTAB_OPTYPE_AUDITALLOW, AVTAB_OPTYPE_DONTAUDIT AVTAB_MEMBER }; int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, Loading @@ -356,11 +330,10 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, { __le16 buf16[4]; u16 enabled; __le32 buf32[7]; u32 items, items2, val, vers = pol->policyvers; struct avtab_key key; struct avtab_datum datum; struct avtab_operation ops; __le32 buf32[ARRAY_SIZE(ops.op.perms)]; int i, rc; unsigned set; Loading Loading @@ -417,15 +390,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); return -EINVAL; } if (val & AVTAB_OP) { printk(KERN_ERR "SELinux: avtab: entry has operations\n"); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(spec_order); i++) { if (val & spec_order[i]) { key.specified = spec_order[i] | enabled; datum.u.data = le32_to_cpu(buf32[items++]); datum.data = le32_to_cpu(buf32[items++]); rc = insertf(a, &key, &datum, p); if (rc) return rc; Loading @@ -444,6 +413,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } items = 0; key.source_type = le16_to_cpu(buf16[items++]); key.target_type = le16_to_cpu(buf16[items++]); Loading @@ -467,32 +437,14 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, return -EINVAL; } if ((vers < POLICYDB_VERSION_IOCTL_OPERATIONS) || !(key.specified & AVTAB_OP)) { rc = next_entry(buf32, fp, sizeof(u32)); if (rc) { printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } datum.u.data = le32_to_cpu(*buf32); } else { memset(&ops, 0, sizeof(struct avtab_operation)); rc = next_entry(&ops.type, fp, sizeof(u8)); if (rc) { printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(ops.op.perms)); if (rc) { printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } for (i = 0; i < ARRAY_SIZE(ops.op.perms); i++) ops.op.perms[i] = le32_to_cpu(buf32[i]); datum.u.ops = &ops; } datum.data = le32_to_cpu(*buf32); if ((key.specified & AVTAB_TYPE) && !policydb_type_isvalid(pol, datum.u.data)) { !policydb_type_isvalid(pol, datum.data)) { printk(KERN_ERR "SELinux: avtab: invalid type\n"); return -EINVAL; } Loading Loading @@ -552,9 +504,8 @@ bad: int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) { __le16 buf16[4]; __le32 buf32[ARRAY_SIZE(cur->datum.u.ops->op.perms)]; __le32 buf32[1]; int rc; unsigned int i; buf16[0] = cpu_to_le16(cur->key.source_type); buf16[1] = cpu_to_le16(cur->key.target_type); Loading @@ -563,16 +514,8 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) rc = put_entry(buf16, sizeof(u16), 4, fp); if (rc) return rc; if (cur->key.specified & AVTAB_OP) { for (i = 0; i < ARRAY_SIZE(cur->datum.u.ops->op.perms); i++) buf32[i] = cpu_to_le32(cur->datum.u.ops->op.perms[i]); rc = put_entry(buf32, sizeof(u32), ARRAY_SIZE(cur->datum.u.ops->op.perms), fp); } else { buf32[0] = cpu_to_le32(cur->datum.u.data); buf32[0] = cpu_to_le32(cur->datum.data); rc = put_entry(buf32, sizeof(u32), 1, fp); } if (rc) return rc; return 0; Loading Loading @@ -605,13 +548,9 @@ void avtab_cache_init(void) avtab_node_cachep = kmem_cache_create("avtab_node", sizeof(struct avtab_node), 0, SLAB_PANIC, NULL); avtab_operation_cachep = kmem_cache_create("avtab_operation", sizeof(struct avtab_operation), 0, SLAB_PANIC, NULL); } void avtab_cache_destroy(void) { kmem_cache_destroy(avtab_node_cachep); kmem_cache_destroy(avtab_operation_cachep); } Loading
security/selinux/avc.c +18 −410 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #include <linux/init.h> #include <linux/skbuff.h> #include <linux/percpu.h> #include <linux/list.h> #include <net/sock.h> #include <linux/un.h> #include <net/af_unix.h> Loading @@ -49,7 +48,6 @@ struct avc_entry { u32 tsid; u16 tclass; struct av_decision avd; struct avc_operation_node *ops_node; }; struct avc_node { Loading @@ -66,16 +64,6 @@ struct avc_cache { u32 latest_notif; /* latest revocation notification */ }; struct avc_operation_decision_node { struct operation_decision od; struct list_head od_list; }; struct avc_operation_node { struct operation ops; struct list_head od_head; /* list of operation_decision_node */ }; struct avc_callback_node { int (*callback) (u32 event); u32 events; Loading @@ -92,9 +80,6 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; static struct avc_cache avc_cache; static struct avc_callback_node *avc_callbacks; static struct kmem_cache *avc_node_cachep; static struct kmem_cache *avc_operation_decision_node_cachep; static struct kmem_cache *avc_operation_node_cachep; static struct kmem_cache *avc_operation_perm_cachep; static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) { Loading Loading @@ -186,16 +171,6 @@ void __init avc_init(void) avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), 0, SLAB_PANIC, NULL); avc_operation_node_cachep = kmem_cache_create("avc_operation_node", sizeof(struct avc_operation_node), 0, SLAB_PANIC, NULL); avc_operation_decision_node_cachep = kmem_cache_create( "avc_operation_decision_node", sizeof(struct avc_operation_decision_node), 0, SLAB_PANIC, NULL); avc_operation_perm_cachep = kmem_cache_create("avc_operation_perm", sizeof(struct operation_perm), 0, SLAB_PANIC, NULL); audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); } Loading Loading @@ -230,269 +205,9 @@ int avc_get_hash_stats(char *page) slots_used, AVC_CACHE_SLOTS, max_chain_len); } /* * using a linked list for operation_decision lookup because the list is * always small. i.e. less than 5, typically 1 */ static struct operation_decision *avc_operation_lookup(u8 type, struct avc_operation_node *ops_node) { struct avc_operation_decision_node *od_node; struct operation_decision *od = NULL; list_for_each_entry(od_node, &ops_node->od_head, od_list) { if (od_node->od.type != type) continue; od = &od_node->od; break; } return od; } static inline unsigned int avc_operation_has_perm(struct operation_decision *od, u16 cmd, u8 specified) { unsigned int rc = 0; u8 num = cmd & 0xff; if ((specified == OPERATION_ALLOWED) && (od->specified & OPERATION_ALLOWED)) rc = security_operation_test(od->allowed->perms, num); else if ((specified == OPERATION_AUDITALLOW) && (od->specified & OPERATION_AUDITALLOW)) rc = security_operation_test(od->auditallow->perms, num); else if ((specified == OPERATION_DONTAUDIT) && (od->specified & OPERATION_DONTAUDIT)) rc = security_operation_test(od->dontaudit->perms, num); return rc; } static void avc_operation_allow_perm(struct avc_operation_node *node, u16 cmd) { struct operation_decision *od; u8 type; u8 num; type = cmd >> 8; num = cmd & 0xff; security_operation_set(node->ops.type, type); od = avc_operation_lookup(type, node); if (od && od->allowed) security_operation_set(od->allowed->perms, num); } static void avc_operation_decision_free( struct avc_operation_decision_node *od_node) { struct operation_decision *od; od = &od_node->od; if (od->allowed) kmem_cache_free(avc_operation_perm_cachep, od->allowed); if (od->auditallow) kmem_cache_free(avc_operation_perm_cachep, od->auditallow); if (od->dontaudit) kmem_cache_free(avc_operation_perm_cachep, od->dontaudit); kmem_cache_free(avc_operation_decision_node_cachep, od_node); } static void avc_operation_free(struct avc_operation_node *ops_node) { struct avc_operation_decision_node *od_node; if (!ops_node) return; list_for_each_entry(od_node, &ops_node->od_head, od_list) avc_operation_decision_free(od_node); kmem_cache_free(avc_operation_node_cachep, ops_node); } static void avc_copy_operation_decision(struct operation_decision *dest, struct operation_decision *src) { dest->type = src->type; dest->specified = src->specified; if (dest->specified & OPERATION_ALLOWED) memcpy(dest->allowed->perms, src->allowed->perms, sizeof(src->allowed->perms)); if (dest->specified & OPERATION_AUDITALLOW) memcpy(dest->auditallow->perms, src->auditallow->perms, sizeof(src->auditallow->perms)); if (dest->specified & OPERATION_DONTAUDIT) memcpy(dest->dontaudit->perms, src->dontaudit->perms, sizeof(src->dontaudit->perms)); } /* * similar to avc_copy_operation_decision, but only copy decision * information relevant to this command */ static inline void avc_quick_copy_operation_decision(u16 cmd, struct operation_decision *dest, struct operation_decision *src) { /* * compute index of the u32 of the 256 bits (8 u32s) that contain this * command permission */ u8 i = (0xff & cmd) >> 5; dest->specified = src->specified; if (dest->specified & OPERATION_ALLOWED) dest->allowed->perms[i] = src->allowed->perms[i]; if (dest->specified & OPERATION_AUDITALLOW) dest->auditallow->perms[i] = src->auditallow->perms[i]; if (dest->specified & OPERATION_DONTAUDIT) dest->dontaudit->perms[i] = src->dontaudit->perms[i]; } static struct avc_operation_decision_node *avc_operation_decision_alloc(u8 specified) { struct avc_operation_decision_node *node; struct operation_decision *od; node = kmem_cache_zalloc(avc_operation_decision_node_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); if (!node) return NULL; od = &node->od; if (specified & OPERATION_ALLOWED) { od->allowed = kmem_cache_zalloc(avc_operation_perm_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); if (!od->allowed) goto error; } if (specified & OPERATION_AUDITALLOW) { od->auditallow = kmem_cache_zalloc(avc_operation_perm_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); if (!od->auditallow) goto error; } if (specified & OPERATION_DONTAUDIT) { od->dontaudit = kmem_cache_zalloc(avc_operation_perm_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); if (!od->dontaudit) goto error; } return node; error: avc_operation_decision_free(node); return NULL; } static int avc_add_operation(struct avc_node *node, struct operation_decision *od) { struct avc_operation_decision_node *dest_od; node->ae.ops_node->ops.len++; dest_od = avc_operation_decision_alloc(od->specified); if (!dest_od) return -ENOMEM; avc_copy_operation_decision(&dest_od->od, od); list_add(&dest_od->od_list, &node->ae.ops_node->od_head); return 0; } static struct avc_operation_node *avc_operation_alloc(void) { struct avc_operation_node *ops; ops = kmem_cache_zalloc(avc_operation_node_cachep, GFP_ATOMIC|__GFP_NOMEMALLOC); if (!ops) return ops; INIT_LIST_HEAD(&ops->od_head); return ops; } static int avc_operation_populate(struct avc_node *node, struct avc_operation_node *src) { struct avc_operation_node *dest; struct avc_operation_decision_node *dest_od; struct avc_operation_decision_node *src_od; if (src->ops.len == 0) return 0; dest = avc_operation_alloc(); if (!dest) return -ENOMEM; memcpy(dest->ops.type, &src->ops.type, sizeof(dest->ops.type)); dest->ops.len = src->ops.len; /* for each source od allocate a destination od and copy */ list_for_each_entry(src_od, &src->od_head, od_list) { dest_od = avc_operation_decision_alloc(src_od->od.specified); if (!dest_od) goto error; avc_copy_operation_decision(&dest_od->od, &src_od->od); list_add(&dest_od->od_list, &dest->od_head); } node->ae.ops_node = dest; return 0; error: avc_operation_free(dest); return -ENOMEM; } static inline u32 avc_operation_audit_required(u32 requested, struct av_decision *avd, struct operation_decision *od, u16 cmd, int result, u32 *deniedp) { u32 denied, audited; denied = requested & ~avd->allowed; if (unlikely(denied)) { audited = denied & avd->auditdeny; if (audited && od) { if (avc_operation_has_perm(od, cmd, OPERATION_DONTAUDIT)) audited &= ~requested; } } else if (result) { audited = denied = requested; } else { audited = requested & avd->auditallow; if (audited && od) { if (!avc_operation_has_perm(od, cmd, OPERATION_AUDITALLOW)) audited &= ~requested; } } *deniedp = denied; return audited; } static inline int avc_operation_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd, struct operation_decision *od, u16 cmd, int result, struct common_audit_data *ad) { u32 audited, denied; audited = avc_operation_audit_required( requested, avd, od, cmd, result, &denied); if (likely(!audited)) return 0; return slow_avc_audit(ssid, tsid, tclass, requested, audited, denied, result, ad, 0); } static void avc_node_free(struct rcu_head *rhead) { struct avc_node *node = container_of(rhead, struct avc_node, rhead); avc_operation_free(node->ae.ops_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); } Loading @@ -506,7 +221,6 @@ static void avc_node_delete(struct avc_node *node) static void avc_node_kill(struct avc_node *node) { avc_operation_free(node->ae.ops_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); atomic_dec(&avc_cache.active_nodes); Loading Loading @@ -653,7 +367,6 @@ static int avc_latest_notif_update(int seqno, int is_insert) * @tsid: target security identifier * @tclass: target security class * @avd: resulting av decision * @ops: resulting operation decisions * * Insert an AVC entry for the SID pair * (@ssid, @tsid) and class @tclass. Loading @@ -665,9 +378,7 @@ static int avc_latest_notif_update(int seqno, int is_insert) * the access vectors into a cache entry, returns * avc_node inserted. Otherwise, this function returns NULL. */ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct avc_operation_node *ops_node) static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) { struct avc_node *pos, *node = NULL; int hvalue; Loading @@ -680,15 +391,10 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, if (node) { struct hlist_head *head; spinlock_t *lock; int rc = 0; hvalue = avc_hash(ssid, tsid, tclass); avc_node_populate(node, ssid, tsid, tclass, avd); rc = avc_operation_populate(node, ops_node); if (rc) { kmem_cache_free(avc_node_cachep, node); return NULL; } head = &avc_cache.slots[hvalue]; lock = &avc_cache.slots_lock[hvalue]; Loading Loading @@ -837,17 +543,14 @@ static inline int avc_sidcmp(u32 x, u32 y) * @perms : Permission mask bits * @ssid,@tsid,@tclass : identifier of an AVC entry * @seqno : sequence number when decision was made * @od: operation_decision to be added to the node * * if a valid AVC entry doesn't exist,this function returns -ENOENT. * if kmalloc() called internal returns NULL, this function returns -ENOMEM. * otherwise, this function updates the AVC entry. The original AVC-entry object * will release later by RCU. */ static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, u16 tclass, u32 seqno, struct operation_decision *od, u32 flags) static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, u32 seqno) { int hvalue, rc = 0; unsigned long flag; Loading Loading @@ -891,19 +594,9 @@ static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); if (orig->ae.ops_node) { rc = avc_operation_populate(node, orig->ae.ops_node); if (rc) { kmem_cache_free(avc_node_cachep, node); goto out_unlock; } } switch (event) { case AVC_CALLBACK_GRANT: node->ae.avd.allowed |= perms; if (node->ae.ops_node && (flags & AVC_OPERATION_CMD)) avc_operation_allow_perm(node->ae.ops_node, cmd); break; case AVC_CALLBACK_TRY_REVOKE: case AVC_CALLBACK_REVOKE: Loading @@ -921,9 +614,6 @@ static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, case AVC_CALLBACK_AUDITDENY_DISABLE: node->ae.avd.auditdeny &= ~perms; break; case AVC_CALLBACK_ADD_OPERATION: avc_add_operation(node, od); break; } avc_node_replace(node, orig); out_unlock: Loading Loading @@ -995,19 +685,17 @@ int avc_ss_reset(u32 seqno) * results in a bigger stack frame. */ static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct avc_operation_node *ops_node) u16 tclass, struct av_decision *avd) { rcu_read_unlock(); INIT_LIST_HEAD(&ops_node->od_head); security_compute_av(ssid, tsid, tclass, avd, &ops_node->ops); security_compute_av(ssid, tsid, tclass, avd); rcu_read_lock(); return avc_insert(ssid, tsid, tclass, avd, ops_node); return avc_insert(ssid, tsid, tclass, avd); } static noinline int avc_denied(u32 ssid, u32 tsid, u16 tclass, u32 requested, u16 cmd, unsigned flags, unsigned flags, struct av_decision *avd) { if (flags & AVC_STRICT) Loading @@ -1016,92 +704,11 @@ static noinline int avc_denied(u32 ssid, u32 tsid, if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) return -EACCES; avc_update_node(AVC_CALLBACK_GRANT, requested, cmd, ssid, tsid, tclass, avd->seqno, NULL, flags); avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, tsid, tclass, avd->seqno); return 0; } /* * ioctl commands are comprised of four fields, direction, size, type, and * number. The avc operation logic filters based on two of them: * * type: or code, typically unique to each driver * number: or function * * For example, 0x89 is a socket type, and number 0x27 is the get hardware * address function. */ int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested, u16 cmd, struct common_audit_data *ad) { struct avc_node *node; struct av_decision avd; u32 denied; struct operation_decision *od = NULL; struct operation_decision od_local; struct operation_perm allowed; struct operation_perm auditallow; struct operation_perm dontaudit; struct avc_operation_node local_ops_node; struct avc_operation_node *ops_node; u8 type = cmd >> 8; int rc = 0, rc2; ops_node = &local_ops_node; BUG_ON(!requested); rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass); if (unlikely(!node)) { node = avc_compute_av(ssid, tsid, tclass, &avd, ops_node); } else { memcpy(&avd, &node->ae.avd, sizeof(avd)); ops_node = node->ae.ops_node; } /* if operations are not defined, only consider av_decision */ if (!ops_node || !ops_node->ops.len) goto decision; od_local.allowed = &allowed; od_local.auditallow = &auditallow; od_local.dontaudit = &dontaudit; /* lookup operation decision */ od = avc_operation_lookup(type, ops_node); if (unlikely(!od)) { /* Compute operation decision if type is flagged */ if (!security_operation_test(ops_node->ops.type, type)) { avd.allowed &= ~requested; goto decision; } rcu_read_unlock(); security_compute_operation(ssid, tsid, tclass, type, &od_local); rcu_read_lock(); avc_update_node(AVC_CALLBACK_ADD_OPERATION, requested, cmd, ssid, tsid, tclass, avd.seqno, &od_local, 0); } else { avc_quick_copy_operation_decision(cmd, &od_local, od); } od = &od_local; if (!avc_operation_has_perm(od, cmd, OPERATION_ALLOWED)) avd.allowed &= ~requested; decision: denied = requested & ~(avd.allowed); if (unlikely(denied)) rc = avc_denied(ssid, tsid, tclass, requested, cmd, AVC_OPERATION_CMD, &avd); rcu_read_unlock(); rc2 = avc_operation_audit(ssid, tsid, tclass, requested, &avd, od, cmd, rc, ad); if (rc2) return rc2; return rc; } /** * avc_has_perm_noaudit - Check permissions but perform no auditing. Loading Loading @@ -1129,7 +736,6 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, struct av_decision *avd) { struct avc_node *node; struct avc_operation_node ops_node; int rc = 0; u32 denied; Loading @@ -1138,14 +744,16 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass); if (unlikely(!node)) node = avc_compute_av(ssid, tsid, tclass, avd, &ops_node); else if (unlikely(!node)) { node = avc_compute_av(ssid, tsid, tclass, avd); } else { memcpy(avd, &node->ae.avd, sizeof(*avd)); avd = &node->ae.avd; } denied = requested & ~(avd->allowed); if (unlikely(denied)) rc = avc_denied(ssid, tsid, tclass, requested, 0, flags, avd); rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); rcu_read_unlock(); return rc; Loading
security/selinux/hooks.c +1 −39 Original line number Diff line number Diff line Loading @@ -3241,44 +3241,6 @@ 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; 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_operation(ssid, isec->sid, isec->sclass, requested, cmd, &ad); out: return rc; } static int selinux_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { Loading Loading @@ -3321,7 +3283,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, * to the file's ioctl() function. */ default: error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); error = file_has_perm(cred, file, FILE__IOCTL); } return error; } Loading
security/selinux/include/avc.h +0 −5 Original line number Diff line number Diff line Loading @@ -142,7 +142,6 @@ static inline int avc_audit(u32 ssid, u32 tsid, } #define AVC_STRICT 1 /* Ignore permissive mode. */ #define AVC_OPERATION_CMD 2 /* ignore command when updating operations */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested, unsigned flags, Loading @@ -152,9 +151,6 @@ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata); int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested, u16 cmd, struct common_audit_data *ad); u32 avc_policy_seqno(void); #define AVC_CALLBACK_GRANT 1 Loading @@ -165,7 +161,6 @@ u32 avc_policy_seqno(void); #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 #define AVC_CALLBACK_AUDITDENY_ENABLE 64 #define AVC_CALLBACK_AUDITDENY_DISABLE 128 #define AVC_CALLBACK_ADD_OPERATION 256 int avc_add_callback(int (*callback)(u32 event), u32 events); Loading
security/selinux/include/security.h +2 −32 Original line number Diff line number Diff line Loading @@ -35,14 +35,13 @@ #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 #define POLICYDB_VERSION_DEFAULT_TYPE 28 #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 #define POLICYDB_VERSION_IOCTL_OPERATIONS 30 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE #else #define POLICYDB_VERSION_MAX POLICYDB_VERSION_IOCTL_OPERATIONS #define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES #endif /* Mask for just the mount related flags */ Loading Loading @@ -110,40 +109,11 @@ struct av_decision { u32 flags; }; #define security_operation_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f)) #define security_operation_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f))) struct operation_perm { u32 perms[8]; }; struct operation_decision { u8 type; u8 specified; struct operation_perm *allowed; struct operation_perm *auditallow; struct operation_perm *dontaudit; }; #define OPERATION_ALLOWED 1 #define OPERATION_AUDITALLOW 2 #define OPERATION_DONTAUDIT 4 #define OPERATION_ALL (OPERATION_ALLOWED | OPERATION_AUDITALLOW |\ OPERATION_DONTAUDIT) struct operation { u16 len; /* length of operation decision chain */ u32 type[8]; /* 256 types */ }; /* definitions of av_decision.flags */ #define AVD_FLAGS_PERMISSIVE 0x0001 void security_compute_av(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct operation *ops); void security_compute_operation(u32 ssid, u32 tsid, u16 tclass, u8 type, struct operation_decision *od); u16 tclass, struct av_decision *avd); void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd); Loading
security/selinux/ss/avtab.c +15 −76 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ #include "policydb.h" static struct kmem_cache *avtab_node_cachep; static struct kmem_cache *avtab_operation_cachep; static inline int avtab_hash(struct avtab_key *keyp, u16 mask) { Loading @@ -38,24 +37,11 @@ avtab_insert_node(struct avtab *h, int hvalue, struct avtab_key *key, struct avtab_datum *datum) { struct avtab_node *newnode; struct avtab_operation *ops; newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); if (newnode == NULL) return NULL; newnode->key = *key; if (key->specified & AVTAB_OP) { ops = kmem_cache_zalloc(avtab_operation_cachep, GFP_KERNEL); if (ops == NULL) { kmem_cache_free(avtab_node_cachep, newnode); return NULL; } *ops = *(datum->u.ops); newnode->datum.u.ops = ops; } else { newnode->datum.u.data = datum->u.data; } newnode->datum = *datum; if (prev) { newnode->next = prev->next; prev->next = newnode; Loading Loading @@ -84,11 +70,8 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && (specified & cur->key.specified)) { if (specified & AVTAB_OPNUM) break; (specified & cur->key.specified)) return -EEXIST; } if (key->source_type < cur->key.source_type) break; if (key->source_type == cur->key.source_type && Loading Loading @@ -249,9 +232,6 @@ void avtab_destroy(struct avtab *h) while (cur) { temp = cur; cur = cur->next; if (temp->key.specified & AVTAB_OP) kmem_cache_free(avtab_operation_cachep, temp->datum.u.ops); kmem_cache_free(avtab_node_cachep, temp); } h->htable[i] = NULL; Loading Loading @@ -340,13 +320,7 @@ static uint16_t spec_order[] = { AVTAB_AUDITALLOW, AVTAB_TRANSITION, AVTAB_CHANGE, AVTAB_MEMBER, AVTAB_OPNUM_ALLOWED, AVTAB_OPNUM_AUDITALLOW, AVTAB_OPNUM_DONTAUDIT, AVTAB_OPTYPE_ALLOWED, AVTAB_OPTYPE_AUDITALLOW, AVTAB_OPTYPE_DONTAUDIT AVTAB_MEMBER }; int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, Loading @@ -356,11 +330,10 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, { __le16 buf16[4]; u16 enabled; __le32 buf32[7]; u32 items, items2, val, vers = pol->policyvers; struct avtab_key key; struct avtab_datum datum; struct avtab_operation ops; __le32 buf32[ARRAY_SIZE(ops.op.perms)]; int i, rc; unsigned set; Loading Loading @@ -417,15 +390,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); return -EINVAL; } if (val & AVTAB_OP) { printk(KERN_ERR "SELinux: avtab: entry has operations\n"); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(spec_order); i++) { if (val & spec_order[i]) { key.specified = spec_order[i] | enabled; datum.u.data = le32_to_cpu(buf32[items++]); datum.data = le32_to_cpu(buf32[items++]); rc = insertf(a, &key, &datum, p); if (rc) return rc; Loading @@ -444,6 +413,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } items = 0; key.source_type = le16_to_cpu(buf16[items++]); key.target_type = le16_to_cpu(buf16[items++]); Loading @@ -467,32 +437,14 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, return -EINVAL; } if ((vers < POLICYDB_VERSION_IOCTL_OPERATIONS) || !(key.specified & AVTAB_OP)) { rc = next_entry(buf32, fp, sizeof(u32)); if (rc) { printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } datum.u.data = le32_to_cpu(*buf32); } else { memset(&ops, 0, sizeof(struct avtab_operation)); rc = next_entry(&ops.type, fp, sizeof(u8)); if (rc) { printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(ops.op.perms)); if (rc) { printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } for (i = 0; i < ARRAY_SIZE(ops.op.perms); i++) ops.op.perms[i] = le32_to_cpu(buf32[i]); datum.u.ops = &ops; } datum.data = le32_to_cpu(*buf32); if ((key.specified & AVTAB_TYPE) && !policydb_type_isvalid(pol, datum.u.data)) { !policydb_type_isvalid(pol, datum.data)) { printk(KERN_ERR "SELinux: avtab: invalid type\n"); return -EINVAL; } Loading Loading @@ -552,9 +504,8 @@ bad: int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) { __le16 buf16[4]; __le32 buf32[ARRAY_SIZE(cur->datum.u.ops->op.perms)]; __le32 buf32[1]; int rc; unsigned int i; buf16[0] = cpu_to_le16(cur->key.source_type); buf16[1] = cpu_to_le16(cur->key.target_type); Loading @@ -563,16 +514,8 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) rc = put_entry(buf16, sizeof(u16), 4, fp); if (rc) return rc; if (cur->key.specified & AVTAB_OP) { for (i = 0; i < ARRAY_SIZE(cur->datum.u.ops->op.perms); i++) buf32[i] = cpu_to_le32(cur->datum.u.ops->op.perms[i]); rc = put_entry(buf32, sizeof(u32), ARRAY_SIZE(cur->datum.u.ops->op.perms), fp); } else { buf32[0] = cpu_to_le32(cur->datum.u.data); buf32[0] = cpu_to_le32(cur->datum.data); rc = put_entry(buf32, sizeof(u32), 1, fp); } if (rc) return rc; return 0; Loading Loading @@ -605,13 +548,9 @@ void avtab_cache_init(void) avtab_node_cachep = kmem_cache_create("avtab_node", sizeof(struct avtab_node), 0, SLAB_PANIC, NULL); avtab_operation_cachep = kmem_cache_create("avtab_operation", sizeof(struct avtab_operation), 0, SLAB_PANIC, NULL); } void avtab_cache_destroy(void) { kmem_cache_destroy(avtab_node_cachep); kmem_cache_destroy(avtab_operation_cachep); }