Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'selinux-pr-20251201' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

Pull selinux updates from Paul Moore:

- Improve the granularity of SELinux labeling for memfd files

Currently when creating a memfd file, SELinux treats it the same as
any other tmpfs, or hugetlbfs, file. While simple, the drawback is
that it is not possible to differentiate between memfd and tmpfs
files.

This adds a call to the security_inode_init_security_anon() LSM hook
and wires up SELinux to provide a set of memfd specific access
controls, including the ability to control the execution of memfds.

As usual, the commit message has more information.

- Improve the SELinux AVC lookup performance

Adopt MurmurHash3 for the SELinux AVC hash function instead of the
custom hash function currently used. MurmurHash3 is already used for
the SELinux access vector table so the impact to the code is minimal,
and performance tests have shown improvements in both hash
distribution and latency.

See the commit message for the performance measurments.

- Introduce a Kconfig option for the SELinux AVC bucket/slot size

While we have the ability to grow the number of AVC hash buckets
today, the size of the buckets (slot size) is fixed at 512. This pull
request makes that slot size configurable at build time through a new
Kconfig knob, CONFIG_SECURITY_SELINUX_AVC_HASH_BITS.

* tag 'selinux-pr-20251201' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
selinux: improve bucket distribution uniformity of avc_hash()
selinux: Move avtab_hash() to a shared location for future reuse
selinux: Introduce a new config to make avc cache slot size adjustable
memfd,selinux: call security_inode_init_security_anon()

