selinux/stable-6.19 PR 20251201

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCgAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmkuAKEUHHBhdWxAcGF1
 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXPKeA/8DSW+sTkQ9BMGGnyuH1uU/r84qtVh
 Ft6pnIPzrogE/GKcQeFgFA9D7gQbB8J39PSxZLS3lp0UiuPCuq+D09L+uzDKzDCD
 Avfe84dwsI5OiplPKyHiG3bF9W2+A1zkwH2j+5uC6yF8v9J9vglo4u5vAYeE2wxA
 X4b2r9jMm7WJ/KFNiSiiLGEhOSjVVUrJULcmWMRPPruplPDC4dLnqYTWTbkrfF8h
 /oXv/+ssqbj6FqfL4WaRnjN8GgZcwaWy1qu9LVlZ40iphpbVAyPBJPLJS6Q4hhOl
 mMHUbYkxALPyW7riQxoXAegQjJyGgKn8Bli9U6bkiKFA2yeIhJFX+OyV1SlOAs/J
 g6s5XfeCzqY0Tw3eqvT1YRhp10GcA7EtBYvhAe5ARq7PkMoqxmiI587piVX9hbos
 a0AH9CDNoOw+8QXx27sOoD1YIaiYD9fikXKymrzRRaW/GX6i43XIKiELBMuKoIVZ
 iwualvQiGBLLczzm5rdqPcLgp09Agn4AHfvFWXKFgS4+IJGKjeeXNOjsp9oFEivq
 RnXmDpa+nBud5zeTSeSpOY2L0pvuIG5N25N6U9bTsDe+4Y6p0qIAUy8e4sQ0PA8P
 xyp9/fcNr9jwHeLTjDbxZqZ+MU3GLIIVPdl0zq4z2J8nhkW3wD3pQX6B4qPIuXLx
 YP3nwhAT9T+hU7w=
 =IvVa
 -----END PGP SIGNATURE-----

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()
This commit is contained in:
Linus Torvalds 2025-12-03 10:45:47 -08:00
commit 51e3b98d73
11 changed files with 110 additions and 47 deletions

View File

@ -4,6 +4,8 @@
#include <linux/file.h>
#define MEMFD_ANON_NAME "[memfd]"
#ifdef CONFIG_MEMFD_CREATE
extern long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg);
struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx);

View File

