Linux Security Modules development
 help / color / mirror / Atom feed
* Re: [PATCH v3 01/14] ACPI: APEI: Remove redundant rcu_read_lock/unlock() in spin_lock
From: Hanjun Guo @ 2025-09-27  3:22 UTC (permalink / raw)
  To: pengdonglin, tj, tony.luck, jani.nikula, ap420073, jv, freude,
	bcrl, trondmy, longman, kees
  Cc: bigeasy, hdanton, paulmck, linux-kernel, linux-rt-devel,
	linux-nfs, linux-aio, linux-fsdevel, linux-security-module,
	netdev, intel-gfx, linux-wireless, linux-acpi, linux-s390,
	cgroups, Rafael J. Wysocki, pengdonglin
In-Reply-To: <20250916044735.2316171-2-dolinux.peng@gmail.com>

On 2025/9/16 12:47, pengdonglin wrote:
> From: pengdonglin <pengdonglin@xiaomi.com>
> 
> Since commit a8bb74acd8efe ("rcu: Consolidate RCU-sched update-side function definitions")
> there is no difference between rcu_read_lock(), rcu_read_lock_bh() and
> rcu_read_lock_sched() in terms of RCU read section and the relevant grace
> period. That means that spin_lock(), which implies rcu_read_lock_sched(),
> also implies rcu_read_lock().
> 
> There is no need no explicitly start a RCU read section if one has already
> been started implicitly by spin_lock().
> 
> Simplify the code and remove the inner rcu_read_lock() invocation.
> 
> Cc: "Rafael J. Wysocki" <rafael@kernel.org>
> Cc: Tony Luck <tony.luck@intel.com>
> Cc: Hanjun Guo <guohanjun@huawei.com>
> Signed-off-by: pengdonglin <pengdonglin@xiaomi.com>
> Signed-off-by: pengdonglin <dolinux.peng@gmail.com>
> ---
>   drivers/acpi/apei/ghes.c | 2 --
>   1 file changed, 2 deletions(-)
> 
> diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
> index a0d54993edb3..97ee19f2cae0 100644
> --- a/drivers/acpi/apei/ghes.c
> +++ b/drivers/acpi/apei/ghes.c
> @@ -1207,12 +1207,10 @@ static int ghes_notify_hed(struct notifier_block *this, unsigned long event,
>   	int ret = NOTIFY_DONE;
>   
>   	spin_lock_irqsave(&ghes_notify_lock_irq, flags);
> -	rcu_read_lock();
>   	list_for_each_entry_rcu(ghes, &ghes_hed, list) {
>   		if (!ghes_proc(ghes))
>   			ret = NOTIFY_OK;
>   	}
> -	rcu_read_unlock();
>   	spin_unlock_irqrestore(&ghes_notify_lock_irq, flags);
>   
>   	return ret;

Reviewed-by: Hanjun Guo <guohanjun@huawei.com>

Thanks
Hanjun

^ permalink raw reply

* [GIT PULL] lsm/lsm-pr-20250926
From: Paul Moore @ 2025-09-27  3:07 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-security-module, linux-kernel

Linus,

Here are the LSM framework patches for the upcoming Linux v6.18 merge
window:

- Move the management of the LSM BPF security blobs into the framework

  In order to enable multiple LSMs we need to allocate and free the
  various security blobs in the LSM framework and not the individual
  LSMs as they would end up stepping all over each other.

- Leverage the lsm_bdev_alloc() helper in lsm_bdev_alloc()

  Make better use of our existing helper functions to reduce some code
  duplication.

- Update the Rust cred code to use 'sync::aref'

  Part of a larger effort to move the Rust code over to the 'sync'
  module.

- Make CONFIG_LSM dependent on CONFIG_SECURITY

  As the CONFIG_LSM Kconfig setting is an ordered list of the LSMs to
  enable a boot, it obviously doesn't make much sense to enable this
  when CONFIG_SECURITY is disabled.

- Update the LSM and CREDENTIALS sections in MAINTAINERS with Rusty bits

  Add the Rust helper files to the associated LSM and CREDENTIALS entries
  int the MAINTAINERS file.  We're trying to improve the communication
  between the two groups and making sure we're all aware of what is
  going on via cross-posting to the relevant lists is a good way to
  start.

Paul

--
The following changes since commit 8f5ae30d69d7543eee0d70083daf4de8fe15d585:

  Linux 6.17-rc1 (2025-08-10 19:41:16 +0300)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git
    tags/lsm-pr-20250926

for you to fetch changes up to 54d94c422fed9575b74167333c1757847a4e6899:

  lsm: CONFIG_LSM can depend on CONFIG_SECURITY
    (2025-09-11 16:32:04 -0400)

----------------------------------------------------------------
lsm/stable-6.18 PR 20250926
----------------------------------------------------------------

Blaise Boscaccy (1):
      lsm,selinux: Add LSM blob support for BPF objects

Paul Moore (3):
      lsm: use lsm_blob_alloc() in lsm_bdev_alloc()
      MAINTAINERS: add the associated Rust helper to the LSM section
      MAINTAINERS: add the associated Rust helper to the CREDENTIALS
         section

Qianfeng Rong (1):
      security: use umax() to improve code

Randy Dunlap (1):
      lsm: CONFIG_LSM can depend on CONFIG_SECURITY

Shankari Anand (1):
      rust,cred: update AlwaysRefCounted import to sync::aref

 MAINTAINERS                       |    2 
 include/linux/lsm_hooks.h         |    3 
 rust/kernel/cred.rs               |    6 -
 security/Kconfig                  |    1 
 security/min_addr.c               |    6 -
 security/security.c               |   98 ++++++++++++++++++++++++++----
 security/selinux/hooks.c          |   56 +++--------------
 security/selinux/include/objsec.h |   20 ++++++
 8 files changed, 124 insertions(+), 68 deletions(-)

--
paul-moore.com

^ permalink raw reply

* [GIT PULL] selinux/selinux-pr-20250926
From: Paul Moore @ 2025-09-27  3:07 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: selinux, linux-security-module, linux-kernel

Linus,

Here are the SELinux patches for the upcoming Linux v6.18 merge window:

- Support per-file labeling for functionfs

  Both genfscon and user defined labeling methods are supported.  This
  should help users who want to provide separation between the control
  endpoint file, "ep0", and other endpoints.

- Remove our use of get_zeroed_page() in sel_read_bool()

  Update sel_read_bool() to use a four byte stack buffer instead of a
  memory page fetched via get_zeroed_page(), and fix a memory in the
  process.

  Needless to say we should have done this a long time ago, but it was
  in a very old chunk of code that "just worked" and I don't think
  anyone had taken a real look at it in many years.

- Better use of the netdev skb/sock helper functions

  Convert a sk_to_full_sk(skb->sk) into a skb_to_full_sk(skb) call.

- Remove some old, dead, and/or redundant code

Paul

--
The following changes since commit 8f5ae30d69d7543eee0d70083daf4de8fe15d585:

  Linux 6.17-rc1 (2025-08-10 19:41:16 +0300)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
    tags/selinux-pr-20250926

for you to fetch changes up to 68e1e908cb7682db9fb7f79907f9352435a81c0f:

  selinux: enable per-file labeling for functionfs
    (2025-09-07 12:54:56 -0400)

----------------------------------------------------------------
selinux/stable-6.18 PR 20250926
----------------------------------------------------------------

Neill Kapron (1):
      selinux: enable per-file labeling for functionfs

Qianfeng Rong (1):
      selinux: Remove redundant __GFP_NOWARN

Stephen Smalley (1):
      selinux: fix sel_read_bool() allocation and error handling

Tianjia Zhang (1):
      selinux: use a consistent method to get full socket from skb

Yue Haibing (1):
      selinux: Remove unused function selinux_policycap_netif_wildcard()

 security/selinux/avc.c                     |   13 ++++++-------
 security/selinux/hooks.c                   |   10 +++++++---
 security/selinux/include/policycap.h       |    1 +
 security/selinux/include/policycap_names.h |    1 +
 security/selinux/include/security.h        |    4 ++--
 security/selinux/selinuxfs.c               |   18 +++++-------------
 6 files changed, 22 insertions(+), 25 deletions(-)

--
paul-moore.com

^ permalink raw reply

* [PATCH bpf-next 2/2] selftests/bpf: Enable map verification for some lskel tests
From: Blaise Boscaccy @ 2025-09-26 20:30 UTC (permalink / raw)
  To: bpf, linux-security-module, kpsingh, bboscaccy, paul, kys, ast,
	daniel, andrii, James.Bottomley, wufan
In-Reply-To: <20250926203111.1305999-1-bboscaccy@linux.microsoft.com>

Convert an existing signed lskel test to use the newly introduced map
signature hash-chain support added to libbpf.

Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
---
 tools/testing/selftests/bpf/Makefile | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 0b6ee902bce51..dab70f6fa6ad8 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -500,12 +500,14 @@ LSKELS := fexit_sleep.c trace_printk.c trace_vprintk.c map_ptr_kern.c 	\
 	core_kern.c core_kern_overflow.c test_ringbuf.c			\
 	test_ringbuf_n.c test_ringbuf_map_key.c test_ringbuf_write.c
 
-LSKELS_SIGNED := fentry_test.c fexit_test.c atomics.c
+LSKELS_SIGNED := fentry_test.c fexit_test.c
+
+LSKELS_SIGNED_MAPS := atomics.c
 
 # Generate both light skeleton and libbpf skeleton for these
 LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test.c \
 	kfunc_call_test_subprog.c
-SKEL_BLACKLIST += $$(LSKELS) $$(LSKELS_SIGNED)
+SKEL_BLACKLIST += $$(LSKELS) $$(LSKELS_SIGNED) $$(LSKELS_SIGNED_MAPS)
 
 test_static_linked.skel.h-deps := test_static_linked1.bpf.o test_static_linked2.bpf.o
 linked_funcs.skel.h-deps := linked_funcs1.bpf.o linked_funcs2.bpf.o
@@ -537,6 +539,7 @@ HEADERS_FOR_BPF_OBJS := $(wildcard $(BPFDIR)/*.bpf.h)		\
 define DEFINE_TEST_RUNNER
 
 LSKEL_SIGN := -S -k $(PRIVATE_KEY) -i $(VERIFICATION_CERT)
+LSKEL_SIGN_MAPS := -S -M -k $(PRIVATE_KEY) -i $(VERIFICATION_CERT)
 TRUNNER_OUTPUT := $(OUTPUT)$(if $2,/)$2
 TRUNNER_BINARY := $1$(if $2,-)$2
 TRUNNER_TEST_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.test.o,	\
@@ -553,6 +556,7 @@ TRUNNER_BPF_SKELS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.skel.h,	\
 TRUNNER_BPF_LSKELS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.lskel.h, $$(LSKELS) $$(LSKELS_EXTRA))
 TRUNNER_BPF_SKELS_LINKED := $$(addprefix $$(TRUNNER_OUTPUT)/,$(LINKED_SKELS))
 TRUNNER_BPF_LSKELS_SIGNED := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.lskel.h, $$(LSKELS_SIGNED))
+TRUNNER_BPF_LSKELS_SIGNED_MAPS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.lskel.h, $$(LSKELS_SIGNED_MAPS))
 TEST_GEN_FILES += $$(TRUNNER_BPF_OBJS)
 
 # Evaluate rules now with extra TRUNNER_XXX variables above already defined
@@ -616,6 +620,15 @@ $(TRUNNER_BPF_LSKELS_SIGNED): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
 	$(Q)$$(BPFTOOL) gen skeleton $(LSKEL_SIGN) $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@
 	$(Q)rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
 
+$(TRUNNER_BPF_LSKELS_SIGNED_MAPS): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
+	$$(call msg,GEN-SKEL,$(TRUNNER_BINARY) (signed),$$@)
+	$(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked1.o) $$<
+	$(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o)
+	$(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o)
+	$(Q)diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
+	$(Q)$$(BPFTOOL) gen skeleton $(LSKEL_SIGN_MAPS) $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@
+	$(Q)rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
+
 $(LINKED_BPF_OBJS): %: $(TRUNNER_OUTPUT)/%
 
 # .SECONDEXPANSION here allows to correctly expand %-deps variables as prerequisites
@@ -666,6 +679,7 @@ $(TRUNNER_TEST_OBJS:.o=.d): $(TRUNNER_OUTPUT)/%.test.d:			\
 			    $(TRUNNER_BPF_SKELS)			\
 			    $(TRUNNER_BPF_LSKELS)			\
 			    $(TRUNNER_BPF_LSKELS_SIGNED)		\
+			    $(TRUNNER_BPF_LSKELS_SIGNED_MAPS)		\
 			    $(TRUNNER_BPF_SKELS_LINKED)			\
 			    $$(BPFOBJ) | $(TRUNNER_OUTPUT)
 
-- 
2.48.1


^ permalink raw reply related

* [PATCH bpf-next 1/2] bpf: Add hash chain signature support for arbitrary maps
From: Blaise Boscaccy @ 2025-09-26 20:30 UTC (permalink / raw)
  To: bpf, linux-security-module, kpsingh, bboscaccy, paul, kys, ast,
	daniel, andrii, James.Bottomley, wufan
In-Reply-To: <20250926203111.1305999-1-bboscaccy@linux.microsoft.com>

This patch introduces hash chain support for signature verification of
arbitrary bpf map objects which was described here:
https://lore.kernel.org/linux-security-module/20250721211958.1881379-1-kpsingh@kernel.org/

The UAPI is extended to allow for in-kernel checking of maps passed in
via the fd_array. A hash chain is constructed from the maps, in order
specified by the signature_maps field. The hash chain is terminated
with the hash of the program itself.

Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
---
 include/uapi/linux/bpf.h                      |  6 ++
 kernel/bpf/syscall.c                          | 73 ++++++++++++++++++-
 .../bpf/bpftool/Documentation/bpftool-gen.rst |  7 +-
 tools/bpf/bpftool/gen.c                       | 27 ++++++-
 tools/bpf/bpftool/main.c                      |  9 ++-
 tools/bpf/bpftool/main.h                      |  1 +
 tools/bpf/bpftool/sign.c                      | 17 ++++-
 tools/include/uapi/linux/bpf.h                |  6 ++
 tools/lib/bpf/libbpf.h                        |  3 +-
 tools/lib/bpf/skel_internal.h                 |  6 +-
 10 files changed, 143 insertions(+), 12 deletions(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index ae83d8649ef1c..a436a2ff49437 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1621,6 +1621,12 @@ union bpf_attr {
 		 * verification.
 		 */
 		__s32		keyring_id;
+		/* Pointer to a buffer containing the maps used in the signature
+		 * hash chain of the BPF program.
+		 */
+		__aligned_u64   signature_maps;
+		/* Size of the signature maps buffer. */
+		__u32		signature_maps_size;
 	};
 
 	struct { /* anonymous struct used by BPF_OBJ_* commands */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index adb05d235011f..eb5c210639ccf 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2800,14 +2800,35 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
 	}
 }
 
