diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index e7ae7e21449b..62990aa1ec9e 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h @@ -31,7 +31,6 @@ struct context { u32 len; /* length of string in bytes */ struct mls_range range; char *str; /* string representation if context cannot be mapped. */ - u32 hash; /* a hash of the string representation */ }; static inline void mls_context_init(struct context *c) @@ -169,13 +168,12 @@ static inline int context_cpy(struct context *dst, struct context *src) kfree(dst->str); return rc; } - dst->hash = src->hash; return 0; } static inline void context_destroy(struct context *c) { - c->user = c->role = c->type = c->hash = 0; + c->user = c->role = c->type = 0; kfree(c->str); c->str = NULL; c->len = 0; @@ -184,8 +182,6 @@ static inline void context_destroy(struct context *c) static inline int context_cmp(struct context *c1, struct context *c2) { - if (c1->hash && c2->hash && (c1->hash != c2->hash)) - return 0; if (c1->len && c2->len) return (c1->len == c2->len && !strcmp(c1->str, c2->str)); if (c1->len || c2->len) @@ -198,10 +194,5 @@ static inline int context_cmp(struct context *c1, struct context *c2) u32 context_compute_hash(const struct context *c); -static inline void context_add_hash(struct context *context) -{ - context->hash = context_compute_hash(context); -} - #endif /* _SS_CONTEXT_H_ */ diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 2849bc362828..dc6729860bd6 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -862,8 +862,6 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s) if (!name) continue; - context_add_hash(&c->context[0]); - rc = sidtab_set_initial(s, sid, &c->context[0]); if (rc) { pr_err("SELinux: unable to load initial SID %s.\n", diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index ed3306914309..b49a336b1e6e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1490,17 +1490,6 @@ static int string_to_context_struct(struct policydb *pol, return rc; } -static int context_struct_to_sid(struct selinux_state *state, - struct context *context, u32 *sid) -{ - struct sidtab *sidtab = state->ss->sidtab; - - if (!context->hash) - context_add_hash(context); - - return sidtab_context_to_sid(sidtab, context, sid); -} - static int security_context_to_sid_core(struct selinux_state *state, const char *scontext, u32 scontext_len, u32 *sid, u32 def_sid, gfp_t gfp_flags, @@ -1555,7 +1544,7 @@ static int security_context_to_sid_core(struct selinux_state *state, str = NULL; } else if (rc) goto out_unlock; - rc = context_struct_to_sid(state, &context, sid); + rc = sidtab_context_to_sid(sidtab, &context, sid); context_destroy(&context); out_unlock: read_unlock(&state->ss->policy_rwlock); @@ -1865,7 +1854,7 @@ static int security_compute_sid(struct selinux_state *state, goto out_unlock; } /* Obtain the sid for the context. */ - rc = context_struct_to_sid(state, &newcontext, out_sid); + rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid); out_unlock: read_unlock(&state->ss->policy_rwlock); context_destroy(&newcontext); @@ -2017,7 +2006,6 @@ static int convert_context(struct context *oldc, struct context *newc, void *p) context_init(newc); newc->str = s; newc->len = oldc->len; - newc->hash = oldc->hash; return 0; } kfree(s); @@ -2094,8 +2082,6 @@ static int convert_context(struct context *oldc, struct context *newc, void *p) goto bad; } - context_add_hash(newc); - return 0; bad: /* Map old representation to string and save it. */ @@ -2105,7 +2091,6 @@ static int convert_context(struct context *oldc, struct context *newc, void *p) context_destroy(newc); newc->str = s; newc->len = len; - context_add_hash(newc); pr_info("SELinux: Context %s became invalid (unmapped).\n", newc->str); return 0; @@ -2322,12 +2307,14 @@ int security_port_sid(struct selinux_state *state, u8 protocol, u16 port, u32 *out_sid) { struct policydb *policydb; + struct sidtab *sidtab; struct ocontext *c; int rc = 0; read_lock(&state->ss->policy_rwlock); policydb = &state->ss->policydb; + sidtab = state->ss->sidtab; c = policydb->ocontexts[OCON_PORT]; while (c) { @@ -2340,7 +2327,7 @@ int security_port_sid(struct selinux_state *state, if (c) { if (!c->sid[0]) { - rc = context_struct_to_sid(state, &c->context[0], + rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; @@ -2365,12 +2352,14 @@ int security_ib_pkey_sid(struct selinux_state *state, u64 subnet_prefix, u16 pkey_num, u32 *out_sid) { struct policydb *policydb; + struct sidtab *sidtab; struct ocontext *c; int rc = 0; read_lock(&state->ss->policy_rwlock); policydb = &state->ss->policydb; + sidtab = state->ss->sidtab; c = policydb->ocontexts[OCON_IBPKEY]; while (c) { @@ -2384,7 +2373,7 @@ int security_ib_pkey_sid(struct selinux_state *state, if (c) { if (!c->sid[0]) { - rc = context_struct_to_sid(state, + rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) @@ -2409,12 +2398,14 @@ int security_ib_endport_sid(struct selinux_state *state, const char *dev_name, u8 port_num, u32 *out_sid) { struct policydb *policydb; + struct sidtab *sidtab; struct ocontext *c; int rc = 0; read_lock(&state->ss->policy_rwlock); policydb = &state->ss->policydb; + sidtab = state->ss->sidtab; c = policydb->ocontexts[OCON_IBENDPORT]; while (c) { @@ -2429,7 +2420,7 @@ int security_ib_endport_sid(struct selinux_state *state, if (c) { if (!c->sid[0]) { - rc = context_struct_to_sid(state, &c->context[0], + rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; @@ -2452,12 +2443,14 @@ int security_netif_sid(struct selinux_state *state, char *name, u32 *if_sid) { struct policydb *policydb; + struct sidtab *sidtab; int rc = 0; struct ocontext *c; read_lock(&state->ss->policy_rwlock); policydb = &state->ss->policydb; + sidtab = state->ss->sidtab; c = policydb->ocontexts[OCON_NETIF]; while (c) { @@ -2468,11 +2461,11 @@ int security_netif_sid(struct selinux_state *state, if (c) { if (!c->sid[0] || !c->sid[1]) { - rc = context_struct_to_sid(state, &c->context[0], + rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; - rc = context_struct_to_sid(state, &c->context[1], + rc = sidtab_context_to_sid(sidtab, &c->context[1], &c->sid[1]); if (rc) goto out; @@ -2513,12 +2506,14 @@ int security_node_sid(struct selinux_state *state, u32 *out_sid) { struct policydb *policydb; + struct sidtab *sidtab; int rc; struct ocontext *c; read_lock(&state->ss->policy_rwlock); policydb = &state->ss->policydb; + sidtab = state->ss->sidtab; switch (domain) { case AF_INET: { @@ -2560,7 +2555,7 @@ int security_node_sid(struct selinux_state *state, if (c) { if (!c->sid[0]) { - rc = context_struct_to_sid(state, + rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) @@ -2644,17 +2639,12 @@ int security_get_user_sids(struct selinux_state *state, usercon.role = i + 1; ebitmap_for_each_positive_bit(&role->types, tnode, j) { usercon.type = j + 1; - /* - * The same context struct is reused here so the hash - * must be reset. - */ - usercon.hash = 0; if (mls_setup_user_range(policydb, fromcon, user, &usercon)) continue; - rc = context_struct_to_sid(state, &usercon, &sid); + rc = sidtab_context_to_sid(sidtab, &usercon, &sid); if (rc) goto out_unlock; if (mynel < maxnel) { @@ -2725,6 +2715,7 @@ static inline int __security_genfs_sid(struct selinux_state *state, u32 *sid) { struct policydb *policydb = &state->ss->policydb; + struct sidtab *sidtab = state->ss->sidtab; int len; u16 sclass; struct genfs *genfs; @@ -2759,7 +2750,7 @@ static inline int __security_genfs_sid(struct selinux_state *state, goto out; if (!c->sid[0]) { - rc = context_struct_to_sid(state, &c->context[0], &c->sid[0]); + rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; } @@ -2801,6 +2792,7 @@ int security_genfs_sid(struct selinux_state *state, int security_fs_use(struct selinux_state *state, struct super_block *sb) { struct policydb *policydb; + struct sidtab *sidtab; int rc = 0; struct ocontext *c; struct superblock_security_struct *sbsec = sb->s_security; @@ -2809,6 +2801,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb) read_lock(&state->ss->policy_rwlock); policydb = &state->ss->policydb; + sidtab = state->ss->sidtab; c = policydb->ocontexts[OCON_FSUSE]; while (c) { @@ -2820,7 +2813,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb) if (c) { sbsec->behavior = c->v.behavior; if (!c->sid[0]) { - rc = context_struct_to_sid(state, &c->context[0], + rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; @@ -3068,7 +3061,7 @@ int security_sid_mls_copy(struct selinux_state *state, goto out_unlock; } } - rc = context_struct_to_sid(state, &newcon, new_sid); + rc = sidtab_context_to_sid(sidtab, &newcon, new_sid); out_unlock: read_unlock(&state->ss->policy_rwlock); context_destroy(&newcon); @@ -3661,7 +3654,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state, if (!mls_context_isvalid(policydb, &ctx_new)) goto out_free; - rc = context_struct_to_sid(state, &ctx_new, sid); + rc = sidtab_context_to_sid(sidtab, &ctx_new, sid); if (rc) goto out_free; diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index 98d5ea3fcde4..eb6d27b5aeb4 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -54,14 +54,15 @@ int sidtab_init(struct sidtab *s) return 0; } -static u32 context_to_sid(struct sidtab *s, struct context *context) +static u32 context_to_sid(struct sidtab *s, struct context *context, u32 hash) { struct sidtab_entry *entry; u32 sid = 0; rcu_read_lock(); - hash_for_each_possible_rcu(s->context_to_sid, entry, list, - context->hash) { + hash_for_each_possible_rcu(s->context_to_sid, entry, list, hash) { + if (entry->hash != hash) + continue; if (context_cmp(&entry->context, context)) { sid = entry->sid; break; @@ -74,6 +75,7 @@ static u32 context_to_sid(struct sidtab *s, struct context *context) int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context) { struct sidtab_isid_entry *isid; + u32 hash; int rc; if (sid == 0 || sid > SECINITSID_NUM) @@ -90,15 +92,18 @@ int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context) #endif isid->set = 1; + hash = context_compute_hash(context); + /* * Multiple initial sids may map to the same context. Check that this * context is not already represented in the context_to_sid hashtable * to avoid duplicate entries and long linked lists upon hash * collision. */ - if (!context_to_sid(s, context)) { + if (!context_to_sid(s, context, hash)) { isid->entry.sid = sid; - hash_add(s->context_to_sid, &isid->entry.list, context->hash); + isid->entry.hash = hash; + hash_add(s->context_to_sid, &isid->entry.list, hash); } return 0; @@ -259,12 +264,12 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid) { unsigned long flags; - u32 count; + u32 count, hash = context_compute_hash(context); struct sidtab_convert_params *convert; struct sidtab_entry *dst, *dst_convert; int rc; - *sid = context_to_sid(s, context); + *sid = context_to_sid(s, context, hash); if (*sid) return 0; @@ -272,7 +277,7 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, spin_lock_irqsave(&s->lock, flags); rc = 0; - *sid = context_to_sid(s, context); + *sid = context_to_sid(s, context, hash); if (*sid) goto out_unlock; @@ -291,6 +296,7 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, goto out_unlock; dst->sid = index_to_sid(count); + dst->hash = hash; rc = context_cpy(&dst->context, context); if (rc) @@ -315,10 +321,11 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, goto out_unlock; } dst_convert->sid = index_to_sid(count); + dst_convert->hash = context_compute_hash(&dst_convert->context); convert->target->count = count + 1; hash_add_rcu(convert->target->context_to_sid, - &dst_convert->list, dst_convert->context.hash); + &dst_convert->list, dst_convert->hash); } if (context->len) @@ -329,7 +336,7 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, /* write entries before updating count */ smp_store_release(&s->count, count + 1); - hash_add_rcu(s->context_to_sid, &dst->list, dst->context.hash); + hash_add_rcu(s->context_to_sid, &dst->list, dst->hash); rc = 0; out_unlock: @@ -345,10 +352,9 @@ static void sidtab_convert_hashtable(struct sidtab *s, u32 count) for (i = 0; i < count; i++) { entry = sidtab_do_lookup(s, i, 0); entry->sid = index_to_sid(i); + entry->hash = context_compute_hash(&entry->context); - hash_add_rcu(s->context_to_sid, &entry->list, - entry->context.hash); - + hash_add_rcu(s->context_to_sid, &entry->list, entry->hash); } } diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h index 3311d9f236c0..f2a84560b8b3 100644 --- a/security/selinux/ss/sidtab.h +++ b/security/selinux/ss/sidtab.h @@ -19,6 +19,7 @@ struct sidtab_entry { u32 sid; + u32 hash; struct context context; #if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 struct sidtab_str_cache __rcu *cache;