@ -460,6 +460,8 @@ static struct file *alloc_file(const char *name, unsigned int flags)
{
unsigned int *file_seals;
struct file *file;
struct inode *inode;
int err = 0;
if (flags & MFD_HUGETLB) {
file = hugetlb_file_setup(name, 0, VM_NORESERVE,
@ -471,12 +473,20 @@ static struct file *alloc_file(const char *name, unsigned int flags)
}
if (IS_ERR(file))
return file;
inode = file_inode(file);
err = security_inode_init_security_anon(inode,
&QSTR(MEMFD_ANON_NAME), NULL);
if (err) {
fput(file);
file = ERR_PTR(err);
return file;
}
file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
file->f_flags |= O_LARGEFILE;
if (flags & MFD_NOEXEC_SEAL) {
struct inode *inode = file_inode(file);
inode->i_mode &= ~0111;
file_seals = memfd_file_seals_ptr(file);
if (file_seals) {

View File

@ -69,6 +69,17 @@ config SECURITY_SELINUX_SID2STR_CACHE_SIZE
If unsure, keep the default value.
config SECURITY_SELINUX_AVC_HASH_BITS
int "SELinux avc hashtable size"
depends on SECURITY_SELINUX
range 9 14
default 9
help
This option sets the number of buckets used in the AVC hash table
to 2^SECURITY_SELINUX_AVC_HASH_BITS. A higher value helps maintain
shorter chain lengths especially when expanding AVC nodes via
/sys/fs/selinux/avc/cache_threshold.
config SECURITY_SELINUX_DEBUG
bool "SELinux kernel debugging support"
depends on SECURITY_SELINUX

View File

@ -30,12 +30,13 @@
#include "avc.h"
#include "avc_ss.h"
#include "classmap.h"
#include "hash.h"
#define CREATE_TRACE_POINTS
#include <trace/events/avc.h>
#define AVC_CACHE_SLOTS 512
#define AVC_DEF_CACHE_THRESHOLD 512
#define AVC_CACHE_SLOTS (1 << CONFIG_SECURITY_SELINUX_AVC_HASH_BITS)
#define AVC_DEF_CACHE_THRESHOLD AVC_CACHE_SLOTS
#define AVC_CACHE_RECLAIM 16
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
@ -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));
}
/**

View File

@ -93,6 +93,7 @@
#include <linux/fanotify.h>
#include <linux/io_uring/cmd.h>
#include <uapi/linux/lsm.h>
#include <linux/memfd.h>
#include "initcalls.h"
#include "avc.h"
@ -2320,6 +2321,10 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
new_crsec = selinux_cred(bprm->cred);
isec = inode_security(inode);
if (WARN_ON(isec->sclass != SECCLASS_FILE &&
isec->sclass != SECCLASS_MEMFD_FILE))
return -EACCES;
/* Default to the current task SID. */
new_crsec->sid = old_crsec->sid;
new_crsec->osid = old_crsec->sid;
@ -2372,8 +2377,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
ad.u.file = bprm->file;
if (new_crsec->sid == old_crsec->sid) {
rc = avc_has_perm(old_crsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
rc = avc_has_perm(old_crsec->sid, isec->sid, isec->sclass,
FILE__EXECUTE_NO_TRANS, &ad);
if (rc)
return rc;
} else {
@ -2383,8 +2388,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
if (rc)
return rc;
rc = avc_has_perm(new_crsec->sid, isec->sid,
SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
rc = avc_has_perm(new_crsec->sid, isec->sid, isec->sclass,
FILE__ENTRYPOINT, &ad);
if (rc)
return rc;
@ -2979,10 +2984,18 @@ static int selinux_inode_init_security_anon(struct inode *inode,
struct common_audit_data ad;
struct inode_security_struct *isec;
int rc;
bool is_memfd = false;
if (unlikely(!selinux_initialized()))
return 0;
if (name != NULL && name->name != NULL &&
!strcmp(name->name, MEMFD_ANON_NAME)) {
if (!selinux_policycap_memfd_class())
return 0;
is_memfd = true;
}
isec = selinux_inode(inode);
/*
@ -3002,6 +3015,9 @@ static int selinux_inode_init_security_anon(struct inode *inode,
isec->sclass = context_isec->sclass;
isec->sid = context_isec->sid;
} else {
if (is_memfd)
isec->sclass = SECCLASS_MEMFD_FILE;
else
isec->sclass = SECCLASS_ANON_INODE;
rc = security_transition_sid(
sid, sid,

View File

@ -179,6 +179,8 @@ const struct security_class_mapping secclass_map[] = {
{ "anon_inode", { COMMON_FILE_PERMS, NULL } },
{ "io_uring", { "override_creds", "sqpoll", "cmd", "allowed", NULL } },
{ "user_namespace", { "create", NULL } },
{ "memfd_file",
{ COMMON_FILE_PERMS, "execute_no_trans", "entrypoint", NULL } },
/* last one */ { NULL, {} }
};

View File

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _SELINUX_HASH_H_
#define _SELINUX_HASH_H_
/*
* Based on MurmurHash3, written by Austin Appleby and placed in the
* public domain.
*/
static inline u32 av_hash(u32 key1, u32 key2, u32 key3, u32 mask)
{
static const u32 c1 = 0xcc9e2d51;
static const u32 c2 = 0x1b873593;
static const u32 r1 = 15;
static const u32 r2 = 13;
static const u32 m = 5;
static const u32 n = 0xe6546b64;
u32 hash = 0;
#define mix(input) \
do { \
u32 v = input; \
v *= c1; \
v = (v << r1) | (v >> (32 - r1)); \
v *= c2; \
hash ^= v; \
hash = (hash << r2) | (hash >> (32 - r2)); \
hash = hash * m + n; \
} while (0)
mix(key1);
mix(key2);
mix(key3);
#undef mix
hash ^= hash >> 16;
hash *= 0x85ebca6b;
hash ^= hash >> 13;
hash *= 0xc2b2ae35;
hash ^= hash >> 16;
return hash & mask;
}
#endif /* _SELINUX_HASH_H_ */

View File

@ -18,6 +18,7 @@ enum {
POLICYDB_CAP_NETIF_WILDCARD,
POLICYDB_CAP_GENFS_SECLABEL_WILDCARD,
POLICYDB_CAP_FUNCTIONFS_SECLABEL,
POLICYDB_CAP_MEMFD_CLASS,
__POLICYDB_CAP_MAX
};
#define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)

View File

@ -21,6 +21,7 @@ const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = {
"netif_wildcard",
"genfs_seclabel_wildcard",
"functionfs_seclabel",
"memfd_class",
};
/* clang-format on */

View File

@ -209,6 +209,11 @@ static inline bool selinux_policycap_functionfs_seclabel(void)
selinux_state.policycap[POLICYDB_CAP_FUNCTIONFS_SECLABEL]);
}
static inline bool selinux_policycap_memfd_class(void)
{
return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_MEMFD_CLASS]);
}
struct selinux_policy_convert_data;
struct selinux_load_state {

View File

@ -20,48 +20,15 @@
#include <linux/errno.h>
#include "avtab.h"
#include "policydb.h"
#include "hash.h"
static struct kmem_cache *avtab_node_cachep __ro_after_init;
static struct kmem_cache *avtab_xperms_cachep __ro_after_init;
/* 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 const u32 c1 = 0xcc9e2d51;
static const u32 c2 = 0x1b873593;
static const u32 r1 = 15;
static const u32 r2 = 13;
static const u32 m = 5;
static const u32 n = 0xe6546b64;
u32 hash = 0;
#define mix(input) \
do { \
u32 v = input; \
v *= c1; \
v = (v << r1) | (v >> (32 - r1)); \
v *= c2; \
hash ^= v; \
hash = (hash << r2) | (hash >> (32 - r2)); \
hash = hash * m + n; \
} while (0)
mix(keyp->target_class);
mix(keyp->target_type);
mix(keyp->source_type);
#undef mix
hash ^= hash >> 16;
hash *= 0x85ebca6b;
hash ^= hash >> 13;
hash *= 0xc2b2ae35;
hash ^= hash >> 16;
return hash & 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,