Merge tag 'selinux-pr-20200601' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / security / selinux / ss / sidtab.c
index f511ffccb131cbe533a733a176f5a17ff22de3fc..eb6d27b5aeb45631057518f5329e6de5b2a5f1e3 100644 (file)
@@ -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,12 +277,11 @@ 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;
 
-       /* read entries only after reading count */
-       count = smp_load_acquire(&s->count);
+       count = s->count;
        convert = s->convert;
 
        /* bail out if we already reached max entries */
@@ -292,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)
@@ -316,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)
@@ -330,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:
@@ -346,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);
        }
 }