]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selinux: improve bucket distribution uniformity of avc_hash()
authorHongru Zhang <zhanghongru@xiaomi.com>
Thu, 23 Oct 2025 11:30:18 +0000 (19:30 +0800)
committerPaul Moore <paul@paul-moore.com>
Thu, 23 Oct 2025 22:24:30 +0000 (18:24 -0400)
Reuse the already implemented MurmurHash3 algorithm. Under heavy stress
testing (on an 8-core system sustaining over 50,000 authentication events
per second), sample once per second and take the mean of 1800 samples:

1. Bucket utilization rate and length of longest chain
+--------------------------+-----------------------------------------+
|                          | bucket utilization rate / longest chain |
|                          +--------------------+--------------------+
|                          |      no-patch      |     with-patch     |
+--------------------------+--------------------+--------------------+
|  512 nodes,  512 buckets |      52.5%/7.5     |     60.2%/5.7      |
+--------------------------+--------------------+--------------------+
| 1024 nodes,  512 buckets |      68.9%/12.1    |     80.2%/9.7      |
+--------------------------+--------------------+--------------------+
| 2048 nodes,  512 buckets |      83.7%/19.4    |     93.4%/16.3     |
+--------------------------+--------------------+--------------------+
| 8192 nodes, 8192 buckets |      49.5%/11.4    |     60.3%/7.4      |
+--------------------------+--------------------+--------------------+

2. avc_search_node latency (total latency of hash operation and table
lookup)
+--------------------------+-----------------------------------------+
|                          |   latency of function avc_search_node   |
|                          +--------------------+--------------------+
|                          |      no-patch      |     with-patch     |
+--------------------------+--------------------+--------------------+
|  512 nodes,  512 buckets |        87ns        |        84ns        |
+--------------------------+--------------------+--------------------+
| 1024 nodes,  512 buckets |        97ns        |        96ns        |
+--------------------------+--------------------+--------------------+
| 2048 nodes,  512 buckets |       118ns        |       113ns        |
+--------------------------+--------------------+--------------------+
| 8192 nodes, 8192 buckets |       106ns        |        99ns        |
+--------------------------+--------------------+--------------------+

Although MurmurHash3 has higher overhead than the bitwise operations in
the original algorithm, the data shows that the MurmurHash3 achieves
better distribution, reducing average lookup time. Consequently, the
total latency of hashing and table lookup is lower than before.

Signed-off-by: Hongru Zhang <zhanghongru@xiaomi.com>
[PM: whitespace fixes]
Signed-off-by: Paul Moore <paul@paul-moore.com>
security/selinux/avc.c
security/selinux/include/hash.h
security/selinux/ss/avtab.c

index c12d45e46db6e8d3b531cde111bc13bcdace5af7..8f77b9a732e16880d20a1e293e8fcb0ea47fc51b 100644 (file)
@@ -30,6 +30,7 @@
 #include "avc.h"
 #include "avc_ss.h"
 #include "classmap.h"
+#include "hash.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/avc.h>
@@ -124,7 +125,7 @@ static struct kmem_cache *avc_xperms_cachep __ro_after_init;
 
 static inline u32 avc_hash(u32 ssid, u32 tsid, u16 tclass)
 {
-       return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
+       return av_hash(ssid, tsid, (u32)tclass, (u32)(AVC_CACHE_SLOTS - 1));
 }
 
 /**
index 5b429a873eb6c1ef15d0f9dee7debc781d330ca4..18956dbef8ffd24a8c5aae9c97977235eb4350a6 100644 (file)
@@ -3,10 +3,11 @@
 #ifndef _SELINUX_HASH_H_
 #define _SELINUX_HASH_H_
 
-/* Based on MurmurHash3, written by Austin Appleby and placed in the
+/*
+ * Based on MurmurHash3, written by Austin Appleby and placed in the
  * public domain.
  */
-static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask)
+static inline u32 av_hash(u32 key1, u32 key2, u32 key3, u32 mask)
 {
        static const u32 c1 = 0xcc9e2d51;
        static const u32 c2 = 0x1b873593;
@@ -28,9 +29,9 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask)
                hash = hash * m + n;                       \
        } while (0)
 
-       mix(keyp->target_class);
-       mix(keyp->target_type);
-       mix(keyp->source_type);
+       mix(key1);
+       mix(key2);
+       mix(key3);
 
 #undef mix
 
index 15e89d9b5d721aff6f58aebf20193cbc6940f825..d12ca337e6498261b9f3f8cb57219d36eb381bf0 100644 (file)
 static struct kmem_cache *avtab_node_cachep __ro_after_init;
 static struct kmem_cache *avtab_xperms_cachep __ro_after_init;
 
+static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask)
+{
+       return av_hash((u32)keyp->target_class, (u32)keyp->target_type,
+                      (u32)keyp->source_type, mask);
+}
+
 static struct avtab_node *avtab_insert_node(struct avtab *h,
                                            struct avtab_node **dst,
                                            const struct avtab_key *key,