+110 -47
+2
include/linux/memfd.h
··· 4 4 5 5 #include <linux/file.h> 6 6 7 + #define MEMFD_ANON_NAME "[memfd]" 8 + 7 9 #ifdef CONFIG_MEMFD_CREATE 8 10 extern long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg); 9 11 struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx);
+12 -2
mm/memfd.c
··· 460 460 { 461 461 unsigned int *file_seals; 462 462 struct file *file; 463 + struct inode *inode; 464 + int err = 0; 463 465 464 466 if (flags & MFD_HUGETLB) { 465 467 file = hugetlb_file_setup(name, 0, VM_NORESERVE, ··· 473 471 } 474 472 if (IS_ERR(file)) 475 473 return file; 474 + 475 + inode = file_inode(file); 476 + err = security_inode_init_security_anon(inode, 477 + &QSTR(MEMFD_ANON_NAME), NULL); 478 + if (err) { 479 + fput(file); 480 + file = ERR_PTR(err); 481 + return file; 482 + } 483 + 476 484 file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; 477 485 file->f_flags |= O_LARGEFILE; 478 486 479 487 if (flags & MFD_NOEXEC_SEAL) { 480 - struct inode *inode = file_inode(file); 481 - 482 488 inode->i_mode &= ~0111; 483 489 file_seals = memfd_file_seals_ptr(file); 484 490 if (file_seals) {
+11
security/selinux/Kconfig
··· 69 69 70 70 If unsure, keep the default value. 71 71 72 + config SECURITY_SELINUX_AVC_HASH_BITS 73 + int "SELinux avc hashtable size" 74 + depends on SECURITY_SELINUX 75 + range 9 14 76 + default 9 77 + help 78 + This option sets the number of buckets used in the AVC hash table 79 + to 2^SECURITY_SELINUX_AVC_HASH_BITS. A higher value helps maintain 80 + shorter chain lengths especially when expanding AVC nodes via 81 + /sys/fs/selinux/avc/cache_threshold. 82 + 72 83 config SECURITY_SELINUX_DEBUG 73 84 bool "SELinux kernel debugging support" 74 85 depends on SECURITY_SELINUX
+5 -4
security/selinux/avc.c
··· 30 30 #include "avc.h" 31 31 #include "avc_ss.h" 32 32 #include "classmap.h" 33 + #include "hash.h" 33 34 34 35 #define CREATE_TRACE_POINTS 35 36 #include <trace/events/avc.h> 36 37 37 - #define AVC_CACHE_SLOTS 512 38 - #define AVC_DEF_CACHE_THRESHOLD 512 39 - #define AVC_CACHE_RECLAIM 16 38 + #define AVC_CACHE_SLOTS (1 << CONFIG_SECURITY_SELINUX_AVC_HASH_BITS) 39 + #define AVC_DEF_CACHE_THRESHOLD AVC_CACHE_SLOTS 40 + #define AVC_CACHE_RECLAIM 16 40 41 41 42 #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS 42 43 #define avc_cache_stats_incr(field) this_cpu_inc(avc_cache_stats.field) ··· 125 124 126 125 static inline u32 avc_hash(u32 ssid, u32 tsid, u16 tclass) 127 126 { 128 - return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1); 127 + return av_hash(ssid, tsid, (u32)tclass, (u32)(AVC_CACHE_SLOTS - 1)); 129 128 } 130 129 131 130 /**
+21 -5
security/selinux/hooks.c
··· 93 93 #include <linux/fanotify.h> 94 94 #include <linux/io_uring/cmd.h> 95 95 #include <uapi/linux/lsm.h> 96 + #include <linux/memfd.h> 96 97 97 98 #include "initcalls.h" 98 99 #include "avc.h" ··· 2321 2320 new_crsec = selinux_cred(bprm->cred); 2322 2321 isec = inode_security(inode); 2323 2322 2323 + if (WARN_ON(isec->sclass != SECCLASS_FILE && 2324 + isec->sclass != SECCLASS_MEMFD_FILE)) 2325 + return -EACCES; 2326 + 2324 2327 /* Default to the current task SID. */ 2325 2328 new_crsec->sid = old_crsec->sid; 2326 2329 new_crsec->osid = old_crsec->sid; ··· 2377 2372 ad.u.file = bprm->file; 2378 2373 2379 2374 if (new_crsec->sid == old_crsec->sid) { 2380 - rc = avc_has_perm(old_crsec->sid, isec->sid, 2381 - SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); 2375 + rc = avc_has_perm(old_crsec->sid, isec->sid, isec->sclass, 2376 + FILE__EXECUTE_NO_TRANS, &ad); 2382 2377 if (rc) 2383 2378 return rc; 2384 2379 } else { ··· 2388 2383 if (rc) 2389 2384 return rc; 2390 2385 2391 - rc = avc_has_perm(new_crsec->sid, isec->sid, 2392 - SECCLASS_FILE, FILE__ENTRYPOINT, &ad); 2386 + rc = avc_has_perm(new_crsec->sid, isec->sid, isec->sclass, 2387 + FILE__ENTRYPOINT, &ad); 2393 2388 if (rc) 2394 2389 return rc; 2395 2390 ··· 2984 2979 struct common_audit_data ad; 2985 2980 struct inode_security_struct *isec; 2986 2981 int rc; 2982 + bool is_memfd = false; 2987 2983 2988 2984 if (unlikely(!selinux_initialized())) 2989 2985 return 0; 2986 + 2987 + if (name != NULL && name->name != NULL && 2988 + !strcmp(name->name, MEMFD_ANON_NAME)) { 2989 + if (!selinux_policycap_memfd_class()) 2990 + return 0; 2991 + is_memfd = true; 2992 + } 2990 2993 2991 2994 isec = selinux_inode(inode); 2992 2995 ··· 3015 3002 isec->sclass = context_isec->sclass; 3016 3003 isec->sid = context_isec->sid; 3017 3004 } else { 3018 - isec->sclass = SECCLASS_ANON_INODE; 3005 + if (is_memfd) 3006 + isec->sclass = SECCLASS_MEMFD_FILE; 3007 + else 3008 + isec->sclass = SECCLASS_ANON_INODE; 3019 3009 rc = security_transition_sid( 3020 3010 sid, sid, 3021 3011 isec->sclass, name, &isec->sid);
+2
security/selinux/include/classmap.h
··· 179 179 { "anon_inode", { COMMON_FILE_PERMS, NULL } }, 180 180 { "io_uring", { "override_creds", "sqpoll", "cmd", "allowed", NULL } }, 181 181 { "user_namespace", { "create", NULL } }, 182 + { "memfd_file", 183 + { COMMON_FILE_PERMS, "execute_no_trans", "entrypoint", NULL } }, 182 184 /* last one */ { NULL, {} } 183 185 }; 184 186
+47
security/selinux/include/hash.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + 3 + #ifndef _SELINUX_HASH_H_ 4 + #define _SELINUX_HASH_H_ 5 + 6 + /* 7 + * Based on MurmurHash3, written by Austin Appleby and placed in the 8 + * public domain. 9 + */ 10 + static inline u32 av_hash(u32 key1, u32 key2, u32 key3, u32 mask) 11 + { 12 + static const u32 c1 = 0xcc9e2d51; 13 + static const u32 c2 = 0x1b873593; 14 + static const u32 r1 = 15; 15 + static const u32 r2 = 13; 16 + static const u32 m = 5; 17 + static const u32 n = 0xe6546b64; 18 + 19 + u32 hash = 0; 20 + 21 + #define mix(input) \ 22 + do { \ 23 + u32 v = input; \ 24 + v *= c1; \ 25 + v = (v << r1) | (v >> (32 - r1)); \ 26 + v *= c2; \ 27 + hash ^= v; \ 28 + hash = (hash << r2) | (hash >> (32 - r2)); \ 29 + hash = hash * m + n; \ 30 + } while (0) 31 + 32 + mix(key1); 33 + mix(key2); 34 + mix(key3); 35 + 36 + #undef mix 37 + 38 + hash ^= hash >> 16; 39 + hash *= 0x85ebca6b; 40 + hash ^= hash >> 13; 41 + hash *= 0xc2b2ae35; 42 + hash ^= hash >> 16; 43 + 44 + return hash & mask; 45 + } 46 + 47 + #endif /* _SELINUX_HASH_H_ */
+1
security/selinux/include/policycap.h
··· 18 18 POLICYDB_CAP_NETIF_WILDCARD, 19 19 POLICYDB_CAP_GENFS_SECLABEL_WILDCARD, 20 20 POLICYDB_CAP_FUNCTIONFS_SECLABEL, 21 + POLICYDB_CAP_MEMFD_CLASS, 21 22 __POLICYDB_CAP_MAX 22 23 }; 23 24 #define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)
+1
security/selinux/include/policycap_names.h
··· 21 21 "netif_wildcard", 22 22 "genfs_seclabel_wildcard", 23 23 "functionfs_seclabel", 24 + "memfd_class", 24 25 }; 25 26 /* clang-format on */ 26 27
+5
security/selinux/include/security.h
··· 209 209 selinux_state.policycap[POLICYDB_CAP_FUNCTIONFS_SECLABEL]); 210 210 } 211 211 212 + static inline bool selinux_policycap_memfd_class(void) 213 + { 214 + return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_MEMFD_CLASS]); 215 + } 216 + 212 217 struct selinux_policy_convert_data; 213 218 214 219 struct selinux_load_state {
+3 -36
security/selinux/ss/avtab.c
··· 20 20 #include <linux/errno.h> 21 21 #include "avtab.h" 22 22 #include "policydb.h" 23 + #include "hash.h" 23 24 24 25 static struct kmem_cache *avtab_node_cachep __ro_after_init; 25 26 static struct kmem_cache *avtab_xperms_cachep __ro_after_init; 26 27 27 - /* Based on MurmurHash3, written by Austin Appleby and placed in the 28 - * public domain. 29 - */ 30 28 static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask) 31 29 { 32 - static const u32 c1 = 0xcc9e2d51; 33 - static const u32 c2 = 0x1b873593; 34 - static const u32 r1 = 15; 35 - static const u32 r2 = 13; 36 - static const u32 m = 5; 37 - static const u32 n = 0xe6546b64; 38 - 39 - u32 hash = 0; 40 - 41 - #define mix(input) \ 42 - do { \ 43 - u32 v = input; \ 44 - v *= c1; \ 45 - v = (v << r1) | (v >> (32 - r1)); \ 46 - v *= c2; \ 47 - hash ^= v; \ 48 - hash = (hash << r2) | (hash >> (32 - r2)); \ 49 - hash = hash * m + n; \ 50 - } while (0) 51 - 52 - mix(keyp->target_class); 53 - mix(keyp->target_type); 54 - mix(keyp->source_type); 55 - 56 - #undef mix 57 - 58 - hash ^= hash >> 16; 59 - hash *= 0x85ebca6b; 60 - hash ^= hash >> 13; 61 - hash *= 0xc2b2ae35; 62 - hash ^= hash >> 16; 63 - 64 - return hash & mask; 30 + return av_hash((u32)keyp->target_class, (u32)keyp->target_type, 31 + (u32)keyp->source_type, mask); 65 32 } 66 33 67 34 static struct avtab_node *avtab_insert_node(struct avtab *h,