Commit 51e3b98d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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()
parents 121cc35c 20d387d7
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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);
+12 −2
Original line number Diff line number Diff line
@@ -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) {
+11 −0
Original line number Diff line number Diff line
@@ -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
+5 −4
Original line number Diff line number Diff line
@@ -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));
}

/**
+21 −5
Original line number Diff line number Diff line
@@ -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,
Loading