+static inline int bpf_map_get_hash(int map_fd, void *buffer)
+{
+	struct bpf_map *map;
+
+	CLASS(fd, f)(map_fd);
+	map = __bpf_map_get(f);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+
+	if (!map->ops->map_get_hash)
+		return -EINVAL;
+
+	return map->ops->map_get_hash(map, SHA256_DIGEST_SIZE, buffer);
+}
+
 static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr,
 				     bool is_kernel)
 {
 	bpfptr_t usig = make_bpfptr(attr->signature, is_kernel);
-	struct bpf_dynptr_kern sig_ptr, insns_ptr;
+	bpfptr_t umaps;
+	struct bpf_dynptr_kern sig_ptr, insns_ptr, hash_ptr;
 	struct bpf_key *key = NULL;
 	void *sig;
+	int *maps;
+	int map_fd;
 	int err = 0;
+	u64 buffer[SHA256_DIGEST_SIZE * 2 / sizeof(u64)];
+	u64 hash[SHA256_DIGEST_SIZE / sizeof(u64)];
+	int n;
 
 	if (system_keyring_id_check(attr->keyring_id) == 0)
 		key = bpf_lookup_system_key(attr->keyring_id);
@@ -2828,16 +2849,60 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr
 	bpf_dynptr_init(&insns_ptr, prog->insnsi, BPF_DYNPTR_TYPE_LOCAL, 0,
 			prog->len * sizeof(struct bpf_insn));
 
-	err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr,
-					 (struct bpf_dynptr *)&sig_ptr, key);
+	if (!attr->signature_maps_size) {
+		err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr,
+						 (struct bpf_dynptr *)&sig_ptr, key);
+	} else {
+		bpf_dynptr_init(&hash_ptr, hash, BPF_DYNPTR_TYPE_LOCAL, 0,
+				sizeof(hash));
+		umaps = make_bpfptr(attr->signature_maps, is_kernel);
+		maps = kvmemdup_bpfptr(umaps, attr->signature_maps_size * sizeof(*maps));
+		if (!maps) {
+			err = -ENOMEM;
+			goto out;
+		}
+		/* Process the map array in reverse order to generate a hash chain
+		 * h(n) = sha256(h(n + 1), sha256(map(n)))
+		 * h(n_len) = sha256(map(n_len))
+		 */
+		for (n = attr->signature_maps_size - 1; n >= 0; n--) {
+			err = copy_from_bpfptr_offset(&map_fd,
+						      make_bpfptr(attr->fd_array, is_kernel),
+						      maps[n] * sizeof(map_fd),
+						      sizeof(map_fd));
+			if (err)
+				goto free_maps;
+
+			if (n == attr->signature_maps_size - 1)
+				err = bpf_map_get_hash(map_fd, hash);
+			else {
+				memcpy(buffer, hash, sizeof(hash));
+				err = bpf_map_get_hash(map_fd, buffer + ARRAY_SIZE(hash));
+				sha256((u8 *)buffer, sizeof(buffer), (u8 *)&hash);
+			}
+			if (err)
+				goto free_maps;
+		}
+		/* Calculate final hash with program instructions
+		 * f_hash = sha256(sha256(prog), h(0))
+		 */
+		sha256((u8 *)prog->insnsi, prog->len * sizeof(struct bpf_insn), (u8 *)&buffer);
+		memcpy(buffer + ARRAY_SIZE(hash), hash, sizeof(hash));
+		sha256((u8 *)buffer, sizeof(buffer), (u8 *)&hash);
+		err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&hash_ptr,
+						 (struct bpf_dynptr *)&sig_ptr, key);
 
+free_maps:
+		kvfree(maps);
+	}
+out:
 	bpf_key_put(key);
 	kvfree(sig);
 	return err;
 }
 
 /* last field in 'union bpf_attr' used by this command */
-#define BPF_PROG_LOAD_LAST_FIELD keyring_id
+#define BPF_PROG_LOAD_LAST_FIELD signature_maps_size
 
 static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
 {
diff --git a/tools/bpf/bpftool/Documentation/bpftool-gen.rst b/tools/bpf/bpftool/Documentation/bpftool-gen.rst
index d0a36f442db72..b632ab87adf20 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-gen.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-gen.rst
@@ -16,7 +16,7 @@ SYNOPSIS
 
 **bpftool** [*OPTIONS*] **gen** *COMMAND*
 
-*OPTIONS* := { |COMMON_OPTIONS| | { **-L** | **--use-loader** } | [ { **-S** | **--sign** } {**-k** <private_key.pem>} **-i** <certificate.x509> ] }
+*OPTIONS* := { |COMMON_OPTIONS| | { **-L** | **--use-loader** } | [ { **-S** | **--sign** } { **-M** | **--sign-maps** } {**-k** <private_key.pem>} **-i** <certificate.x509> ] }
 
 *COMMAND* := { **object** | **skeleton** | **help** }
 
@@ -190,6 +190,11 @@ OPTIONS
     For skeletons, generate a signed skeleton. This option must be used with
     **-k** and **-i**. Using this flag implicitly enables **--use-loader**.
 
+-M --sign-maps
+    For skeletons, generate a signed skeleton that includes a hash chain for the
+    skeletons maps. This option must be used with **-k** and **-i**. Using this
+    flag implicitly enables **--use-loader** and **--sign**.
+
 -k <private_key.pem>
     Path to the private key file in PEM format, required for signing.
 
diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 993c7d9484a46..1c4278e2a662b 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -699,6 +699,9 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 	if (sign_progs)
 		opts.gen_hash = true;
 
+	if (sign_maps)
+		opts.sign_maps = true;
+
 	err = bpf_object__gen_loader(obj, &opts);
 	if (err)
 		return err;
@@ -793,6 +796,8 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 	if (sign_progs) {
 		sopts.insns = opts.insns;
 		sopts.insns_sz = opts.insns_sz;
+		sopts.data = opts.data;
+		sopts.data_sz = opts.data_sz;
 		sopts.excl_prog_hash = prog_sha;
 		sopts.excl_prog_hash_sz = sizeof(prog_sha);
 		sopts.signature = sig_buf;
@@ -822,6 +827,13 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		\n\
 		\";\n");
 
+		if (sign_maps) {
+			codegen("\
+			\n\
+				static const int opts_signature_maps[1] __attribute__((__aligned__(8))) = {0}; \n\
+			");
+		}
+
 		codegen("\
 		\n\
 			opts.signature = (void *)opts_sig;			\n\
@@ -830,6 +842,19 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 			opts.excl_prog_hash_sz = sizeof(opts_excl_hash) - 1;	\n\
 			opts.keyring_id = skel->keyring_id;			\n\
 		");
+		if (sign_maps) {
+			codegen("\
+			\n\
+				opts.signature_maps = (void *)opts_signature_maps;	\n\
+				opts.signature_maps_sz = 1; 				\n\
+			");
+		} else {
+			codegen("\
+			\n\
+				opts.signature_maps = (void *)NULL;		\n\
+				opts.signature_maps_sz = 0;			\n\
+			");
+		}
 	}
 
 	codegen("\
@@ -1990,7 +2015,7 @@ static int do_help(int argc, char **argv)
 		"       %1$s %2$s help\n"
 		"\n"
 		"       " HELP_SPEC_OPTIONS " |\n"
-		"                    {-L|--use-loader} | [ {-S|--sign } {-k} <private_key.pem> {-i} <certificate.x509> ]}\n"
+		"                    {-L|--use-loader} | [ {-S|--sign } {-M|--sign-maps } {-k} <private_key.pem> {-i} <certificate.x509> ]}\n"
 		"",
 		bin_name, "gen");
 
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
index a829a6a49037a..47b14dcbae4ee 100644
--- a/tools/bpf/bpftool/main.c
+++ b/tools/bpf/bpftool/main.c
@@ -34,6 +34,7 @@ bool use_loader;
 struct btf *base_btf;
 struct hashmap *refs_table;
 bool sign_progs;
+bool sign_maps;
 const char *private_key_path;
 const char *cert_path;
 
@@ -452,6 +453,7 @@ int main(int argc, char **argv)
 		{ "debug",	no_argument,	NULL,	'd' },
 		{ "use-loader",	no_argument,	NULL,	'L' },
 		{ "sign",	no_argument,	NULL,	'S' },
+		{ "sign-maps",	no_argument,	NULL,	'M' },
 		{ "base-btf",	required_argument, NULL, 'B' },
 		{ 0 }
 	};
@@ -478,7 +480,7 @@ int main(int argc, char **argv)
 	bin_name = "bpftool";
 
 	opterr = 0;
-	while ((opt = getopt_long(argc, argv, "VhpjfLmndSi:k:B:l",
+	while ((opt = getopt_long(argc, argv, "VhpjfLmndSMi:k:B:l",
 				  options, NULL)) >= 0) {
 		switch (opt) {
 		case 'V':
@@ -528,6 +530,11 @@ int main(int argc, char **argv)
 			sign_progs = true;
 			use_loader = true;
 			break;
+		case 'M':
+			sign_maps = true;
+			sign_progs = true;
+			use_loader = true;
+			break;
 		case 'k':
 			private_key_path = optarg;
 			break;
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 1130299cede0b..d4e8b39d97746 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -92,6 +92,7 @@ extern bool use_loader;
 extern struct btf *base_btf;
 extern struct hashmap *refs_table;
 extern bool sign_progs;
+extern bool sign_maps;
 extern const char *private_key_path;
 extern const char *cert_path;
 
diff --git a/tools/bpf/bpftool/sign.c b/tools/bpf/bpftool/sign.c
index b29d825bb1d41..50986c716292e 100644
--- a/tools/bpf/bpftool/sign.c
+++ b/tools/bpf/bpftool/sign.c
@@ -24,6 +24,7 @@
 #include <errno.h>
 
 #include <bpf/skel_internal.h>
+#include <bpf/libbpf_internal.h>
 
 #include "main.h"
 
@@ -131,8 +132,18 @@ int bpftool_prog_sign(struct bpf_load_and_run_opts *opts)
 	long actual_sig_len = 0;
 	X509 *x509 = NULL;
 	int err = 0;
-
-	bd_in = BIO_new_mem_buf(opts->insns, opts->insns_sz);
+	unsigned char hash[SHA256_DIGEST_LENGTH  * 2];
+	unsigned char term[SHA256_DIGEST_LENGTH];
+
+	if (sign_maps) {
+		libbpf_sha256(opts->insns, opts->insns_sz, hash, SHA256_DIGEST_LENGTH);
+		libbpf_sha256(opts->data, opts->data_sz, hash + SHA256_DIGEST_LENGTH,
+			      SHA256_DIGEST_LENGTH);
+		libbpf_sha256(hash, sizeof(hash), term, sizeof(term));
+		bd_in = BIO_new_mem_buf(term, sizeof(term));
+	} else {
+		bd_in = BIO_new_mem_buf(opts->insns, opts->insns_sz);
+	}
 	if (!bd_in) {
 		err = -ENOMEM;
 		goto cleanup;
@@ -173,7 +184,7 @@ int bpftool_prog_sign(struct bpf_load_and_run_opts *opts)
 	EVP_Digest(opts->insns, opts->insns_sz, opts->excl_prog_hash,
 		   &opts->excl_prog_hash_sz, EVP_sha256(), NULL);
 
-		bd_out = BIO_new(BIO_s_mem());
+	bd_out = BIO_new(BIO_s_mem());
 	if (!bd_out) {
 		err = -ENOMEM;
 		goto cleanup;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index ae83d8649ef1c..a436a2ff49437 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1621,6 +1621,12 @@ union bpf_attr {
 		 * verification.
 		 */
 		__s32		keyring_id;
+		/* Pointer to a buffer containing the maps used in the signature
+		 * hash chain of the BPF program.
+		 */
+		__aligned_u64   signature_maps;
+		/* Size of the signature maps buffer. */
+		__u32		signature_maps_size;
 	};
 
 	struct { /* anonymous struct used by BPF_OBJ_* commands */
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 5118d0a90e243..63946bdad41ad 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -1858,9 +1858,10 @@ struct gen_loader_opts {
 	__u32 data_sz;
 	__u32 insns_sz;
 	bool gen_hash;
+	bool sign_maps;
 };
 
-#define gen_loader_opts__last_field gen_hash
+#define gen_loader_opts__last_field sign_maps
 LIBBPF_API int bpf_object__gen_loader(struct bpf_object *obj,
 				      struct gen_loader_opts *opts);
 
diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
index 6a8f5c7a02eb9..11c2c19a5b2a4 100644
--- a/tools/lib/bpf/skel_internal.h
+++ b/tools/lib/bpf/skel_internal.h
@@ -74,6 +74,8 @@ struct bpf_load_and_run_opts {
 	__s32 keyring_id;
 	void *excl_prog_hash;
 	__u32 excl_prog_hash_sz;
+	const int *signature_maps;
+	__u32 signature_maps_sz;
 };
 
 long kern_sys_bpf(__u32 cmd, void *attr, __u32 attr_size);
@@ -352,7 +354,7 @@ static inline int skel_map_freeze(int fd)
 
 static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
 {
-	const size_t prog_load_attr_sz = offsetofend(union bpf_attr, keyring_id);
+	const size_t prog_load_attr_sz = offsetofend(union bpf_attr, signature_maps_size);
 	const size_t test_run_attr_sz = offsetofend(union bpf_attr, test);
 	int map_fd = -1, prog_fd = -1, key = 0, err;
 	union bpf_attr attr;
@@ -395,6 +397,8 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
 #ifndef __KERNEL__
 	attr.signature = (long) opts->signature;
 	attr.signature_size = opts->signature_sz;
+	attr.signature_maps = (long) opts->signature_maps;
+	attr.signature_maps_size = opts->signature_maps_sz;
 #else
 	if (opts->signature || opts->signature_sz)
 		pr_warn("signatures are not supported from bpf_preload\n");
-- 
2.48.1


^ permalink raw reply related

* [PATCH bpf-next 0/2] BPF signature hash chains
From: Blaise Boscaccy @ 2025-09-26 20:30 UTC (permalink / raw)
  To: bpf, linux-security-module, kpsingh, bboscaccy, paul, kys, ast,
	daniel, andrii, James.Bottomley, wufan

This patchset extends the currently proposed signature verification
patchset
https://lore.kernel.org/linux-security-module/20250813205526.2992911-1-kpsingh@kernel.org/
with hash-chain functionality to verify the contents of arbitrary maps.

The currently proposed loader + map signature verification
scheme—requested by Alexei and KP—is simple to implement and
acceptable if users/admins are satisfied with it. However, verifying
both the loader and the maps offers additional benefits beyond just
verifying the loader:

1. Simplified Loader Logic: The lskel loader becomes simpler since it
   doesn’t need to verify program maps—this is already handled by
   bpf_check_signature().

2. Security and Audit Integrity: A key advantage is that the LSM
  (Linux Security Module) hook for authorizing BPF program loads can
  operate after signature verification. This ensures:

  * Access control decisions can be based on verified signature status.
  * Accurate system state measurement and logging.
  * Log events claiming a verified signature are fully truthful,
    avoiding misleading entries that only the loader was verified
    while the actual BPF program verification happens later without
    logging.

This approach addresses concerns from users who require strict audit
trails and verification guarantees, especially in security-sensitive
environments.

A working tree with this patchset is being maintained at
https://github.com/blaiseboscaccy/linux/tree/bpf-hash-chains

bpf CI tests passed as well
https://github.com/kernel-patches/bpf/actions/runs/18021422444/


Blaise Boscaccy (2):
  bpf: Add hash chain signature support for arbitrary maps
  selftests/bpf: Enable map verification for some lskel tests

 include/uapi/linux/bpf.h                      |  6 ++
 kernel/bpf/syscall.c                          | 73 ++++++++++++++++++-
 .../bpf/bpftool/Documentation/bpftool-gen.rst |  7 +-
 tools/bpf/bpftool/gen.c                       | 27 ++++++-
 tools/bpf/bpftool/main.c                      |  9 ++-
 tools/bpf/bpftool/main.h                      |  1 +
 tools/bpf/bpftool/sign.c                      | 17 ++++-
 tools/include/uapi/linux/bpf.h                |  6 ++
 tools/lib/bpf/libbpf.h                        |  3 +-
 tools/lib/bpf/skel_internal.h                 |  6 +-
 tools/testing/selftests/bpf/Makefile          | 18 ++++-
 11 files changed, 159 insertions(+), 14 deletions(-)

-- 
2.48.1


^ permalink raw reply

* Re: [PATCH kvm-next V11 6/7] KVM: guest_memfd: Enforce NUMA mempolicy using shared policy
From: Sean Christopherson @ 2025-09-26 19:36 UTC (permalink / raw)
  To: Shivank Garg
  Cc: willy, akpm, david, pbonzini, shuah, vbabka, brauner, viro,
	dsterba, xiang, chao, jaegeuk, clm, josef, kent.overstreet,
	zbestahu, jefflexu, dhavale, lihongbo22, lorenzo.stoakes,
	Liam.Howlett, rppt, surenb, mhocko, ziy, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	tabba, ackerleytng, paul, jmorris, serge, pvorel, bfoster,
	vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
	yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
	jgg, kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes,
	roypat, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
	gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <aNVQJqYLX17v-fsf@google.com>

On Thu, Sep 25, 2025, Sean Christopherson wrote:
> On Wed, Aug 27, 2025, Shivank Garg wrote:
> > @@ -26,6 +28,9 @@ static inline struct kvm_gmem_inode_info *KVM_GMEM_I(struct inode *inode)
> >  	return container_of(inode, struct kvm_gmem_inode_info, vfs_inode);
> >  }
> >  
> > +static struct mempolicy *kvm_gmem_get_pgoff_policy(struct kvm_gmem_inode_info *info,
> > +						   pgoff_t index);
> > +
> >  /**
> >   * folio_file_pfn - like folio_file_page, but return a pfn.
> >   * @folio: The folio which contains this index.
> > @@ -112,7 +117,25 @@ static int kvm_gmem_prepare_folio(struct kvm *kvm, struct kvm_memory_slot *slot,
> >  static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index)
> >  {
> >  	/* TODO: Support huge pages. */
> > -	return filemap_grab_folio(inode->i_mapping, index);
> > +	struct mempolicy *policy;
> > +	struct folio *folio;
> > +
> > +	/*
> > +	 * Fast-path: See if folio is already present in mapping to avoid
> > +	 * policy_lookup.
> > +	 */
> > +	folio = __filemap_get_folio(inode->i_mapping, index,
> > +				    FGP_LOCK | FGP_ACCESSED, 0);
> > +	if (!IS_ERR(folio))
> > +		return folio;
> > +
> > +	policy = kvm_gmem_get_pgoff_policy(KVM_GMEM_I(inode), index);
> > +	folio = __filemap_get_folio_mpol(inode->i_mapping, index,
> > +					 FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
> > +					 mapping_gfp_mask(inode->i_mapping), policy);
> > +	mpol_cond_put(policy);
> > +
> > +	return folio;
> >  }
> >  
> >  static void kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start,
> > @@ -372,8 +395,45 @@ static vm_fault_t kvm_gmem_fault_user_mapping(struct vm_fault *vmf)
> >  	return ret;
> >  }
> >  
> > +#ifdef CONFIG_NUMA
> > +static int kvm_gmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
> > +{
> > +	struct inode *inode = file_inode(vma->vm_file);
> > +
> > +	return mpol_set_shared_policy(&KVM_GMEM_I(inode)->policy, vma, mpol);
> > +}
> > +
> > +static struct mempolicy *kvm_gmem_get_policy(struct vm_area_struct *vma,
> > +					     unsigned long addr, pgoff_t *pgoff)
> > +{
> > +	struct inode *inode = file_inode(vma->vm_file);
> > +
> > +	*pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);
> > +	return mpol_shared_policy_lookup(&KVM_GMEM_I(inode)->policy, *pgoff);
> > +}
> > +
> > +static struct mempolicy *kvm_gmem_get_pgoff_policy(struct kvm_gmem_inode_info *info,
> > +						   pgoff_t index)
> 
> I keep reading this is "page offset policy", as opposed to "policy given a page
> offset".  Another oddity that is confusing is that this helper explicitly does
> get_task_policy(current), while kvm_gmem_get_policy() lets the caller do that.
> The end result is the same, but I think it would be helpful for gmem to be
> internally consistent.
> 
> If we have kvm_gmem_get_policy() use this helper, then we can kill two birds with
> one stone:
> 
> static struct mempolicy *__kvm_gmem_get_policy(struct gmem_inode *gi,
> 					       pgoff_t index)
> {
> 	struct mempolicy *mpol;
> 
> 	mpol = mpol_shared_policy_lookup(&gi->policy, index);
> 	return mpol ? mpol : get_task_policy(current);
> }
> 
> static struct mempolicy *kvm_gmem_get_policy(struct vm_area_struct *vma,
> 					     unsigned long addr, pgoff_t *pgoff)
> {
> 	*pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);
> 
> 	return __kvm_gmem_get_policy(GMEM_I(file_inode(vma->vm_file)), *pgoff);

Argh!!!!!  This breaks the selftest because do_get_mempolicy() very specifically
falls back to the default_policy, NOT to the current task's policy.  That is
*exactly* the type of subtle detail that needs to be commented, because there's
no way some random KVM developer is going to know that returning NULL here is
important with respect to get_mempolicy() ABI.

On a happier note, I'm very glad you wrote a testcase :-)

I've got this as fixup-to-the-fixup:

diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index e796cc552a96..61130a52553f 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -114,8 +114,8 @@ static int kvm_gmem_prepare_folio(struct kvm *kvm, struct kvm_memory_slot *slot,
        return r;
 }
 
-static struct mempolicy *__kvm_gmem_get_policy(struct gmem_inode *gi,
-                                              pgoff_t index)
+static struct mempolicy *kvm_gmem_get_folio_policy(struct gmem_inode *gi,
+                                                  pgoff_t index)
 {
 #ifdef CONFIG_NUMA
        struct mempolicy *mpol;
@@ -151,7 +151,7 @@ static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index)
        if (!IS_ERR(folio))
                return folio;
 
-       policy = __kvm_gmem_get_policy(GMEM_I(inode), index);
+       policy = kvm_gmem_get_folio_policy(GMEM_I(inode), index);
        folio = __filemap_get_folio_mpol(inode->i_mapping, index,
                                         FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
                                         mapping_gfp_mask(inode->i_mapping), policy);
@@ -431,9 +431,18 @@ static int kvm_gmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpo
 static struct mempolicy *kvm_gmem_get_policy(struct vm_area_struct *vma,
                                              unsigned long addr, pgoff_t *pgoff)
 {
+       struct inode *inode = file_inode(vma->vm_file);
+
         *pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);
 
-        return __kvm_gmem_get_policy(GMEM_I(file_inode(vma->vm_file)), *pgoff);
+       /*
+        * Note!  Directly return whatever the lookup returns, do NOT return
+        * the current task's policy as is done when looking up the policy for
+        * a specific folio.  Kernel ABI for get_mempolicy() is to return
+        * MPOL_DEFAULT when there is no defined policy, not whatever the
+        * default policy resolves to.
+        */
+        return mpol_shared_policy_lookup(&GMEM_I(inode)->policy, *pgoff);
 }
 #endif /* CONFIG_NUMA */
 


^ permalink raw reply related

* Re: [PATCH kvm-next V11 7/7] KVM: guest_memfd: selftests: Add tests for mmap and NUMA policy support
From: Garg, Shivank @ 2025-09-26  7:37 UTC (permalink / raw)
  To: David Hildenbrand, Sean Christopherson
  Cc: willy, akpm, pbonzini, shuah, vbabka, brauner, viro, dsterba,
	xiang, chao, jaegeuk, clm, josef, kent.overstreet, zbestahu,
	jefflexu, dhavale, lihongbo22, lorenzo.stoakes, Liam.Howlett,
	rppt, surenb, mhocko, ziy, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, tabba,
	ackerleytng, paul, jmorris, serge, pvorel, bfoster, vannapurve,
	chao.gao, bharata, nikunj, michael.day, shdhiman, yan.y.zhao,
	Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik, jgg,
	kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes, roypat,
	chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra, gshan,
	jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <95ace421-36d2-48af-b527-7e799722eb17@redhat.com>



On 9/26/2025 1:01 PM, David Hildenbrand wrote:
> On 25.09.25 23:35, Sean Christopherson wrote:
>> On Wed, Aug 27, 2025, Shivank Garg wrote:
>>> Add tests for NUMA memory policy binding and NUMA aware allocation in
>>> guest_memfd. This extends the existing selftests by adding proper
>>> validation for:
>>> - KVM GMEM set_policy and get_policy() vm_ops functionality using
>>>    mbind() and get_mempolicy()
>>> - NUMA policy application before and after memory allocation
>>>
>>> These tests help ensure NUMA support for guest_memfd works correctly.
>>>
>>> Signed-off-by: Shivank Garg <shivankg@amd.com>
>>> ---
>>>   tools/testing/selftests/kvm/Makefile.kvm      |   1 +
>>>   .../testing/selftests/kvm/guest_memfd_test.c  | 121 ++++++++++++++++++
>>>   2 files changed, 122 insertions(+)
>>>
>>> diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
>>> index 90f03f00cb04..c46cef2a7cd7 100644
>>> --- a/tools/testing/selftests/kvm/Makefile.kvm
>>> +++ b/tools/testing/selftests/kvm/Makefile.kvm
>>> @@ -275,6 +275,7 @@ pgste-option = $(call try-run, echo 'int main(void) { return 0; }' | \
>>>       $(CC) -Werror -Wl$(comma)--s390-pgste -x c - -o "$$TMP",-Wl$(comma)--s390-pgste)
>>>     LDLIBS += -ldl
>>> +LDLIBS += -lnuma
>>
>> Hrm, this is going to be very annoying.  I don't have libnuma-dev installed on
>> any of my <too many> systems, and I doubt I'm alone.  Installing the package is
>> trivial, but I'm a little wary of foisting that requirement on all KVM developers
>> and build bots.
>>
>> I'd be especially curious what ARM and RISC-V think, as NUMA is likely a bit less
>> prevelant there.
> 
> We unconditionally use it in the mm tests for ksm and migration tests, so it's not particularly odd to require it here as well.
> 
> What we do with liburing in mm selftests is to detect presence at compile time and essentially make the tests behave differently based on availability (see check_config.sh).
> 

I have an alternative that drops libnuma entirely.
If this approach looks reasonable, could we potentially factor these out into a
common test utility for other selftests that currently depend on libnuma?

What are your thoughts on this?

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index c46cef2a7cd7..90f03f00cb04 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -275,7 +275,6 @@ pgste-option = $(call try-run, echo 'int main(void) { return 0; }' | \
 	$(CC) -Werror -Wl$(comma)--s390-pgste -x c - -o "$$TMP",-Wl$(comma)--s390-pgste)
 
 LDLIBS += -ldl
-LDLIBS += -lnuma
 LDFLAGS += -pthread $(no-pie-option) $(pgste-option)
 
 LIBKVM_C := $(filter %.c,$(LIBKVM))
diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
index 9640d04ec293..12ce91950c44 100644
--- a/tools/testing/selftests/kvm/guest_memfd_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_test.c
@@ -7,8 +7,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <numa.h>
-#include <numaif.h>
 #include <errno.h>
 #include <stdio.h>
 #include <fcntl.h>
@@ -75,9 +73,6 @@ static void test_mmap_supported(int fd, size_t page_size, size_t total_size)
 	TEST_ASSERT(!ret, "munmap() should succeed.");
 }
 
-#define TEST_REQUIRE_NUMA_MULTIPLE_NODES()	\
-	TEST_REQUIRE(numa_available() != -1 && numa_max_node() >= 1)
-
 static void test_mbind(int fd, size_t page_size, size_t total_size)
 {
 	unsigned long nodemask = 1; /* nid: 0 */
@@ -87,7 +82,8 @@ static void test_mbind(int fd, size_t page_size, size_t total_size)
 	char *mem;
 	int ret;
 
-	TEST_REQUIRE_NUMA_MULTIPLE_NODES();
+	if (!is_multi_numa_node_system())
+		return;
 
 	mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 	TEST_ASSERT(mem != MAP_FAILED, "mmap for mbind test should succeed");
@@ -136,7 +132,8 @@ static void test_numa_allocation(int fd, size_t page_size, size_t total_size)
 	char *mem;
 	int ret, i;
 
-	TEST_REQUIRE_NUMA_MULTIPLE_NODES();
+	if (!is_multi_numa_node_system())
+		return;
 
 	/* Clean slate: deallocate all file space, if any */
 	ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, total_size);
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 23a506d7eca3..ba4c316f4fef 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -12,6 +12,7 @@
 #include "linux/list.h"
 #include <linux/kernel.h>
 #include <linux/kvm.h>
+#include <linux/mempolicy.h>
 #include "linux/rbtree.h"
 #include <linux/types.h>
 
@@ -20,6 +21,7 @@
 
 #include <sys/eventfd.h>
 #include <sys/ioctl.h>
+#include <sys/syscall.h>
 
 #include <pthread.h>
 
@@ -633,6 +635,50 @@ static inline bool is_smt_on(void)
 	return false;
 }
 
+#include <dirent.h>
+static int numa_max_node(void)
+{
+	DIR *d;
+	struct dirent *de;
+	int max_node = 0;
+
+	d = opendir("/sys/devices/system/node");
+	if (!d) {
+		/* No NUMA support or no nodes found, assume single node */
+		return 0;
+	}
+
+	while ((de = readdir(d)) != NULL) {
+		int node_id;
+		char *endptr;
+
+		if (strncmp(de->d_name, "node", 4) != 0)
+			continue;
+
+		node_id = strtol(de->d_name + 4, &endptr, 10);
+		if (*endptr != '\0')
+			continue;
+
+		if (node_id > max_node)
+			max_node = node_id;
+	}
+	closedir(d);
+
+	return max_node;
+}
+
+static int numa_available(void)
+{
+	if (syscall(__NR_get_mempolicy, NULL, NULL, 0, 0, 0) < 0 && (errno == ENOSYS || errno == EPERM))
+		return -1;
+	return 0;
+}
+
+static inline bool is_multi_numa_node_system(void)
+{
+	return numa_available() != -1 && numa_max_node() >= 1;
+}
+
 void vm_create_irqchip(struct kvm_vm *vm);
 
 static inline int __vm_create_guest_memfd(struct kvm_vm *vm, uint64_t size,





^ permalink raw reply related

* Re: [PATCH kvm-next V11 7/7] KVM: guest_memfd: selftests: Add tests for mmap and NUMA policy support
From: David Hildenbrand @ 2025-09-26  7:32 UTC (permalink / raw)
  To: Jason Gunthorpe, Sean Christopherson
  Cc: Shivank Garg, willy, akpm, pbonzini, shuah, vbabka, brauner, viro,
	dsterba, xiang, chao, jaegeuk, clm, josef, kent.overstreet,
	zbestahu, jefflexu, dhavale, lihongbo22, lorenzo.stoakes,
	Liam.Howlett, rppt, surenb, mhocko, ziy, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	tabba, ackerleytng, paul, jmorris, serge, pvorel, bfoster,
	vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
	yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
	kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes, roypat,
	chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra, gshan,
	jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <20250925230420.GC2617119@nvidia.com>

On 26.09.25 01:04, Jason Gunthorpe wrote:
> On Thu, Sep 25, 2025 at 02:35:19PM -0700, Sean Christopherson wrote:
>>>   LDLIBS += -ldl
>>> +LDLIBS += -lnuma
>>
>> Hrm, this is going to be very annoying.  I don't have libnuma-dev installed on
>> any of my <too many> systems, and I doubt I'm alone.  Installing the package is
>> trivial, but I'm a little wary of foisting that requirement on all KVM developers
>> and build bots.
> 
> Wouldn't it be great if the kselftest build system used something like
> meson and could work around these little issues without breaking the
> whole build ? :(
> 
> Does anyone else think this?
> 
> Every time I try to build kselftsts I just ignore all the errors the
> fly by because the one bit I wanted did build properly anyhow.

When I'm in a hurry I even do the same within mm selftests.

-- 
Cheers

David / dhildenb


^ permalink raw reply

* Re: [PATCH kvm-next V11 7/7] KVM: guest_memfd: selftests: Add tests for mmap and NUMA policy support
From: David Hildenbrand @ 2025-09-26  7:31 UTC (permalink / raw)
  To: Sean Christopherson, Shivank Garg
  Cc: willy, akpm, pbonzini, shuah, vbabka, brauner, viro, dsterba,
	xiang, chao, jaegeuk, clm, josef, kent.overstreet, zbestahu,
	jefflexu, dhavale, lihongbo22, lorenzo.stoakes, Liam.Howlett,
	rppt, surenb, mhocko, ziy, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, tabba,
	ackerleytng, paul, jmorris, serge, pvorel, bfoster, vannapurve,
	chao.gao, bharata, nikunj, michael.day, shdhiman, yan.y.zhao,
	Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik, jgg,
	kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes, roypat,
	chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra, gshan,
	jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <aNW1l-Wdk6wrigM8@google.com>

On 25.09.25 23:35, Sean Christopherson wrote:
> On Wed, Aug 27, 2025, Shivank Garg wrote:
>> Add tests for NUMA memory policy binding and NUMA aware allocation in
>> guest_memfd. This extends the existing selftests by adding proper
>> validation for:
>> - KVM GMEM set_policy and get_policy() vm_ops functionality using
>>    mbind() and get_mempolicy()
>> - NUMA policy application before and after memory allocation
>>
>> These tests help ensure NUMA support for guest_memfd works correctly.
>>
>> Signed-off-by: Shivank Garg <shivankg@amd.com>
>> ---
>>   tools/testing/selftests/kvm/Makefile.kvm      |   1 +
>>   .../testing/selftests/kvm/guest_memfd_test.c  | 121 ++++++++++++++++++
>>   2 files changed, 122 insertions(+)
>>
>> diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
>> index 90f03f00cb04..c46cef2a7cd7 100644
>> --- a/tools/testing/selftests/kvm/Makefile.kvm
>> +++ b/tools/testing/selftests/kvm/Makefile.kvm
>> @@ -275,6 +275,7 @@ pgste-option = $(call try-run, echo 'int main(void) { return 0; }' | \
>>   	$(CC) -Werror -Wl$(comma)--s390-pgste -x c - -o "$$TMP",-Wl$(comma)--s390-pgste)
>>   
>>   LDLIBS += -ldl
>> +LDLIBS += -lnuma
> 
> Hrm, this is going to be very annoying.  I don't have libnuma-dev installed on
> any of my <too many> systems, and I doubt I'm alone.  Installing the package is
> trivial, but I'm a little wary of foisting that requirement on all KVM developers
> and build bots.
> 
> I'd be especially curious what ARM and RISC-V think, as NUMA is likely a bit less
> prevelant there.

We unconditionally use it in the mm tests for ksm and migration tests, 
so it's not particularly odd to require it here as well.

What we do with liburing in mm selftests is to detect presence at 
compile time and essentially make the tests behave differently based on 
availability (see check_config.sh).

-- 
Cheers

David / dhildenb


^ permalink raw reply

* Re: [PATCH kvm-next V11 7/7] KVM: guest_memfd: selftests: Add tests for mmap and NUMA policy support
From: Sean Christopherson @ 2025-09-25 23:12 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Shivank Garg, willy, akpm, david, pbonzini, shuah, vbabka,
	brauner, viro, dsterba, xiang, chao, jaegeuk, clm, josef,
	kent.overstreet, zbestahu, jefflexu, dhavale, lihongbo22,
	lorenzo.stoakes, Liam.Howlett, rppt, surenb, mhocko, ziy,
	matthew.brost, joshua.hahnjy, rakie.kim, byungchul, gourry,
	ying.huang, apopple, tabba, ackerleytng, paul, jmorris, serge,
	pvorel, bfoster, vannapurve, chao.gao, bharata, nikunj,
	michael.day, shdhiman, yan.y.zhao, Neeraj.Upadhyay,
	thomas.lendacky, michael.roth, aik, kalyazin, peterx, jack, hch,
	cgzones, ira.weiny, rientjes, roypat, chao.p.peng, amit, ddutile,
	dan.j.williams, ashish.kalra, gshan, jgowans, pankaj.gupta,
	papaluri, yuzhao, suzuki.poulose, quic_eberman, linux-bcachefs,
	linux-btrfs, linux-erofs, linux-f2fs-devel, linux-fsdevel,
	linux-mm, linux-kernel, linux-security-module, kvm,
	linux-kselftest, linux-coco
In-Reply-To: <20250925230420.GC2617119@nvidia.com>

On Thu, Sep 25, 2025, Jason Gunthorpe wrote:
> On Thu, Sep 25, 2025 at 02:35:19PM -0700, Sean Christopherson wrote:
> > >  LDLIBS += -ldl
> > > +LDLIBS += -lnuma
> > 
> > Hrm, this is going to be very annoying.  I don't have libnuma-dev installed on
> > any of my <too many> systems, and I doubt I'm alone.  Installing the package is
> > trivial, but I'm a little wary of foisting that requirement on all KVM developers
> > and build bots.
> 
> Wouldn't it be great if the kselftest build system used something like
> meson and could work around these little issues without breaking the
> whole build ? :(
> 
> Does anyone else think this?
> 
> Every time I try to build kselftsts I just ignore all the errors the
> fly by because the one bit I wanted did build properly anyhow.

I'm indifferent, as I literally never build all of kselftests, I just build KVM
selftests.  But I'm probably in the minority for the kernel overall.

^ permalink raw reply

* Re: [PATCH kvm-next V11 7/7] KVM: guest_memfd: selftests: Add tests for mmap and NUMA policy support
From: Jason Gunthorpe @ 2025-09-25 23:04 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Shivank Garg, willy, akpm, david, pbonzini, shuah, vbabka,
	brauner, viro, dsterba, xiang, chao, jaegeuk, clm, josef,
	kent.overstreet, zbestahu, jefflexu, dhavale, lihongbo22,
	lorenzo.stoakes, Liam.Howlett, rppt, surenb, mhocko, ziy,
	matthew.brost, joshua.hahnjy, rakie.kim, byungchul, gourry,
	ying.huang, apopple, tabba, ackerleytng, paul, jmorris, serge,
	pvorel, bfoster, vannapurve, chao.gao, bharata, nikunj,
	michael.day, shdhiman, yan.y.zhao, Neeraj.Upadhyay,
	thomas.lendacky, michael.roth, aik, kalyazin, peterx, jack, hch,
	cgzones, ira.weiny, rientjes, roypat, chao.p.peng, amit, ddutile,
	dan.j.williams, ashish.kalra, gshan, jgowans, pankaj.gupta,
	papaluri, yuzhao, suzuki.poulose, quic_eberman, linux-bcachefs,
	linux-btrfs, linux-erofs, linux-f2fs-devel, linux-fsdevel,
	linux-mm, linux-kernel, linux-security-module, kvm,
	linux-kselftest, linux-coco
In-Reply-To: <aNW1l-Wdk6wrigM8@google.com>

On Thu, Sep 25, 2025 at 02:35:19PM -0700, Sean Christopherson wrote:
> >  LDLIBS += -ldl
> > +LDLIBS += -lnuma
> 
> Hrm, this is going to be very annoying.  I don't have libnuma-dev installed on
> any of my <too many> systems, and I doubt I'm alone.  Installing the package is
> trivial, but I'm a little wary of foisting that requirement on all KVM developers
> and build bots.

Wouldn't it be great if the kselftest build system used something like
meson and could work around these little issues without breaking the
whole build ? :(

Does anyone else think this?

Every time I try to build kselftsts I just ignore all the errors the
fly by because the one bit I wanted did build properly anyhow.

Jason

^ permalink raw reply

* Re: [PATCH kvm-next V11 7/7] KVM: guest_memfd: selftests: Add tests for mmap and NUMA policy support
From: Sean Christopherson @ 2025-09-25 23:03 UTC (permalink / raw)
  To: Shivank Garg
  Cc: willy, akpm, david, pbonzini, shuah, vbabka, brauner, viro,
	dsterba, xiang, chao, jaegeuk, clm, josef, kent.overstreet,
	zbestahu, jefflexu, dhavale, lihongbo22, lorenzo.stoakes,
	Liam.Howlett, rppt, surenb, mhocko, ziy, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	tabba, ackerleytng, paul, jmorris, serge, pvorel, bfoster,
	vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
	yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
	jgg, kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes,
	roypat, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
	gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <aNW1l-Wdk6wrigM8@google.com>

On Thu, Sep 25, 2025, Sean Christopherson wrote:
> On Wed, Aug 27, 2025, Shivank Garg wrote:
> > Add tests for NUMA memory policy binding and NUMA aware allocation in
> > guest_memfd. This extends the existing selftests by adding proper
> > validation for:
> > - KVM GMEM set_policy and get_policy() vm_ops functionality using
> >   mbind() and get_mempolicy()
> > - NUMA policy application before and after memory allocation
> > 
> > These tests help ensure NUMA support for guest_memfd works correctly.
> > 
> > Signed-off-by: Shivank Garg <shivankg@amd.com>
> > ---
> >  tools/testing/selftests/kvm/Makefile.kvm      |   1 +
> >  .../testing/selftests/kvm/guest_memfd_test.c  | 121 ++++++++++++++++++
> >  2 files changed, 122 insertions(+)
> > 
> > diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
> > index 90f03f00cb04..c46cef2a7cd7 100644
> > --- a/tools/testing/selftests/kvm/Makefile.kvm
> > +++ b/tools/testing/selftests/kvm/Makefile.kvm
> > @@ -275,6 +275,7 @@ pgste-option = $(call try-run, echo 'int main(void) { return 0; }' | \
> >  	$(CC) -Werror -Wl$(comma)--s390-pgste -x c - -o "$$TMP",-Wl$(comma)--s390-pgste)
> >  
> >  LDLIBS += -ldl
> > +LDLIBS += -lnuma
> 
> Hrm, this is going to be very annoying.  I don't have libnuma-dev installed on
> any of my <too many> systems, and I doubt I'm alone.  Installing the package is
> trivial, but I'm a little wary of foisting that requirement on all KVM developers
> and build bots.
> 
> I'd be especially curious what ARM and RISC-V think, as NUMA is likely a bit less
> prevelant there.

Ugh, and it doesn't play nice with static linking.  I haven't tried running on a
NUMA system yet, so maybe it's benign?

/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/14/../../../x86_64-linux-gnu/libnuma.a(affinity.o): in function `affinity_ip':
(.text+0x629): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

^ permalink raw reply

* Re: [PATCH kvm-next V11 7/7] KVM: guest_memfd: selftests: Add tests for mmap and NUMA policy support
From: Sean Christopherson @ 2025-09-25 21:35 UTC (permalink / raw)
  To: Shivank Garg
  Cc: willy, akpm, david, pbonzini, shuah, vbabka, brauner, viro,
	dsterba, xiang, chao, jaegeuk, clm, josef, kent.overstreet,
	zbestahu, jefflexu, dhavale, lihongbo22, lorenzo.stoakes,
	Liam.Howlett, rppt, surenb, mhocko, ziy, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	tabba, ackerleytng, paul, jmorris, serge, pvorel, bfoster,
	vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
	yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
	jgg, kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes,
	roypat, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
	gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <20250827175247.83322-10-shivankg@amd.com>

On Wed, Aug 27, 2025, Shivank Garg wrote:
> Add tests for NUMA memory policy binding and NUMA aware allocation in
> guest_memfd. This extends the existing selftests by adding proper
> validation for:
> - KVM GMEM set_policy and get_policy() vm_ops functionality using
>   mbind() and get_mempolicy()
> - NUMA policy application before and after memory allocation
> 
> These tests help ensure NUMA support for guest_memfd works correctly.
> 
> Signed-off-by: Shivank Garg <shivankg@amd.com>
> ---
>  tools/testing/selftests/kvm/Makefile.kvm      |   1 +
>  .../testing/selftests/kvm/guest_memfd_test.c  | 121 ++++++++++++++++++
>  2 files changed, 122 insertions(+)
> 
> diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
> index 90f03f00cb04..c46cef2a7cd7 100644
> --- a/tools/testing/selftests/kvm/Makefile.kvm
> +++ b/tools/testing/selftests/kvm/Makefile.kvm
> @@ -275,6 +275,7 @@ pgste-option = $(call try-run, echo 'int main(void) { return 0; }' | \
>  	$(CC) -Werror -Wl$(comma)--s390-pgste -x c - -o "$$TMP",-Wl$(comma)--s390-pgste)
>  
>  LDLIBS += -ldl
> +LDLIBS += -lnuma

Hrm, this is going to be very annoying.  I don't have libnuma-dev installed on
any of my <too many> systems, and I doubt I'm alone.  Installing the package is
trivial, but I'm a little wary of foisting that requirement on all KVM developers
and build bots.

I'd be especially curious what ARM and RISC-V think, as NUMA is likely a bit less
prevelant there.

>  LDFLAGS += -pthread $(no-pie-option) $(pgste-option)
>  
>  LIBKVM_C := $(filter %.c,$(LIBKVM))
> diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
> index b3ca6737f304..9640d04ec293 100644
> --- a/tools/testing/selftests/kvm/guest_memfd_test.c
> +++ b/tools/testing/selftests/kvm/guest_memfd_test.c
> @@ -7,6 +7,8 @@
>  #include <stdlib.h>
>  #include <string.h>
>  #include <unistd.h>
> +#include <numa.h>
> +#include <numaif.h>
>  #include <errno.h>
>  #include <stdio.h>
>  #include <fcntl.h>
> @@ -19,6 +21,7 @@
>  #include <sys/mman.h>
>  #include <sys/types.h>
>  #include <sys/stat.h>
> +#include <sys/syscall.h>
>  
>  #include "kvm_util.h"
>  #include "test_util.h"
> @@ -72,6 +75,122 @@ static void test_mmap_supported(int fd, size_t page_size, size_t total_size)
>  	TEST_ASSERT(!ret, "munmap() should succeed.");
>  }
>  
> +#define TEST_REQUIRE_NUMA_MULTIPLE_NODES()	\
> +	TEST_REQUIRE(numa_available() != -1 && numa_max_node() >= 1)

Using TEST_REQUIRE() here will result in skipping the _entire_ test.  Ideally
this test would use fixtures so that each testcase can run in a child process
and thus can use TEST_REQUIRE(), but that's a conversion for another day.

Easiest thing would probably be to turn this into a common helper and then bail
early.

diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
index 9640d04ec293..6acb186e5300 100644
--- a/tools/testing/selftests/kvm/guest_memfd_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_test.c
@@ -7,7 +7,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <numa.h>
 #include <numaif.h>
 #include <errno.h>
 #include <stdio.h>
@@ -75,9 +74,6 @@ static void test_mmap_supported(int fd, size_t page_size, size_t total_size)
        TEST_ASSERT(!ret, "munmap() should succeed.");
 }
 
-#define TEST_REQUIRE_NUMA_MULTIPLE_NODES()     \
-       TEST_REQUIRE(numa_available() != -1 && numa_max_node() >= 1)
-
 static void test_mbind(int fd, size_t page_size, size_t total_size)
 {
        unsigned long nodemask = 1; /* nid: 0 */
@@ -87,7 +83,8 @@ static void test_mbind(int fd, size_t page_size, size_t total_size)
        char *mem;
        int ret;
 
-       TEST_REQUIRE_NUMA_MULTIPLE_NODES();
+       if (!is_multi_numa_node_system())
+               return;
 
        mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        TEST_ASSERT(mem != MAP_FAILED, "mmap for mbind test should succeed");
@@ -136,7 +133,8 @@ static void test_numa_allocation(int fd, size_t page_size, size_t total_size)
        char *mem;
        int ret, i;
 
-       TEST_REQUIRE_NUMA_MULTIPLE_NODES();
+       if (!is_multi_numa_node_system())
+               return;
 
        /* Clean slate: deallocate all file space, if any */
        ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, total_size);
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 23a506d7eca3..d7051607e6bf 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -21,6 +21,7 @@
 #include <sys/eventfd.h>
 #include <sys/ioctl.h>
 
+#include <numa.h>
 #include <pthread.h>
 
 #include "kvm_util_arch.h"
@@ -633,6 +634,11 @@ static inline bool is_smt_on(void)
        return false;
 }
 
+static inline bool is_multi_numa_node_system(void)
+{
+       return numa_available() != -1 && numa_max_node() >= 1;
+}
+
 void vm_create_irqchip(struct kvm_vm *vm);
 
 static inline int __vm_create_guest_memfd(struct kvm_vm *vm, uint64_t size,

^ permalink raw reply related

* Re: [bug report] [regression?] bpf lsm breaks /proc/*/attr/current with security= on commandline
From: Paul Moore @ 2025-09-25 19:07 UTC (permalink / raw)
  To: Filip Hejsek
  Cc: linux-security-module, James Morris, Serge E. Hallyn, bpf,
	linux-kernel, regressions
In-Reply-To: <9df66167c205e341bd5896376e06950aa7bd7240.camel@gmail.com>

On Thu, Sep 25, 2025 at 12:25 PM Filip Hejsek <filip.hejsek@gmail.com> wrote:
> On Thu, 2025-09-25 at 11:28 -0400, Paul Moore wrote:
> > On Thu, Sep 25, 2025 at 10:56 AM Filip Hejsek <filip.hejsek@gmail.com> wrote:
> > > On Wed, 2025-09-24 at 17:24 -0400, Paul Moore wrote:
> > > > On Sat, Sep 13, 2025 at 1:01 PM Filip Hejsek <filip.hejsek@gmail.com> wrote:
> > > > >
> > > > > Hello,
> > > > >
> > > > > TLDR: because of bpf lsm, putting security=selinux on commandline
> > > > >       results in /proc/*/attr/current returning errors.
> > > > >
> > > > > When the legacy security= commandline option is used, the specified lsm
> > > > > is added to the end of the lsm list. For example, security=apparmor
> > > > > results in the following order of security modules:
> > > > >
> > > > >    capability,landlock,lockdown,yama,bpf,apparmor
> > > > >
> > > > > In particular, the bpf lsm will be ordered before the chosen major lsm.
> > > > >
> > > > > This causes reads and writes of /proc/*/attr/current to fail, because
> > > > > the bpf hook overrides the apparmor/selinux hook.
> > > >
> > > > What kernel are you using?
> > >
> > > I'm using Arch Linux kernel, which is very close to mainline. I have
> > > also tested my own build from git sources (I used a stripped down
> > > config which I based on config from Arch). Example in QEMU:
> > >
> > > $ qemu-system-x86_64 -nodefaults -accel kvm -cpu host -smp cpus=2 -m 1G -display none -kernel ~/git/linux/arch/x86/boot/bzImage -initrd ./initramfs.img -serial mon:stdio -append 'console=ttyS0 security=selinux'
> > > :: mounting '' on real root
> > > mount: /new_root: no valid filesystem type specified.
> > > ERROR: Failed to mount '' on real root
> > > You are now being dropped into an emergency shell.
> > > sh: can't access tty; job control turned off
> > > [rootfs ~]# uname -a
> > > Linux archlinux 6.17.0-rc7-00020-gcec1e6e5d1ab #3 SMP PREEMPT_DYNAMIC Thu Sep 25 16:28:02 CEST 2025 x86_64 GNU/Linux
> > > [rootfs ~]# mount -t securityfs securityfs /sys/kernel/security
> > > [rootfs ~]# cat /proc/cmdline
> > > console=ttyS0 security=selinux
> > > [rootfs ~]# cat /sys/kernel/security/lsm; echo
> > > capability,landlock,lockdown,yama,bpf,selinux
> > > [rootfs ~]# cat /proc/self/attr/current
> > > cat: read error: Invalid argument
> > >
> > > (Note: In this example, uname reports archlinux, but that's only
> > > because I based the config on Arch config, it's not actually an Arch
> > > kernel.)
> > >
> > > Maybe the different behavior is caused by a different config? You can
> > > find the Arch config at [1]. Based on Fedora package sources, I think
> > > their config has
> > >
> > >    CONFIG_LSM="lockdown,yama,integrity,selinux,bpf,landlock,ipe"
> > >
> > > while the Arch config has
> > >
> > >    CONFIG_LSM="landlock,lockdown,yama,integrity,bpf"
> >
> > That's interesting, you're running a LSM that isn't normally run in
> > your distro and you're not properly initializing it (no policy load).
> > Both are acceptable, but you're definitely operating in the
> > corner-iest of corner cases ;)
> >
> > I'd have to look at the relevant code, but I suspect that with
> > "selinux" missing from the CONFIG_LSM list and you manually specifying
> > it on the kernel command line with "security=selinux" you are getting
> > it placed at the very end as opposed to what I saw (I have "selinux"
> > in my CONFIG_LSM list).  It's further complicated by the fact that the
> > procfs call into the LSM's security_getprocattr() hook is going to
> > pass a 0/zero into the hook as the @lsmid which means "first
> > available".
> >
> > Considering that the "security=" parameter is a legacy option, I'd
> > encourage you to try the "lsm=" parameter (make sure you specify the
> > full list of LSMs you want, in order) to see if that works.
>
> Yes, that works.
>
> The problem isn't that there wouldn't be any working configuration. The
> problem is that a userspace program (in my case CRIU) was broken and I
> had to spend time figuring out what the cause of the issue was. I'm not
> the only one who encountered this issue [1].

Arguably, when a Linux distro that is enabling new features, e.g.
multiple LSMs and/or the BPF LSM, they have an obligation to migrate
away from legacy/deprecated configuration knobs to properly use those
new features.

With the "security=" command line option only supporting one LSM, it's
going to be hard to do the right thing in all situations; someone is
always going to be upset with the placement in a multi-LSM system.
Perhaps it's time to make a push to properly deprecate and eventually
remove the "security=" command line option; it would definitely
simplify the kernel code.

> So in reporting this issue, I was just hoping to help future users
> avoid the same problem. If you think this is a waste of time, feel free
> to ignore this (and sorry I didn't make this clear in the first email).
>
> Lastly, I will offer a few thoughts:
>  * The fact that the security parameter can break programs like this is
>    highly non-obvious and undocumented.

https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html

I'll agree that the documentation probably should carry a stronger
warning, but it is marked as deprecated.

>  * The BPF LSM hook which causes this breakage is useless, because a
>    BPF program cannot be attached to it. I think it would make sense to
>    just remove it.

That would be a decision the BPF LSM maintainer would need to make.
There is precedent for doing things like this in the BPF LSM, and I
would tend to agree that this hook probably has little use for the
usual BPF LSMs.

>  * Switching to using /proc/*/attr/<lsm>/* solves the problem from the
>    userspace side. Unfortunately, selinux does not have its
>    subdirectory in attr.

This is a legacy carryover from the early days of the LSM framework
and SELinux.  By the time there was a need for LSM specific entries in
procfs there was already a significant amount of userspace that relied
on getting SELinux info from /proc/*/attr; migrating to
/proc/*/attr/selinux (or any other path for that matter) would have
broken too many things.

The good news is that there are a number of reasons why we want to get
away from using procfs for these things anyway, and we recently added
a few LSM syscalls to both solve the procfs problems and better
support multiple LSMs.  LWN.net wrote a nice article on the syscalls
which you can find at the link below:

* https://lwn.net/Articles/919059

-- 
paul-moore.com

^ permalink raw reply

* [PATCH v2 2/2] LSM: Infrastructure management of the mnt_opts security blob
From: Casey Schaufler @ 2025-09-25 17:12 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux
In-Reply-To: <20250925171208.5997-1-casey@schaufler-ca.com>

Move management of the mnt_opts->security blob out of the individual
security modules and into the security infrastructure.  The modules
tell the infrastructure how much space is required, and the space is
allocated as required in the interfaces that use the blob.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/security.c               | 42 +++++++++++++++++
 security/selinux/hooks.c          | 75 ++++++++++---------------------
 security/selinux/include/objsec.h |  8 ++++
 security/smack/smack.h            |  8 ++++
 security/smack/smack_lsm.c        | 44 +++++-------------
 5 files changed, 92 insertions(+), 85 deletions(-)

diff --git a/security/security.c b/security/security.c
index 8390410aec91..b16c0843dafa 100644
--- a/security/security.c
+++ b/security/security.c
@@ -29,6 +29,7 @@
 #include <linux/overflow.h>
 #include <linux/perf_event.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <net/flow.h>
 #include <net/sock.h>
 
@@ -1337,6 +1338,19 @@ void security_bprm_committed_creds(const struct linux_binprm *bprm)
 	call_void_hook(bprm_committed_creds, bprm);
 }
 
+/**
+ * lsm_mnt_opts_alloc - allocate a mnt_opts blob
+ * @opts: pointer to options
+ *
+ * Allocate a mount options blob.
+ *
+ * Returns 0, or -ENOMEM if memory isn't available.
+ */
+static int lsm_mnt_opts_alloc(void **opts)
+{
+	return lsm_blob_alloc(opts, blob_sizes.lbs_mnt_opts, GFP_KERNEL);
+}
+
 /**
  * security_fs_context_submount() - Initialise fc->security
  * @fc: new filesystem context
@@ -1348,6 +1362,13 @@ void security_bprm_committed_creds(const struct linux_binprm *bprm)
  */
 int security_fs_context_submount(struct fs_context *fc, struct super_block *reference)
 {
+	int rc;
+
+	if (!fc->security) {
+		rc = lsm_mnt_opts_alloc(&fc->security);
+		if (rc)
+			return rc;
+	}
 	return call_int_hook(fs_context_submount, fc, reference);
 }
 
@@ -1364,6 +1385,13 @@ int security_fs_context_submount(struct fs_context *fc, struct super_block *refe
  */
 int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
 {
+	int rc;
+
+	if (!fc->security) {
+		rc = lsm_mnt_opts_alloc(&fc->security);
+		if (rc)
+			return rc;
+	}
 	return call_int_hook(fs_context_dup, fc, src_fc);
 }
 
@@ -1386,6 +1414,12 @@ int security_fs_context_parse_param(struct fs_context *fc,
 	int trc;
 	int rc = -ENOPARAM;
 
+	if (!fc->security) {
+		trc = lsm_mnt_opts_alloc(&fc->security);
+		if (trc)
+			return trc;
+	}
+
 	lsm_for_each_hook(scall, fs_context_parse_param) {
 		trc = scall->hl->hook.fs_context_parse_param(fc, param);
 		if (trc == 0)
@@ -1455,6 +1489,7 @@ void security_free_mnt_opts(void **mnt_opts)
 	if (!*mnt_opts)
 		return;
 	call_void_hook(sb_free_mnt_opts, *mnt_opts);
+	kfree(*mnt_opts);
 	*mnt_opts = NULL;
 }
 EXPORT_SYMBOL(security_free_mnt_opts);
@@ -1470,6 +1505,13 @@ EXPORT_SYMBOL(security_free_mnt_opts);
  */
 int security_sb_eat_lsm_opts(char *options, void **mnt_opts)
 {
+	int rc;
+
+	if (!*mnt_opts) {
+		rc = lsm_mnt_opts_alloc(mnt_opts);
+		if (rc)
+			return rc;
+	}
 	return call_int_hook(sb_eat_lsm_opts, options, mnt_opts);
 }
 EXPORT_SYMBOL(security_sb_eat_lsm_opts);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4bba9d119713..1ccf880e4894 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -383,11 +383,6 @@ struct selinux_mnt_opts {
 	u32 defcontext_sid;
 };
 
-static void selinux_free_mnt_opts(void *mnt_opts)
-{
-	kfree(mnt_opts);
-}
-
 enum {
 	Opt_error = -1,
 	Opt_context = 0,
@@ -640,7 +635,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	const struct cred *cred = current_cred();
 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 	struct dentry *root = sb->s_root;
-	struct selinux_mnt_opts *opts = mnt_opts;
+	struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
 	struct inode_security_struct *root_isec;
 	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
 	u32 defcontext_sid = 0;
@@ -656,19 +651,13 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	mutex_lock(&sbsec->lock);
 
 	if (!selinux_initialized()) {
-		if (!opts) {
-			/* Defer initialization until selinux_complete_init,
-			   after the initial policy is loaded and the security
-			   server is ready to handle calls. */
-			if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
-				sbsec->flags |= SE_SBNATIVE;
-				*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
-			}
-			goto out;
+		/* Defer initialization until selinux_complete_init,
+		   after the initial policy is loaded and the security
+		   server is ready to handle calls. */
+		if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+			sbsec->flags |= SE_SBNATIVE;
+			*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
 		}
-		rc = -EINVAL;
-		pr_warn("SELinux: Unable to set superblock options "
-			"before the security server is initialized\n");
 		goto out;
 	}
 
@@ -1003,7 +992,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
  */
 static int selinux_add_opt(int token, const char *s, void **mnt_opts)
 {
-	struct selinux_mnt_opts *opts = *mnt_opts;
+	struct selinux_mnt_opts *opts = selinux_mnt_opts(*mnt_opts);
 	u32 *dst_sid;
 	int rc;
 
@@ -1012,19 +1001,14 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
 		return 0;
 	if (!s)
 		return -EINVAL;
+	if (!opts)
+		return 0;
 
 	if (!selinux_initialized()) {
 		pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
 		return -EINVAL;
 	}
 
-	if (!opts) {
-		opts = kzalloc(sizeof(*opts), GFP_KERNEL);
-		if (!opts)
-			return -ENOMEM;
-		*mnt_opts = opts;
-	}
-
 	switch (token) {
 	case Opt_context:
 		if (opts->context_sid || opts->defcontext_sid)
@@ -2620,17 +2604,14 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
 						*q++ = c;
 				}
 				arg = kmemdup_nul(arg, q - arg, GFP_KERNEL);
-				if (!arg) {
-					rc = -ENOMEM;
-					goto free_opt;
-				}
+				if (!arg)
+					return -ENOMEM;
 			}
 			rc = selinux_add_opt(token, arg, mnt_opts);
 			kfree(arg);
 			arg = NULL;
-			if (unlikely(rc)) {
-				goto free_opt;
-			}
+			if (unlikely(rc))
+				return rc;
 		} else {
 			if (!first) {	// copy with preceding comma
 				from--;
@@ -2647,18 +2628,11 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
 	}
 	*to = '\0';
 	return 0;
-
-free_opt:
-	if (*mnt_opts) {
-		selinux_free_mnt_opts(*mnt_opts);
-		*mnt_opts = NULL;
-	}
-	return rc;
 }
 
 static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
 {
-	struct selinux_mnt_opts *opts = mnt_opts;
+	struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
 	/*
@@ -2703,7 +2677,7 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
 
 static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
 {
-	struct selinux_mnt_opts *opts = mnt_opts;
+	struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
 	if (!(sbsec->flags & SE_SBINITIALIZED))
@@ -2800,14 +2774,10 @@ static int selinux_fs_context_submount(struct fs_context *fc,
 	const struct superblock_security_struct *sbsec = selinux_superblock(reference);
 	struct selinux_mnt_opts *opts;
 
-	/*
-	 * Ensure that fc->security remains NULL when no options are set
-	 * as expected by selinux_set_mnt_opts().
-	 */
 	if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
 		return 0;
 
-	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+	opts = selinux_mnt_opts(fc->security);
 	if (!opts)
 		return -ENOMEM;
 
@@ -2817,20 +2787,22 @@ static int selinux_fs_context_submount(struct fs_context *fc,
 		opts->context_sid = sbsec->mntpoint_sid;
 	if (sbsec->flags & DEFCONTEXT_MNT)
 		opts->defcontext_sid = sbsec->def_sid;
-	fc->security = opts;
 	return 0;
 }
 
 static int selinux_fs_context_dup(struct fs_context *fc,
 				  struct fs_context *src_fc)
 {
-	const struct selinux_mnt_opts *src = src_fc->security;
+	const struct selinux_mnt_opts *src = selinux_mnt_opts(src_fc->security);
+	struct selinux_mnt_opts *dst = selinux_mnt_opts(fc->security);
 
 	if (!src)
 		return 0;
+	if (!dst)
+		return 0;
 
-	fc->security = kmemdup(src, sizeof(*src), GFP_KERNEL);
-	return fc->security ? 0 : -ENOMEM;
+	*dst = *src;
+	return 0;
 }
 
 static const struct fs_parameter_spec selinux_fs_parameters[] = {
@@ -7337,7 +7309,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
 	LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
 	LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
 
-	LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
 	LSM_HOOK_INIT(sb_mnt_opts_compat, selinux_sb_mnt_opts_compat),
 	LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
 	LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 1d7ac59015a1..cefc6c550f74 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -245,4 +245,12 @@ selinux_perf_event(void *perf_event)
 	return perf_event + selinux_blob_sizes.lbs_perf_event;
 }
 
+static inline struct selinux_mnt_opts *selinux_mnt_opts(void *opts)
+{
+	if (!opts)
+		return NULL;
+
+	return opts + selinux_blob_sizes.lbs_mnt_opts;
+}
+
 #endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/smack/smack.h b/security/smack/smack.h
index bf6a6ed3946c..828c913dd62d 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -367,6 +367,14 @@ static inline struct socket_smack *smack_sock(const struct sock *sock)
 	return sock->sk_security + smack_blob_sizes.lbs_sock;
 }
 
+static inline struct smack_mnt_opts *smack_mnt_opts(void *opts)
+{
+	if (!opts)
+		return NULL;
+
+	return opts + smack_blob_sizes.lbs_mnt_opts;
+}
+
 #ifdef CONFIG_KEYS
 static inline struct smack_known **smack_key(const struct key *key)
 {
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1f236014e7d8..c83bb85ee1b5 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -551,22 +551,13 @@ struct smack_mnt_opts {
 	const char *fstransmute;
 };
 
-static void smack_free_mnt_opts(void *mnt_opts)
-{
-	kfree(mnt_opts);
-}
-
 static int smack_add_opt(int token, const char *s, void **mnt_opts)
 {
-	struct smack_mnt_opts *opts = *mnt_opts;
+	struct smack_mnt_opts *opts = smack_mnt_opts(*mnt_opts);
 	struct smack_known *skp;
 
-	if (!opts) {
-		opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
-		if (!opts)
-			return -ENOMEM;
-		*mnt_opts = opts;
-	}
+	if (!opts)
+		return -ENOMEM;
 	if (!s)
 		return -ENOMEM;
 
@@ -622,10 +613,9 @@ static int smack_fs_context_submount(struct fs_context *fc,
 	struct smack_mnt_opts *ctx;
 	struct inode_smack *isp;
 
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	ctx = smack_mnt_opts(fc->security);
 	if (!ctx)
 		return -ENOMEM;
-	fc->security = ctx;
 
 	sbsp = smack_superblock(reference);
 	isp = smack_inode(reference->s_root->d_inode);
@@ -668,22 +658,15 @@ static int smack_fs_context_submount(struct fs_context *fc,
 static int smack_fs_context_dup(struct fs_context *fc,
 				struct fs_context *src_fc)
 {
-	struct smack_mnt_opts *dst, *src = src_fc->security;
+	struct smack_mnt_opts *dst = smack_mnt_opts(fc->security);
+	struct smack_mnt_opts *src = smack_mnt_opts(src_fc->security);
 
 	if (!src)
 		return 0;
+	if (!dst)
+		return 0;
 
-	fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
-	if (!fc->security)
-		return -ENOMEM;
-
-	dst = fc->security;
-	dst->fsdefault = src->fsdefault;
-	dst->fsfloor = src->fsfloor;
-	dst->fshat = src->fshat;
-	dst->fsroot = src->fsroot;
-	dst->fstransmute = src->fstransmute;
-
+	*dst = *src;
 	return 0;
 }
 
@@ -741,12 +724,8 @@ static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts)
 			arg = kmemdup_nul(arg, from + len - arg, GFP_KERNEL);
 			rc = smack_add_opt(token, arg, mnt_opts);
 			kfree(arg);
-			if (unlikely(rc)) {
-				if (*mnt_opts)
-					smack_free_mnt_opts(*mnt_opts);
-				*mnt_opts = NULL;
+			if (unlikely(rc))
 				return rc;
-			}
 		} else {
 			if (!first) {	// copy with preceding comma
 				from--;
@@ -787,7 +766,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
 	struct superblock_smack *sp = smack_superblock(sb);
 	struct inode_smack *isp;
 	struct smack_known *skp;
-	struct smack_mnt_opts *opts = mnt_opts;
+	struct smack_mnt_opts *opts = smack_mnt_opts(mnt_opts);
 	bool transmute = false;
 
 	if (sp->smk_flags & SMK_SB_INITIALIZED)
@@ -5048,7 +5027,6 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
 	LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param),
 
 	LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
-	LSM_HOOK_INIT(sb_free_mnt_opts, smack_free_mnt_opts),
 	LSM_HOOK_INIT(sb_eat_lsm_opts, smack_sb_eat_lsm_opts),
 	LSM_HOOK_INIT(sb_statfs, smack_sb_statfs),
 	LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts),
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 1/2] LSM: Add mount opts blob size tracking
From: Casey Schaufler @ 2025-09-25 17:12 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux
In-Reply-To: <20250925171208.5997-1-casey@schaufler-ca.com>

Add mount option data to the blob size accounting in anticipation
of using a shared mnt_opts blob.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_hooks.h  | 1 +
 security/security.c        | 2 ++
 security/selinux/hooks.c   | 1 +
 security/smack/smack_lsm.c | 1 +
 4 files changed, 5 insertions(+)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 090d1d3e19fe..0de143d7c094 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -116,6 +116,7 @@ struct lsm_blob_sizes {
 	int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
 	int lbs_tun_dev;
 	int lbs_bdev;
+	int lbs_mnt_opts;
 };
 
 /*
diff --git a/security/security.c b/security/security.c
index ad163f06bf7a..8390410aec91 100644
--- a/security/security.c
+++ b/security/security.c
@@ -283,6 +283,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
 	lsm_set_blob_size(&needed->lbs_xattr_count,
 			  &blob_sizes.lbs_xattr_count);
 	lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
+	lsm_set_blob_size(&needed->lbs_mnt_opts, &blob_sizes.lbs_mnt_opts);
 }
 
 /* Prepare LSM for initialization. */
@@ -480,6 +481,7 @@ static void __init ordered_lsm_init(void)
 	init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
 	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
 	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
+	init_debug("mnt_opts blob size   = %d\n", blob_sizes.lbs_mnt_opts);
 
 	/*
 	 * Create any kmem_caches needed for blobs
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c95a5874bf7d..4bba9d119713 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7183,6 +7183,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
 	.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
 	.lbs_tun_dev = sizeof(struct tun_security_struct),
 	.lbs_ib = sizeof(struct ib_security_struct),
+	.lbs_mnt_opts = sizeof(struct selinux_mnt_opts),
 };
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index fc340a6f0dde..1f236014e7d8 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5030,6 +5030,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
 	.lbs_sock = sizeof(struct socket_smack),
 	.lbs_superblock = sizeof(struct superblock_smack),
 	.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
+	.lbs_mnt_opts = sizeof(struct smack_mnt_opts),
 };
 
 static const struct lsm_id smack_lsmid = {
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 0/2] LSM: Multiple LSM mount options
From: Casey Schaufler @ 2025-09-25 17:12 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux
In-Reply-To: <20250925171208.5997-1-casey.ref@schaufler-ca.com>

Linux Security Module (LSM) that support mount options, currently SELinux
and Smack, allocate their own data for those options. This patch set
moves the handling of mount option data out of the individual LSMs and
into the LSM infrastructure. This allows for multiple LSMs to support
mount options at the same time.

https://github.com/cschaufler/lsm-stacking#mount-opts-6.17-rc6-v2

v2: Significant rewrite to move allocations out of the LSMs.

Casey Schaufler (2):
  LSM: Add mount opts blob size tracking
  LSM: Infrastructure management of the mnt_opts security blob

 include/linux/lsm_hooks.h         |  1 +
 security/security.c               | 44 ++++++++++++++++++
 security/selinux/hooks.c          | 76 ++++++++++---------------------
 security/selinux/include/objsec.h |  8 ++++
 security/smack/smack.h            |  8 ++++
 security/smack/smack_lsm.c        | 45 +++++-------------
 6 files changed, 97 insertions(+), 85 deletions(-)

-- 
2.51.0


^ permalink raw reply

* Re: [bug report] [regression?] bpf lsm breaks /proc/*/attr/current with security= on commandline
From: Filip Hejsek @ 2025-09-25 16:25 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, James Morris, Serge E. Hallyn, bpf,
	linux-kernel, regressions
In-Reply-To: <CAHC9VhQ-c65UJS+dRaRFn_D=Sq++QXePTsCkN+cV5BVQEbf9fQ@mail.gmail.com>

On Thu, 2025-09-25 at 11:28 -0400, Paul Moore wrote:
> On Thu, Sep 25, 2025 at 10:56 AM Filip Hejsek <filip.hejsek@gmail.com> wrote:
> > On Wed, 2025-09-24 at 17:24 -0400, Paul Moore wrote:
> > > On Sat, Sep 13, 2025 at 1:01 PM Filip Hejsek <filip.hejsek@gmail.com> wrote:
> > > > 
> > > > Hello,
> > > > 
> > > > TLDR: because of bpf lsm, putting security=selinux on commandline
> > > >       results in /proc/*/attr/current returning errors.
> > > > 
> > > > When the legacy security= commandline option is used, the specified lsm
> > > > is added to the end of the lsm list. For example, security=apparmor
> > > > results in the following order of security modules:
> > > > 
> > > >    capability,landlock,lockdown,yama,bpf,apparmor
> > > > 
> > > > In particular, the bpf lsm will be ordered before the chosen major lsm.
> > > > 
> > > > This causes reads and writes of /proc/*/attr/current to fail, because
> > > > the bpf hook overrides the apparmor/selinux hook.
> > > 
> > > What kernel are you using?
> > 
> > I'm using Arch Linux kernel, which is very close to mainline. I have
> > also tested my own build from git sources (I used a stripped down
> > config which I based on config from Arch). Example in QEMU:
> > 
> > $ qemu-system-x86_64 -nodefaults -accel kvm -cpu host -smp cpus=2 -m 1G -display none -kernel ~/git/linux/arch/x86/boot/bzImage -initrd ./initramfs.img -serial mon:stdio -append 'console=ttyS0 security=selinux'
> > :: mounting '' on real root
> > mount: /new_root: no valid filesystem type specified.
> > ERROR: Failed to mount '' on real root
> > You are now being dropped into an emergency shell.
> > sh: can't access tty; job control turned off
> > [rootfs ~]# uname -a
> > Linux archlinux 6.17.0-rc7-00020-gcec1e6e5d1ab #3 SMP PREEMPT_DYNAMIC Thu Sep 25 16:28:02 CEST 2025 x86_64 GNU/Linux
> > [rootfs ~]# mount -t securityfs securityfs /sys/kernel/security
> > [rootfs ~]# cat /proc/cmdline
> > console=ttyS0 security=selinux
> > [rootfs ~]# cat /sys/kernel/security/lsm; echo
> > capability,landlock,lockdown,yama,bpf,selinux
> > [rootfs ~]# cat /proc/self/attr/current
> > cat: read error: Invalid argument
> > 
> > (Note: In this example, uname reports archlinux, but that's only
> > because I based the config on Arch config, it's not actually an Arch
> > kernel.)
> > 
> > Maybe the different behavior is caused by a different config? You can
> > find the Arch config at [1]. Based on Fedora package sources, I think
> > their config has
> > 
> >    CONFIG_LSM="lockdown,yama,integrity,selinux,bpf,landlock,ipe"
> > 
> > while the Arch config has
> > 
> >    CONFIG_LSM="landlock,lockdown,yama,integrity,bpf"
> 
> That's interesting, you're running a LSM that isn't normally run in
> your distro and you're not properly initializing it (no policy load).
> Both are acceptable, but you're definitely operating in the
> corner-iest of corner cases ;)
> 
> I'd have to look at the relevant code, but I suspect that with
> "selinux" missing from the CONFIG_LSM list and you manually specifying
> it on the kernel command line with "security=selinux" you are getting
> it placed at the very end as opposed to what I saw (I have "selinux"
> in my CONFIG_LSM list).  It's further complicated by the fact that the
> procfs call into the LSM's security_getprocattr() hook is going to
> pass a 0/zero into the hook as the @lsmid which means "first
> available".
> 
> Considering that the "security=" parameter is a legacy option, I'd
> encourage you to try the "lsm=" parameter (make sure you specify the
> full list of LSMs you want, in order) to see if that works.

Yes, that works.

The problem isn't that there wouldn't be any working configuration. The
problem is that a userspace program (in my case CRIU) was broken and I
had to spend time figuring out what the cause of the issue was. I'm not
the only one who encountered this issue [1]. I know that at least
Manjaro Linux used to ship a grub config with security=apparmor at some
point (and maybe still does). I no longer use Manjaro Linux, but I
still had this parameter left in my grub config.

[1]: https://github.com/checkpoint-restore/criu/issues/2033

So in reporting this issue, I was just hoping to help future users
avoid the same problem. If you think this is a waste of time, feel free
to ignore this (and sorry I didn't make this clear in the first email).

Lastly, I will offer a few thoughts:
 * The fact that the security parameter can break programs like this is
   highly non-obvious and undocumented.
 * The BPF LSM hook which causes this breakage is useless, because a
   BPF program cannot be attached to it. I think it would make sense to
   just remove it.
 * Switching to using /proc/*/attr/<lsm>/* solves the problem from the
   userspace side. Unfortunately, selinux does not have its
   subdirectory in attr.

Kind regards,
Filip Hejsek

^ permalink raw reply

* Re: [bug report] [regression?] bpf lsm breaks /proc/*/attr/current with security= on commandline
From: Paul Moore @ 2025-09-25 15:28 UTC (permalink / raw)
  To: Filip Hejsek
  Cc: linux-security-module, James Morris, Serge E. Hallyn, bpf,
	linux-kernel, regressions
In-Reply-To: <cd35aa283cf010188a3b0e318f2c16655224767c.camel@gmail.com>

On Thu, Sep 25, 2025 at 10:56 AM Filip Hejsek <filip.hejsek@gmail.com> wrote:
> On Wed, 2025-09-24 at 17:24 -0400, Paul Moore wrote:
> > On Sat, Sep 13, 2025 at 1:01 PM Filip Hejsek <filip.hejsek@gmail.com> wrote:
> > >
> > > Hello,
> > >
> > > TLDR: because of bpf lsm, putting security=selinux on commandline
> > >       results in /proc/*/attr/current returning errors.
> > >
> > > When the legacy security= commandline option is used, the specified lsm
> > > is added to the end of the lsm list. For example, security=apparmor
> > > results in the following order of security modules:
> > >
> > >    capability,landlock,lockdown,yama,bpf,apparmor
> > >
> > > In particular, the bpf lsm will be ordered before the chosen major lsm.
> > >
> > > This causes reads and writes of /proc/*/attr/current to fail, because
> > > the bpf hook overrides the apparmor/selinux hook.
> >
> > What kernel are you using?
>
> I'm using Arch Linux kernel, which is very close to mainline. I have
> also tested my own build from git sources (I used a stripped down
> config which I based on config from Arch). Example in QEMU:
>
> $ qemu-system-x86_64 -nodefaults -accel kvm -cpu host -smp cpus=2 -m 1G -display none -kernel ~/git/linux/arch/x86/boot/bzImage -initrd ./initramfs.img -serial mon:stdio -append 'console=ttyS0 security=selinux'
> :: mounting '' on real root
> mount: /new_root: no valid filesystem type specified.
> ERROR: Failed to mount '' on real root
> You are now being dropped into an emergency shell.
> sh: can't access tty; job control turned off
> [rootfs ~]# uname -a
> Linux archlinux 6.17.0-rc7-00020-gcec1e6e5d1ab #3 SMP PREEMPT_DYNAMIC Thu Sep 25 16:28:02 CEST 2025 x86_64 GNU/Linux
> [rootfs ~]# mount -t securityfs securityfs /sys/kernel/security
> [rootfs ~]# cat /proc/cmdline
> console=ttyS0 security=selinux
> [rootfs ~]# cat /sys/kernel/security/lsm; echo
> capability,landlock,lockdown,yama,bpf,selinux
> [rootfs ~]# cat /proc/self/attr/current
> cat: read error: Invalid argument
>
> (Note: In this example, uname reports archlinux, but that's only
> because I based the config on Arch config, it's not actually an Arch
> kernel.)
>
> Maybe the different behavior is caused by a different config? You can
> find the Arch config at [1]. Based on Fedora package sources, I think
> their config has
>
>    CONFIG_LSM="lockdown,yama,integrity,selinux,bpf,landlock,ipe"
>
> while the Arch config has
>
>    CONFIG_LSM="landlock,lockdown,yama,integrity,bpf"

That's interesting, you're running a LSM that isn't normally run in
your distro and you're not properly initializing it (no policy load).
Both are acceptable, but you're definitely operating in the
corner-iest of corner cases ;)

I'd have to look at the relevant code, but I suspect that with
"selinux" missing from the CONFIG_LSM list and you manually specifying
it on the kernel command line with "security=selinux" you are getting
it placed at the very end as opposed to what I saw (I have "selinux"
in my CONFIG_LSM list).  It's further complicated by the fact that the
procfs call into the LSM's security_getprocattr() hook is going to
pass a 0/zero into the hook as the @lsmid which means "first
available".

Considering that the "security=" parameter is a legacy option, I'd
encourage you to try the "lsm=" parameter (make sure you specify the
full list of LSMs you want, in order) to see if that works.  The
"security=" option predates both the concept of multiple simultaneous
LSMs as well as the uniqueness that is the BPF LSM.  Assuming that
"lsm=" works for you, and I would expect it to work, I think that is
the right solution here; new or unusual systems really shouldn't be
using "security=" at this point.

-- 
paul-moore.com

^ permalink raw reply

* Re: [PATCH kvm-next V11 4/7] KVM: guest_memfd: Use guest mem inodes instead of anonymous inodes
From: Sean Christopherson @ 2025-09-25 15:06 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: Shivank Garg, Ackerley Tng, willy, akpm, pbonzini, shuah, vbabka,
	brauner, viro, dsterba, xiang, chao, jaegeuk, clm, josef,
	kent.overstreet, zbestahu, jefflexu, dhavale, lihongbo22,
	lorenzo.stoakes, Liam.Howlett, rppt, surenb, mhocko, ziy,
	matthew.brost, joshua.hahnjy, rakie.kim, byungchul, gourry,
	ying.huang, apopple, tabba, paul, jmorris, serge, pvorel, bfoster,
	vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
	yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
	jgg, kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes,
	roypat, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
	gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <3a82a197-495f-40c3-ae1b-500453e3d1ec@redhat.com>

On Thu, Sep 25, 2025, David Hildenbrand wrote:
> On 25.09.25 15:41, Sean Christopherson wrote:
> > Regarding timing, how much do people care about getting this into 6.18 in
> > particular?
> 
> I think it will be beneficial if we start getting stuff upstream. But
> waiting a bit longer probably doesn't hurt.
> 
> > AFAICT, this hasn't gotten any coverage in -next, which makes me a
> > little nervous.
> 
> Right.
> 
> If we agree, then Shivank can just respin a new version after the merge
> window.

Actually, if Shivank is ok with it, I'd be happy to post the next version(s).
I'll be focusing on the in-place conversion support for the next 1-2 weeks, and
have some (half-baked) refactoring changes to better leverage the inode support
from this series.

I can also plop the first three patches (the non-KVM changes) in a topic branch
straightaway, but not feed it into -next until the merge window closes.  The 0-day
bots scrapes kvm-x86, so that'd get us some early build-bot exposure, and we can
stop bugging the non-KVM folks.  Then when the dust settles on the KVM changes,
I can throw them into the same topic branch.

^ permalink raw reply

* Re: [bug report] [regression?] bpf lsm breaks /proc/*/attr/current with security= on commandline
From: Filip Hejsek @ 2025-09-25 14:56 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, James Morris, Serge E. Hallyn, bpf,
	linux-kernel, regressions
In-Reply-To: <CAHC9VhRu=-J5xdKgYOJ1eqQ6EiMoEJ3M+cjDU8AHrts-=DoTvg@mail.gmail.com>

On Wed, 2025-09-24 at 17:24 -0400, Paul Moore wrote:
> On Sat, Sep 13, 2025 at 1:01 PM Filip Hejsek <filip.hejsek@gmail.com> wrote:
> > 
> > Hello,
> > 
> > TLDR: because of bpf lsm, putting security=selinux on commandline
> >       results in /proc/*/attr/current returning errors.
> > 
> > When the legacy security= commandline option is used, the specified lsm
> > is added to the end of the lsm list. For example, security=apparmor
> > results in the following order of security modules:
> > 
> >    capability,landlock,lockdown,yama,bpf,apparmor
> > 
> > In particular, the bpf lsm will be ordered before the chosen major lsm.
> > 
> > This causes reads and writes of /proc/*/attr/current to fail, because
> > the bpf hook overrides the apparmor/selinux hook.
> 
> What kernel are you using?

I'm using Arch Linux kernel, which is very close to mainline. I have
also tested my own build from git sources (I used a stripped down
config which I based on config from Arch). Example in QEMU:

$ qemu-system-x86_64 -nodefaults -accel kvm -cpu host -smp cpus=2 -m 1G -display none -kernel ~/git/linux/arch/x86/boot/bzImage -initrd ./initramfs.img -serial mon:stdio -append 'console=ttyS0 security=selinux'
:: mounting '' on real root
mount: /new_root: no valid filesystem type specified.
ERROR: Failed to mount '' on real root
You are now being dropped into an emergency shell.
sh: can't access tty; job control turned off
[rootfs ~]# uname -a
Linux archlinux 6.17.0-rc7-00020-gcec1e6e5d1ab #3 SMP PREEMPT_DYNAMIC Thu Sep 25 16:28:02 CEST 2025 x86_64 GNU/Linux
[rootfs ~]# mount -t securityfs securityfs /sys/kernel/security
[rootfs ~]# cat /proc/cmdline
console=ttyS0 security=selinux
[rootfs ~]# cat /sys/kernel/security/lsm; echo
capability,landlock,lockdown,yama,bpf,selinux
[rootfs ~]# cat /proc/self/attr/current
cat: read error: Invalid argument

(Note: In this example, uname reports archlinux, but that's only
because I based the config on Arch config, it's not actually an Arch
kernel.)

Maybe the different behavior is caused by a different config? You can
find the Arch config at [1]. Based on Fedora package sources, I think
their config has

   CONFIG_LSM="lockdown,yama,integrity,selinux,bpf,landlock,ipe"

while the Arch config has

   CONFIG_LSM="landlock,lockdown,yama,integrity,bpf"

.

[1]: https://gitlab.archlinux.org/archlinux/packaging/packages/linux/-/raw/main/config?ref_type=heads

>   Things appear to work correctly on my
> kernel that is tracking upstream (Fedora Rawhide + some unrelated
> bits):
> 
> % uname -a
> Linux dev-rawhide-1.lan 6.17.0-0.rc7.250923gd1ab3.57.1.secnext.fc44.x86_64 #1 SM
> P PREEMPT_DYNAMIC Tue Sep 23 10:07:14 EDT 2025 x86_64 GNU/Linux
> % cat /proc/cmdline
> BOOT_IMAGE=(hd0,gpt4)/boot/vmlinuz-6.17.0-0.rc7.250923gd1ab3.57.1.secnext.fc44.x
> 86_64 root=UUID=285029fa-4431-45e9-af1b-298ab0caf16a ro console=ttyS0 mitigation
> s=off security=selinux
> % cat /sys/kernel/security/lsm; echo ""
> lockdown,capability,yama,selinux,bpf,landlock,ipe,ima,evm
> % id -Z
> unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> % cat /proc/self/attr/current; echo ""
> unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> 
> I even ran it against the LSM initialization rework that has been
> proposed, but has not yet been accepted/merged, and that worked the
> same as above.
> 
> Is this a distro kernel with a lot of "special" patches which aren't
> present upstream?

^ permalink raw reply

* Re: [PATCH kvm-next V11 4/7] KVM: guest_memfd: Use guest mem inodes instead of anonymous inodes
From: David Hildenbrand @ 2025-09-25 14:26 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Shivank Garg, Ackerley Tng, willy, akpm, pbonzini, shuah, vbabka,
	brauner, viro, dsterba, xiang, chao, jaegeuk, clm, josef,
	kent.overstreet, zbestahu, jefflexu, dhavale, lihongbo22,
	lorenzo.stoakes, Liam.Howlett, rppt, surenb, mhocko, ziy,
	matthew.brost, joshua.hahnjy, rakie.kim, byungchul, gourry,
	ying.huang, apopple, tabba, paul, jmorris, serge, pvorel, bfoster,
	vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
	yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
	jgg, kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes,
	roypat, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
	gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <aNVFrZDAkHmgNNci@google.com>

On 25.09.25 15:41, Sean Christopherson wrote:
> On Thu, Sep 25, 2025, David Hildenbrand wrote:
>> On 25.09.25 13:44, Garg, Shivank wrote:
>>> On 9/25/2025 8:20 AM, Sean Christopherson wrote:
>>> I did functional testing and it works fine.
>>
>> I can queue this instead. I guess I can reuse the patch description and add
>> Sean as author + add his SOB (if he agrees).
> 
> Eh, Ackerley and Fuad did all the work.  If I had provided feedback earlier,
> this would have been handled in a new version.  If they are ok with the changes,
> I would prefer they remain co-authors.

Yeah, that's what I would have done.

> 
> Regarding timing, how much do people care about getting this into 6.18 in
> particular?

I think it will be beneficial if we start getting stuff upstream. But 
waiting a bit longer probably doesn't hurt.

> AFAICT, this hasn't gotten any coverage in -next, which makes me a
> little nervous.

Right.

If we agree, then Shivank can just respin a new version after the merge 
window.

-- 
Cheers

David / dhildenb


^ permalink raw reply

* Re: [PATCH kvm-next V11 6/7] KVM: guest_memfd: Enforce NUMA mempolicy using shared policy
From: Sean Christopherson @ 2025-09-25 14:22 UTC (permalink / raw)
  To: Shivank Garg
  Cc: willy, akpm, david, pbonzini, shuah, vbabka, brauner, viro,
	dsterba, xiang, chao, jaegeuk, clm, josef, kent.overstreet,
	zbestahu, jefflexu, dhavale, lihongbo22, lorenzo.stoakes,
	Liam.Howlett, rppt, surenb, mhocko, ziy, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	tabba, ackerleytng, paul, jmorris, serge, pvorel, bfoster,
	vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
	yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
	jgg, kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes,
	roypat, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
	gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <20250827175247.83322-9-shivankg@amd.com>

On Wed, Aug 27, 2025, Shivank Garg wrote:
> @@ -26,6 +28,9 @@ static inline struct kvm_gmem_inode_info *KVM_GMEM_I(struct inode *inode)
>  	return container_of(inode, struct kvm_gmem_inode_info, vfs_inode);
>  }
>  
> +static struct mempolicy *kvm_gmem_get_pgoff_policy(struct kvm_gmem_inode_info *info,
> +						   pgoff_t index);
> +
>  /**
>   * folio_file_pfn - like folio_file_page, but return a pfn.
>   * @folio: The folio which contains this index.
> @@ -112,7 +117,25 @@ static int kvm_gmem_prepare_folio(struct kvm *kvm, struct kvm_memory_slot *slot,
>  static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index)
>  {
>  	/* TODO: Support huge pages. */
> -	return filemap_grab_folio(inode->i_mapping, index);
> +	struct mempolicy *policy;
> +	struct folio *folio;
> +
> +	/*
> +	 * Fast-path: See if folio is already present in mapping to avoid
> +	 * policy_lookup.
> +	 */
> +	folio = __filemap_get_folio(inode->i_mapping, index,
> +				    FGP_LOCK | FGP_ACCESSED, 0);
> +	if (!IS_ERR(folio))
> +		return folio;
> +
> +	policy = kvm_gmem_get_pgoff_policy(KVM_GMEM_I(inode), index);
> +	folio = __filemap_get_folio_mpol(inode->i_mapping, index,
> +					 FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
> +					 mapping_gfp_mask(inode->i_mapping), policy);
> +	mpol_cond_put(policy);
> +
> +	return folio;
>  }
>  
>  static void kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start,
> @@ -372,8 +395,45 @@ static vm_fault_t kvm_gmem_fault_user_mapping(struct vm_fault *vmf)
>  	return ret;
>  }
>  
> +#ifdef CONFIG_NUMA
> +static int kvm_gmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
> +{
> +	struct inode *inode = file_inode(vma->vm_file);
> +
> +	return mpol_set_shared_policy(&KVM_GMEM_I(inode)->policy, vma, mpol);
> +}
> +
> +static struct mempolicy *kvm_gmem_get_policy(struct vm_area_struct *vma,
> +					     unsigned long addr, pgoff_t *pgoff)
> +{
> +	struct inode *inode = file_inode(vma->vm_file);
> +
> +	*pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);
> +	return mpol_shared_policy_lookup(&KVM_GMEM_I(inode)->policy, *pgoff);
> +}
> +
> +static struct mempolicy *kvm_gmem_get_pgoff_policy(struct kvm_gmem_inode_info *info,
> +						   pgoff_t index)

I keep reading this is "page offset policy", as opposed to "policy given a page
offset".  Another oddity that is confusing is that this helper explicitly does
get_task_policy(current), while kvm_gmem_get_policy() lets the caller do that.
The end result is the same, but I think it would be helpful for gmem to be
internally consistent.

If we have kvm_gmem_get_policy() use this helper, then we can kill two birds with
one stone:

static struct mempolicy *__kvm_gmem_get_policy(struct gmem_inode *gi,
					       pgoff_t index)
{
	struct mempolicy *mpol;

	mpol = mpol_shared_policy_lookup(&gi->policy, index);
	return mpol ? mpol : get_task_policy(current);
}

static struct mempolicy *kvm_gmem_get_policy(struct vm_area_struct *vma,
					     unsigned long addr, pgoff_t *pgoff)
{
	*pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);

	return __kvm_gmem_get_policy(GMEM_I(file_inode(vma->vm_file)), *pgoff);
}

^ permalink raw reply

* Re: [PATCH kvm-next V11 5/7] KVM: guest_memfd: Add slab-allocated inode cache
From: Sean Christopherson @ 2025-09-25 14:17 UTC (permalink / raw)
  To: Shivank Garg
  Cc: willy, akpm, david, pbonzini, shuah, vbabka, brauner, viro,
	dsterba, xiang, chao, jaegeuk, clm, josef, kent.overstreet,
	zbestahu, jefflexu, dhavale, lihongbo22, lorenzo.stoakes,
	Liam.Howlett, rppt, surenb, mhocko, ziy, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	tabba, ackerleytng, paul, jmorris, serge, pvorel, bfoster,
	vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
	yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
	jgg, kalyazin, peterx, jack, hch, cgzones, ira.weiny, rientjes,
	roypat, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
	gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
	quic_eberman, linux-bcachefs, linux-btrfs, linux-erofs,
	linux-f2fs-devel, linux-fsdevel, linux-mm, linux-kernel,
	linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <aNVMIRels8iCldOj@google.com>

On Thu, Sep 25, 2025, Sean Christopherson wrote:
> On Wed, Aug 27, 2025, Shivank Garg wrote:
> > Add dedicated inode structure (kvm_gmem_inode_info) and slab-allocated
> > inode cache for guest memory backing, similar to how shmem handles inodes.
> > 
> > This adds the necessary allocation/destruction functions and prepares
> > for upcoming guest_memfd NUMA policy support changes.
> > 
> > Signed-off-by: Shivank Garg <shivankg@amd.com>
> > ---
> >  virt/kvm/guest_memfd.c | 70 ++++++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 68 insertions(+), 2 deletions(-)
> > 
> > diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> > index 6c66a0974055..356947d36a47 100644
> > --- a/virt/kvm/guest_memfd.c
> > +++ b/virt/kvm/guest_memfd.c
> > @@ -17,6 +17,15 @@ struct kvm_gmem {
> >  	struct list_head entry;
> >  };
> >  
> > +struct kvm_gmem_inode_info {
> 
> What about naming this simply gmem_inode?

Heh, after looking through other filesystems, they're fairly even on appending
_info or not.  My vote is definitely for gmem_inode.

Before we accumulate more inode usage, e.g. for in-place conversion (which is
actually why I started looking at this code), I think we should also settle on
naming for gmem_file and gmem_inode variables.

As below, "struct kvm_gmem *gmem" gets quite confusing once inodes are in the
picture, especially since that structure isn't _the_ gmem instance, rather it's
a VM's view of that gmem instance.  And on the other side, "info" for the inode
is a bit imprecise, e.g. doesn't immediately make me think of inodes.

A few ideas:

 (a)
   struct gmem_inode *gmem;
   struct gmem_file *f;

 (b)
   struct gmem_inode *gi;
   struct gmem_file *f;

 (c)
   struct gmem_inode *gi;
   struct gmem_file *gf;

 (d)
   struct gmem_inode *gmem_i;
   struct gmem_file *gmem_f;


I think my would be for (a) or (b).  Option (c) seems like it would be hard to
visually differentiate between "gi" and "gf", and gmem_{i,f} are a bit verbose
IMO.

> > +	struct inode vfs_inode;
> > +};
> > +
> > +static inline struct kvm_gmem_inode_info *KVM_GMEM_I(struct inode *inode)
> 
> And then GMEM_I()?
> 
> And then (in a later follow-up if we target this for 6.18, or as a prep patch if
> we push this out to 6.19), rename kvm_gmem to gmem_file?
> 
> That would make guest_memfd look a bit more like other filesystems, and I don't
> see a need to preface the local structures and helpers with "kvm_", e.g. GMEM_I()
> is analogous to x86's to_vmx() and to_svm().
> 
> As for renaming kvm_gmem => gmem_file, I wandered back into this code via Ackerley's
> in-place conversion series, and it took me a good long while to remember the roles
> of files vs. inodes in gmem.  That's probably a sign that the code needs clarification
> given that I wrote the original code.  :-)
> 
> Leveraging an old discussion[*], my thought is to get to this:
> 
> /*
>  * A guest_memfd instance can be associated multiple VMs, each with its own
>  * "view" of the underlying physical memory.
>  *
>  * The gmem's inode is effectively the raw underlying physical storage, and is
>  * used to track properties of the physical memory, while each gmem file is
>  * effectively a single VM's view of that storage, and is used to track assets
>  * specific to its associated VM, e.g. memslots=>gmem bindings.
>  */
> struct gmem_file {
> 	struct kvm *kvm;
> 	struct xarray bindings;
> 	struct list_head entry;
> };
> 
> struct gmem_inode {
> 	struct shared_policy policy;
> 	struct inode vfs_inode;
> };
> 
> [*] https://lore.kernel.org/all/ZLGiEfJZTyl7M8mS@google.com

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox