* Re: [PATCH v5 18/23] bpf: Use vmalloc special flag
From: Edgecombe, Rick P @ 2025-08-12 18:49 UTC (permalink / raw)
To: glaubitz@physik.fu-berlin.de, peterz@infradead.org,
mingo@redhat.com, luto@kernel.org, bp@alien8.de
Cc: sam@gentoo.org, andreas@gaisler.com, nadav.amit@gmail.com,
anthony.yznaga@oracle.com, dave.hansen@linux.intel.com,
akpm@linux-foundation.org, linux-kernel@vger.kernel.org,
linux_dti@icloud.com, will.deacon@arm.com,
deneen.t.dock@intel.com, linux-mm@kvack.org, tglx@linutronix.de,
linux-security-module@vger.kernel.org, sparclinux@vger.kernel.org,
hpa@zytor.com, linux-integrity@vger.kernel.org,
daniel@iogearbox.net, kernel-hardening@lists.openwall.com,
ast@kernel.org, x86@kernel.org, kristen@linux.intel.com
In-Reply-To: <49b112b80b211ae05b5f3c36a55f67041783f51e.camel@physik.fu-berlin.de>
On Tue, 2025-08-12 at 20:37 +0200, John Paul Adrian Glaubitz wrote:
> That could be true. I knew about the patch in [1] but I didn't think of applying it.
>
> FWIW, the crashes we're seeing on recent kernel versions look like this:
>
> [ 40.992851] \|/ ____ \|/
> [ 40.992851] "@'/ .. \`@"
> [ 40.992851] /_| \__/ |_\
> [ 40.992851] \__U_/
> [ 41.186220] (udev-worker)(88): Kernel illegal instruction [#1]
Possibly re-using some stale TLB executable VA which's page now has other data
in it.
> [ 41.262910] CPU: 0 UID: 0 PID: 88 Comm: (udev-worker) Tainted: G W 6.12.0+ #25
> [ 41.376151] Tainted: [W]=WARN
> [ 41.415025] TSTATE: 0000004411001607 TPC: 00000000101c21c0 TNPC: 00000000101c21c4 Y: 00000000 Tainted: G W
> [ 41.563717] TPC: <ehci_init_driver+0x0/0x160 [ehci_hcd]>
> [ 41.633584] g0: 00000000012005b8 g1: 00000000100a1800 g2: 0000000010206000 g3: 00000000101de000
> [ 41.747962] g4: fff000000a5af380 g5: 0000000000000000 g6: fff000000aac8000 g7: 0000000000000e7b
> [ 41.862338] o0: 0000000010060118 o1: 000000001020a000 o2: fff000000aa30ce0 o3: 0000000000000e7a
> [ 41.976728] o4: 00000000ff000000 o5: 00ff000000000000 sp: fff000000aacb091 ret_pc: 00000000101de028
> [ 42.095768] RPC: <ehci_pci_init+0x28/0x2000 [ehci_pci]>
> [ 42.164394] l0: 0000000000000000 l1: 0000000100043fff l2: ffffffffff800000 l3: 0000000000800000
> [ 42.278768] l4: fff00000001c8008 l5: 0000000000000000 l6: 00000000013358e0 l7: 0000000001002800
> [ 42.393143] i0: ffffffffffffffed i1: 00000000004db8d8 i2: 0000000000000000 i3: fff000000aa304e0
> [ 42.507517] i4: 0000000001127250 i5: 0000000010060000 i6: fff000000aacb141 i7: 0000000000427d90
> [ 42.621893] I7: <do_one_initcall+0x30/0x200>
> [ 42.677931] Call Trace:
> [ 42.709953] [<0000000000427d90>] do_one_initcall+0x30/0x200
> [ 42.783158] [<00000000004db908>] do_init_module+0x48/0x240
> [ 42.855214] [<00000000004dd82c>] load_module+0x19cc/0x1f20
> [ 42.927270] [<00000000004ddf8c>] init_module_from_file+0x6c/0xa0
> [ 43.006189] [<00000000004de1e4>] sys_finit_module+0x1c4/0x2c0
> [ 43.081677] [<0000000000406174>] linux_sparc_syscall+0x34/0x44
> [ 43.158307] Disabling lock debugging due to kernel taint
> [ 43.228077] Caller[0000000000427d90]: do_one_initcall+0x30/0x200
> [ 43.306995] Caller[00000000004db908]: do_init_module+0x48/0x240
> [ 43.384772] Caller[00000000004dd82c]: load_module+0x19cc/0x1f20
> [ 43.462544] Caller[00000000004ddf8c]: init_module_from_file+0x6c/0xa0
> [ 43.547184] Caller[00000000004de1e4]: sys_finit_module+0x1c4/0x2c0
> [ 43.628389] Caller[0000000000406174]: linux_sparc_syscall+0x34/0x44
> [ 43.710741] Caller[fff000010480e2fc]: 0xfff000010480e2fc
> [ 43.780508] Instruction DUMP:
> [ 43.780511] 00000000
> [ 43.819394] 00000000
> [ 43.850273] 00000000
> [ 43.881153] <00000000>
> [ 43.912036] 00000000
> [ 43.942917] 00000000
> [ 43.973797] 00000000
> [ 44.004678] 00000000
> [ 44.035561] 00000000
> [ 44.066443]
>
> Do you have any suggestion what to bisect?
This does look like kernel range TLB flush related. Not sure how it's related to
userspace huge pages. Perhaps the userspace range TLB flush has issues to? Or
the TLB flush asm needs to be fixed in this another sparc variant?
So far two issues were found with that patch and they were both rare
architectures with broken kernel TLB flushes. Kernel TLB flushes can actually
not be required for a long time, so probably the bug normally looked like
unexplained crashes after days. The VM_FLUSH_RESET_PERMS just made them show up
earlier in a bisectable way.
^ permalink raw reply
* Re: [PATCH v5 18/23] bpf: Use vmalloc special flag
From: John Paul Adrian Glaubitz @ 2025-08-12 18:37 UTC (permalink / raw)
To: Edgecombe, Rick P, peterz@infradead.org, mingo@redhat.com,
luto@kernel.org, bp@alien8.de
Cc: sam@gentoo.org, andreas@gaisler.com, nadav.amit@gmail.com,
dave.hansen@linux.intel.com, anthony.yznaga@oracle.com,
akpm@linux-foundation.org, linux-kernel@vger.kernel.org,
will.deacon@arm.com, linux_dti@icloud.com,
deneen.t.dock@intel.com, linux-mm@kvack.org, tglx@linutronix.de,
linux-security-module@vger.kernel.org, sparclinux@vger.kernel.org,
hpa@zytor.com, linux-integrity@vger.kernel.org,
daniel@iogearbox.net, kernel-hardening@lists.openwall.com,
ast@kernel.org, x86@kernel.org, kristen@linux.intel.com
In-Reply-To: <1738e24239cc0c001245fdd4bd3811175c573ce2.camel@intel.com>
Hi,
On Tue, 2025-08-12 at 18:03 +0000, Edgecombe, Rick P wrote:
> On Tue, 2025-08-12 at 18:43 +0200, John Paul Adrian Glaubitz wrote:
> > I suspect that the main issue is to be found in the following patch which introduced VM_FLUSH_RESET_PERMS
> > which may not work as expected on sun4u SPARC systems:
>
> I think the problem we found with VM_FLUSH_RESET_PERMS was that the sparc64
> kernel TLB flush implementation was broken. Since VM_FLUSH_RESET_PERMS caused
> kernel TLB flushes to happen sooner, it just showed up sooner. [0]
>
> This other issue seems to be about userspace memory. So I wonder if these are
> two separate issues? Bisecting to the original VM_FLUSH_RESET_PERMS would have
> had the known sparc kernel range TLB flush issue. So to bisect the other issue
> you might need to apply this [1].
That could be true. I knew about the patch in [1] but I didn't think of applying it.
FWIW, the crashes we're seeing on recent kernel versions look like this:
[ 40.992851] \|/ ____ \|/
[ 40.992851] "@'/ .. \`@"
[ 40.992851] /_| \__/ |_\
[ 40.992851] \__U_/
[ 41.186220] (udev-worker)(88): Kernel illegal instruction [#1]
[ 41.262910] CPU: 0 UID: 0 PID: 88 Comm: (udev-worker) Tainted: G W 6.12.0+ #25
[ 41.376151] Tainted: [W]=WARN
[ 41.415025] TSTATE: 0000004411001607 TPC: 00000000101c21c0 TNPC: 00000000101c21c4 Y: 00000000 Tainted: G W
[ 41.563717] TPC: <ehci_init_driver+0x0/0x160 [ehci_hcd]>
[ 41.633584] g0: 00000000012005b8 g1: 00000000100a1800 g2: 0000000010206000 g3: 00000000101de000
[ 41.747962] g4: fff000000a5af380 g5: 0000000000000000 g6: fff000000aac8000 g7: 0000000000000e7b
[ 41.862338] o0: 0000000010060118 o1: 000000001020a000 o2: fff000000aa30ce0 o3: 0000000000000e7a
[ 41.976728] o4: 00000000ff000000 o5: 00ff000000000000 sp: fff000000aacb091 ret_pc: 00000000101de028
[ 42.095768] RPC: <ehci_pci_init+0x28/0x2000 [ehci_pci]>
[ 42.164394] l0: 0000000000000000 l1: 0000000100043fff l2: ffffffffff800000 l3: 0000000000800000
[ 42.278768] l4: fff00000001c8008 l5: 0000000000000000 l6: 00000000013358e0 l7: 0000000001002800
[ 42.393143] i0: ffffffffffffffed i1: 00000000004db8d8 i2: 0000000000000000 i3: fff000000aa304e0
[ 42.507517] i4: 0000000001127250 i5: 0000000010060000 i6: fff000000aacb141 i7: 0000000000427d90
[ 42.621893] I7: <do_one_initcall+0x30/0x200>
[ 42.677931] Call Trace:
[ 42.709953] [<0000000000427d90>] do_one_initcall+0x30/0x200
[ 42.783158] [<00000000004db908>] do_init_module+0x48/0x240
[ 42.855214] [<00000000004dd82c>] load_module+0x19cc/0x1f20
[ 42.927270] [<00000000004ddf8c>] init_module_from_file+0x6c/0xa0
[ 43.006189] [<00000000004de1e4>] sys_finit_module+0x1c4/0x2c0
[ 43.081677] [<0000000000406174>] linux_sparc_syscall+0x34/0x44
[ 43.158307] Disabling lock debugging due to kernel taint
[ 43.228077] Caller[0000000000427d90]: do_one_initcall+0x30/0x200
[ 43.306995] Caller[00000000004db908]: do_init_module+0x48/0x240
[ 43.384772] Caller[00000000004dd82c]: load_module+0x19cc/0x1f20
[ 43.462544] Caller[00000000004ddf8c]: init_module_from_file+0x6c/0xa0
[ 43.547184] Caller[00000000004de1e4]: sys_finit_module+0x1c4/0x2c0
[ 43.628389] Caller[0000000000406174]: linux_sparc_syscall+0x34/0x44
[ 43.710741] Caller[fff000010480e2fc]: 0xfff000010480e2fc
[ 43.780508] Instruction DUMP:
[ 43.780511] 00000000
[ 43.819394] 00000000
[ 43.850273] 00000000
[ 43.881153] <00000000>
[ 43.912036] 00000000
[ 43.942917] 00000000
[ 43.973797] 00000000
[ 44.004678] 00000000
[ 44.035561] 00000000
[ 44.066443]
Do you have any suggestion what to bisect?
Adrian
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer
`. `' Physicist
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
^ permalink raw reply
* Re: [PATCH v5 18/23] bpf: Use vmalloc special flag
From: Edgecombe, Rick P @ 2025-08-12 18:03 UTC (permalink / raw)
To: glaubitz@physik.fu-berlin.de, peterz@infradead.org,
mingo@redhat.com, luto@kernel.org, namit@vmware.com, bp@alien8.de
Cc: ard.biesheuvel@linaro.org, sam@gentoo.org, andreas@gaisler.com,
nadav.amit@gmail.com, dave.hansen@linux.intel.com,
anthony.yznaga@oracle.com, akpm@linux-foundation.org,
linux-kernel@vger.kernel.org, will.deacon@arm.com,
linux_dti@icloud.com, deneen.t.dock@intel.com, linux-mm@kvack.org,
tglx@linutronix.de, linux-security-module@vger.kernel.org,
sparclinux@vger.kernel.org, hpa@zytor.com,
linux-integrity@vger.kernel.org, daniel@iogearbox.net,
kernel-hardening@lists.openwall.com, ast@kernel.org,
x86@kernel.org, kristen@linux.intel.com
In-Reply-To: <14437e403ed8fceacafe0a89521d3b731211156e.camel@physik.fu-berlin.de>
On Tue, 2025-08-12 at 18:43 +0200, John Paul Adrian Glaubitz wrote:
> I suspect that the main issue is to be found in the following patch which introduced VM_FLUSH_RESET_PERMS
> which may not work as expected on sun4u SPARC systems:
I think the problem we found with VM_FLUSH_RESET_PERMS was that the sparc64
kernel TLB flush implementation was broken. Since VM_FLUSH_RESET_PERMS caused
kernel TLB flushes to happen sooner, it just showed up sooner. [0]
This other issue seems to be about userspace memory. So I wonder if these are
two separate issues? Bisecting to the original VM_FLUSH_RESET_PERMS would have
had the known sparc kernel range TLB flush issue. So to bisect the other issue
you might need to apply this [1].
[0] https://marc.info/?l=linux-sparc&m=155915694304118&w=2
[1] https://lore.kernel.org/all/57385AAB-C9A1-46AD-B743-445D4ECCA902@jrtc27.com/
^ permalink raw reply
* Re: [PATCH v5 18/23] bpf: Use vmalloc special flag
From: John Paul Adrian Glaubitz @ 2025-08-12 16:43 UTC (permalink / raw)
To: Nadav Amit, Peter Zijlstra, Borislav Petkov, Andy Lutomirski,
Ingo Molnar
Cc: linux-kernel, x86, hpa, Thomas Gleixner, Nadav Amit, Dave Hansen,
linux_dti, linux-integrity, linux-security-module, akpm,
kernel-hardening, linux-mm, will.deacon, ard.biesheuvel, kristen,
deneen.t.dock, Rick Edgecombe, Daniel Borkmann,
Alexei Starovoitov, sparclinux, Sam James, Andreas Larsson,
Anthony Yznaga
In-Reply-To: <20190426001143.4983-19-namit@vmware.com>
Hi,
On Thu, 2019-04-25 at 17:11 -0700, Nadav Amit wrote:
> From: Rick Edgecombe <rick.p.edgecombe@intel.com>
>
> Use new flag VM_FLUSH_RESET_PERMS for handling freeing of special
> permissioned memory in vmalloc and remove places where memory was set RW
> before freeing which is no longer needed. Don't track if the memory is RO
> anymore because it is now tracked in vmalloc.
>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
> ---
> include/linux/filter.h | 17 +++--------------
> kernel/bpf/core.c | 1 -
> 2 files changed, 3 insertions(+), 15 deletions(-)
>
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index 14ec3bdad9a9..7d3abde3f183 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -20,6 +20,7 @@
> #include <linux/set_memory.h>
> #include <linux/kallsyms.h>
> #include <linux/if_vlan.h>
> +#include <linux/vmalloc.h>
>
> #include <net/sch_generic.h>
>
> @@ -503,7 +504,6 @@ struct bpf_prog {
> u16 pages; /* Number of allocated pages */
> u16 jited:1, /* Is our filter JIT'ed? */
> jit_requested:1,/* archs need to JIT the prog */
> - undo_set_mem:1, /* Passed set_memory_ro() checkpoint */
> gpl_compatible:1, /* Is filter GPL compatible? */
> cb_access:1, /* Is control block accessed? */
> dst_needed:1, /* Do we need dst entry? */
> @@ -733,27 +733,17 @@ bpf_ctx_narrow_access_ok(u32 off, u32 size, u32 size_default)
>
> static inline void bpf_prog_lock_ro(struct bpf_prog *fp)
> {
> - fp->undo_set_mem = 1;
> + set_vm_flush_reset_perms(fp);
> set_memory_ro((unsigned long)fp, fp->pages);
> }
>
> -static inline void bpf_prog_unlock_ro(struct bpf_prog *fp)
> -{
> - if (fp->undo_set_mem)
> - set_memory_rw((unsigned long)fp, fp->pages);
> -}
> -
> static inline void bpf_jit_binary_lock_ro(struct bpf_binary_header *hdr)
> {
> + set_vm_flush_reset_perms(hdr);
> set_memory_ro((unsigned long)hdr, hdr->pages);
> set_memory_x((unsigned long)hdr, hdr->pages);
> }
>
> -static inline void bpf_jit_binary_unlock_ro(struct bpf_binary_header *hdr)
> -{
> - set_memory_rw((unsigned long)hdr, hdr->pages);
> -}
> -
> static inline struct bpf_binary_header *
> bpf_jit_binary_hdr(const struct bpf_prog *fp)
> {
> @@ -789,7 +779,6 @@ void __bpf_prog_free(struct bpf_prog *fp);
>
> static inline void bpf_prog_unlock_free(struct bpf_prog *fp)
> {
> - bpf_prog_unlock_ro(fp);
> __bpf_prog_free(fp);
> }
>
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index ff09d32a8a1b..c605397c79f0 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -848,7 +848,6 @@ void __weak bpf_jit_free(struct bpf_prog *fp)
> if (fp->jited) {
> struct bpf_binary_header *hdr = bpf_jit_binary_hdr(fp);
>
> - bpf_jit_binary_unlock_ro(hdr);
> bpf_jit_binary_free(hdr);
>
> WARN_ON_ONCE(!bpf_prog_kallsyms_verify_off(fp));
> --
> 2.17.1
>
>
> From mboxrd@z Thu Jan 1 00:00:00 1970
> From: Nadav Amit <namit@vmware.com>
> Subject: [PATCH v5 18/23] bpf: Use vmalloc special flag
> Date: Thu, 25 Apr 2019 17:11:38 -0700
> Message-ID: <20190426001143.4983-19-namit@vmware.com>
> In-Reply-To: <20190426001143.4983-1-namit@vmware.com>
> References: <20190426001143.4983-1-namit@vmware.com>
> MIME-Version: 1.0
> Content-Type: text/plain
> To: Peter Zijlstra <peterz@infradead.org>, Borislav Petkov <bp@alien8.de>, Andy Lutomirski <luto@kernel.org>, Ingo Molnar <mingo@redhat.com>
> Cc: linux-kernel@vger.kernel.org, x86@kernel.org, hpa@zytor.com, Thomas Gleixner <tglx@linutronix.de>, Nadav Amit <nadav.amit@gmail.com>, Dave Hansen <dave.hansen@linux.intel.com>, linux_dti@icloud.com, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, akpm@linux-foundation.org, kernel-hardening@lists.openwall.com, linux-mm@kvack.org, will.deacon@arm.com, ard.biesheuvel@linaro.org, kristen@linux.intel.com, deneen.t.dock@intel.com, Rick Edgecombe <rick.p.edgecombe@intel.com>, Daniel Borkmann <daniel@iogearbox.net>, Alexei Starovoitov <ast@kernel.org>
> List-ID: <kernel-hardening.lists.openwall.com>
>
> From: Rick Edgecombe <rick.p.edgecombe@intel.com>
>
> Use new flag VM_FLUSH_RESET_PERMS for handling freeing of special
> permissioned memory in vmalloc and remove places where memory was set RW
> before freeing which is no longer needed. Don't track if the memory is RO
> anymore because it is now tracked in vmalloc.
>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
> ---
> include/linux/filter.h | 17 +++--------------
> kernel/bpf/core.c | 1 -
> 2 files changed, 3 insertions(+), 15 deletions(-)
>
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index 14ec3bdad9a9..7d3abde3f183 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -20,6 +20,7 @@
> #include <linux/set_memory.h>
> #include <linux/kallsyms.h>
> #include <linux/if_vlan.h>
> +#include <linux/vmalloc.h>
>
> #include <net/sch_generic.h>
>
> @@ -503,7 +504,6 @@ struct bpf_prog {
> u16 pages; /* Number of allocated pages */
> u16 jited:1, /* Is our filter JIT'ed? */
> jit_requested:1,/* archs need to JIT the prog */
> - undo_set_mem:1, /* Passed set_memory_ro() checkpoint */
> gpl_compatible:1, /* Is filter GPL compatible? */
> cb_access:1, /* Is control block accessed? */
> dst_needed:1, /* Do we need dst entry? */
> @@ -733,27 +733,17 @@ bpf_ctx_narrow_access_ok(u32 off, u32 size, u32 size_default)
>
> static inline void bpf_prog_lock_ro(struct bpf_prog *fp)
> {
> - fp->undo_set_mem = 1;
> + set_vm_flush_reset_perms(fp);
> set_memory_ro((unsigned long)fp, fp->pages);
> }
>
> -static inline void bpf_prog_unlock_ro(struct bpf_prog *fp)
> -{
> - if (fp->undo_set_mem)
> - set_memory_rw((unsigned long)fp, fp->pages);
> -}
> -
> static inline void bpf_jit_binary_lock_ro(struct bpf_binary_header *hdr)
> {
> + set_vm_flush_reset_perms(hdr);
> set_memory_ro((unsigned long)hdr, hdr->pages);
> set_memory_x((unsigned long)hdr, hdr->pages);
> }
>
> -static inline void bpf_jit_binary_unlock_ro(struct bpf_binary_header *hdr)
> -{
> - set_memory_rw((unsigned long)hdr, hdr->pages);
> -}
> -
> static inline struct bpf_binary_header *
> bpf_jit_binary_hdr(const struct bpf_prog *fp)
> {
> @@ -789,7 +779,6 @@ void __bpf_prog_free(struct bpf_prog *fp);
>
> static inline void bpf_prog_unlock_free(struct bpf_prog *fp)
> {
> - bpf_prog_unlock_ro(fp);
> __bpf_prog_free(fp);
> }
>
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index ff09d32a8a1b..c605397c79f0 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -848,7 +848,6 @@ void __weak bpf_jit_free(struct bpf_prog *fp)
> if (fp->jited) {
> struct bpf_binary_header *hdr = bpf_jit_binary_hdr(fp);
>
> - bpf_jit_binary_unlock_ro(hdr);
> bpf_jit_binary_free(hdr);
>
> WARN_ON_ONCE(!bpf_prog_kallsyms_verify_off(fp));
There are issues with the TLB management on sparc64 (primarily sun4u) that were introduced
by this patch. A typical backtrace after a crash looks like this:
[ 122.085803] Unable to handle kernel NULL pointer dereference
[ 122.160227] tsk->{mm,active_mm}->context = 000000000000009d
[ 122.233502] tsk->{mm,active_mm}->pgd = fff0000231d14000
[ 122.302118] \|/ ____ \|/
[ 122.302118] "@'/ .. \`@"
[ 122.302118] /_| \__/ |_\
[ 122.302118] \__U_/
[ 122.495420] systemd(1): Oops [#1]
[ 122.538874] CPU: 0 PID: 1 Comm: systemd Not tainted 5.2.0-3-sparc64 #1 Debian 5.2.17-1
[ 122.642957] TSTATE: 0000004411001601 TPC: 000000000061cd94 TNPC: 000000000061cd98 Y: 00000000 Not tainted
[ 122.772207] TPC: <vfs_getattr_nosec+0x34/0xc0>
[ 122.830529] g0: 0000000000000000 g1: 00000000000007ff g2: 0000000000000000 g3: 00000000000007df
[ 122.944902] g4: fff00002381771c0 g5: 0000000000000003 g6: fff0000238178000 g7: 0000000000000000
[ 123.059275] o0: fff000023817be18 o1: 0000000000000000 o2: 0000000000000000 o3: fff000023817be18
[ 123.173658] o4: 0000000000000000 o5: 0000000000000000 sp: fff000023817b341 ret_pc: 000000000061cd7c
[ 123.292611] RPC: <vfs_getattr_nosec+0x1c/0xc0>
[ 123.350933] l0: 0000010000204010 l1: fff0000101600e28 l2: e4e45b5b8ae44628 l3: 0000000000000000
[ 123.465311] l4: 0000000000000000 l5: 0000000000000000 l6: 0000000000000000 l7: fff0000100bff140
[ 123.579692] i0: fff000023817bd50 i1: fff000023817be18 i2: 0000000000000001 i3: 0000000000000900
[ 123.694060] i4: 0000000000000000 i5: fff00002320c1210 i6: fff000023817b3f1 i7: 000000000061ce48
[ 123.808439] I7: <vfs_getattr+0x28/0x40>
[ 123.858759] Call Trace:
[ 123.890785] [000000000061ce48] vfs_getattr+0x28/0x40
[ 123.957123] [000000000061cf64] vfs_statx+0x84/0xc0
[ 124.021173] [000000000061d918] sys_statx+0x38/0x60
[ 124.085226] [0000000000406154] linux_sparc_syscall+0x34/0x44
[ 124.160708] Disabling lock debugging due to kernel taint
[ 124.230481] Caller[000000000061ce48]: vfs_getattr+0x28/0x40
[ 124.303680] Caller[000000000061cf64]: vfs_statx+0x84/0xc0
[ 124.374593] Caller[000000000061d918]: sys_statx+0x38/0x60
[ 124.445503] Caller[0000000000406154]: linux_sparc_syscall+0x34/0x44
[ 124.527857] Caller[fff00001013fde40]: 0xfff00001013fde40
[ 124.597621] Instruction DUMP:
[ 124.597623] c2264000
[ 124.636505] 861027df
[ 124.667386] c45f6028
[ 124.698267] <c458a050>
[ 124.729148] 8408a401
[ 124.760031] 83789403
[ 124.790910] c2264000
[ 124.821801] c207600c
[ 124.852675] 80886800
[ 124.883556]
[ 124.954015] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000009
[ 125.054721] Press Stop-A (L1-A) from sun keyboard or send break
[ 125.054721] twice on console to return to the boot prom
[ 125.201103] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000009 ]---
I suspect that the main issue is to be found in the following patch which introduced VM_FLUSH_RESET_PERMS
which may not work as expected on sun4u SPARC systems:
commit 868b104d7379e28013e9d48bdd2db25e0bdcf751
Author: Rick Edgecombe <rick.p.edgecombe@intel.com>
Date: Thu Apr 25 17:11:36 2019 -0700
mm/vmalloc: Add flag for freeing of special permsissions
Add a new flag VM_FLUSH_RESET_PERMS, for enabling vfree operations to
immediately clear executable TLB entries before freeing pages, and handle
resetting permissions on the directmap. This flag is useful for any kind
of memory with elevated permissions, or where there can be related
permissions changes on the directmap. Today this is RO+X and RO memory.
Although this enables directly vfreeing non-writeable memory now,
non-writable memory cannot be freed in an interrupt because the allocation
itself is used as a node on deferred free list. So when RO memory needs to
be freed in an interrupt the code doing the vfree needs to have its own
work queue, as was the case before the deferred vfree list was added to
vmalloc.
For architectures with set_direct_map_ implementations this whole operation
can be done with one TLB flush when centralized like this. For others with
directmap permissions, currently only arm64, a backup method using
set_memory functions is used to reset the directmap. When arm64 adds
set_direct_map_ functions, this backup can be removed.
When the TLB is flushed to both remove TLB entries for the vmalloc range
mapping and the direct map permissions, the lazy purge operation could be
done to try to save a TLB flush later. However today vm_unmap_aliases
could flush a TLB range that does not include the directmap. So a helper
is added with extra parameters that can allow both the vmalloc address and
the direct mapping to be flushed during this operation. The behavior of the
normal vm_unmap_aliases function is unchanged.
Suggested-by: Dave Hansen <dave.hansen@intel.com>
Suggested-by: Andy Lutomirski <luto@kernel.org>
Suggested-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: <akpm@linux-foundation.org>
Cc: <ard.biesheuvel@linaro.org>
Cc: <deneen.t.dock@intel.com>
Cc: <kernel-hardening@lists.openwall.com>
Cc: <kristen@linux.intel.com>
Cc: <linux_dti@icloud.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nadav Amit <nadav.amit@gmail.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: https://lkml.kernel.org/r/20190426001143.4983-17-namit@vmware.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
The crash will always happen when support for transparent huge pages is enabled (CONFIG_TRANSPARENT_HUGEPAGE=y
and CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y) and in particular on sun4u machines (but not so much the more modern
sun4v machines although I cannot rule out that the crashes sometimes happening on these machines is related
to this bug).
With THP enabled, the crash can be delayed by either reverting d563d678aa0b or, for example, by this crude hack:
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 6dbcdceecae1..128118593b48 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2948,8 +2948,8 @@ static void _vm_unmap_aliases(unsigned long start, unsigned long end, int flush)
}
free_purged_blocks(&purge_list);
- if (!__purge_vmap_area_lazy(start, end, false) && flush)
- flush_tlb_kernel_range(start, end);
+ // if (!__purge_vmap_area_lazy(start, end, false) && flush)
+ // flush_tlb_kernel_range(start, end);
mutex_unlock(&vmap_purge_lock);
}
Please see also the discussion in [1].
Thanks,
Adrian
> [1] https://lore.kernel.org/all/35f5ec4eda8a7dbeeb7df9ec0be5c0b062c509f7.camel@physik.fu-berlin.de/
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer
`. `' Physicist
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
^ permalink raw reply related
* Re: [PATCH v2 02/13] bpf: Implement exclusive map creation
From: KP Singh @ 2025-08-11 22:48 UTC (permalink / raw)
To: Fan Wu
Cc: bpf, linux-security-module, bboscaccy, paul, kys, ast, daniel,
andrii
In-Reply-To: <CAKtyLkGOBMBF_d1=qUTa=Fxj5HE6_GRWaE6tVgxyEe3WP1oNPg@mail.gmail.com>
On Wed, Jul 30, 2025 at 12:59 AM Fan Wu <wufan@kernel.org> wrote:
>
> On Mon, Jul 21, 2025 at 2:35 PM KP Singh <kpsingh@kernel.org> wrote:
> >
> > Exclusive maps allow maps to only be accessed by program with a
> > program with a matching hash which is specified in the excl_prog_hash
> > attr.
> >
> > For the signing use-case, this allows the trusted loader program
> > to load the map and verify the integrity
> >
> > Signed-off-by: KP Singh <kpsingh@kernel.org>
> > ---
> > include/linux/bpf.h | 1 +
> > include/uapi/linux/bpf.h | 2 ++
> > kernel/bpf/syscall.c | 32 ++++++++++++++++++++++++++++----
> > kernel/bpf/verifier.c | 6 ++++++
> > tools/include/uapi/linux/bpf.h | 2 ++
> > 5 files changed, 39 insertions(+), 4 deletions(-)
> >
>
> ...
>
> > -static int map_create(union bpf_attr *attr, bool kernel)
> > +static int map_create(union bpf_attr *attr, bpfptr_t uattr)
> > {
> > const struct bpf_map_ops *ops;
> > struct bpf_token *token = NULL;
> > @@ -1527,7 +1528,30 @@ static int map_create(union bpf_attr *attr, bool kernel)
> > attr->btf_vmlinux_value_type_id;
> > }
> >
> > - err = security_bpf_map_create(map, attr, token, kernel);
> > + if (attr->excl_prog_hash) {
> > + bpfptr_t uprog_hash = make_bpfptr(attr->excl_prog_hash, uattr.is_kernel);
> > +
> > + map->excl_prog_sha = kzalloc(SHA256_DIGEST_SIZE, GFP_KERNEL);
> > + if (!map->excl_prog_sha) {
> > + err = -ENOMEM;
> > + goto free_map;
> > + }
> > +
> > + if (attr->excl_prog_hash_size != SHA256_DIGEST_SIZE) {
> > + err = -EINVAL;
> > + goto free_map;
> > + }
>
> Nit: Maybe check the size first to avoid unncessary kzalloc?
Thanks, fixed.
- KP
>
> -Fan
>
> > +
> > + if (copy_from_bpfptr(map->excl_prog_sha, uprog_hash,
> > + SHA256_DIGEST_SIZE)) {
> > + err = -EFAULT;
> > + goto free_map;
> > + }
> > + } else if (attr->excl_prog_hash_size) {
> > + return -EINVAL;
> > + }
> > +
> > + err = security_bpf_map_create(map, attr, token, uattr.is_kernel);
> > if (err)
> > goto free_map_sec;
> >
^ permalink raw reply
* Re: [PATCH v2 08/13] bpf: Implement signature verification for BPF programs
From: KP Singh @ 2025-08-11 22:22 UTC (permalink / raw)
To: Dan Carpenter
Cc: oe-kbuild, bpf, linux-security-module, lkp, oe-kbuild-all,
bboscaccy, paul, kys, ast, daniel, andrii
In-Reply-To: <0b060832-4f55-486a-8994-f52d84c39e38@suswa.mountain>
[...]
> vim +/sig +2797 kernel/bpf/syscall.c
>
> c83b0ba795b625 KP Singh 2025-07-21 2782 static noinline int bpf_prog_verify_signature(struct bpf_prog *prog,
> c83b0ba795b625 KP Singh 2025-07-21 2783 union bpf_attr *attr,
> c83b0ba795b625 KP Singh 2025-07-21 2784 bool is_kernel)
> c83b0ba795b625 KP Singh 2025-07-21 2785 {
> c83b0ba795b625 KP Singh 2025-07-21 2786 bpfptr_t usig = make_bpfptr(attr->signature, is_kernel);
> c83b0ba795b625 KP Singh 2025-07-21 2787 struct bpf_dynptr_kern sig_ptr, insns_ptr;
> c83b0ba795b625 KP Singh 2025-07-21 2788 struct bpf_key *key = NULL;
> c83b0ba795b625 KP Singh 2025-07-21 2789 void *sig;
> c83b0ba795b625 KP Singh 2025-07-21 2790 int err = 0;
> c83b0ba795b625 KP Singh 2025-07-21 2791
> c83b0ba795b625 KP Singh 2025-07-21 2792 key = bpf_lookup_user_key(attr->keyring_id, 0);
> c83b0ba795b625 KP Singh 2025-07-21 2793 if (!key)
> c83b0ba795b625 KP Singh 2025-07-21 2794 return -ENOKEY;
> c83b0ba795b625 KP Singh 2025-07-21 2795
> c83b0ba795b625 KP Singh 2025-07-21 2796 sig = kvmemdup_bpfptr(usig, attr->signature_size);
> c83b0ba795b625 KP Singh 2025-07-21 @2797 if (!sig) {
>
> This should be an if (!IS_ERR(sig)) { check.
Thanks, fixed.
- KP
^ permalink raw reply
* Re: [PATCH v5 4/5] Audit: Fix indentation in audit_log_exit
From: Paul Moore @ 2025-08-11 22:21 UTC (permalink / raw)
To: Casey Schaufler
Cc: eparis, linux-security-module, audit, jmorris, serge, keescook,
john.johansen, penguin-kernel, stephen.smalley.work, linux-kernel,
selinux
In-Reply-To: <4f6c9294-dfb3-45cf-8f46-c1a0063d2921@schaufler-ca.com>
On Tue, Aug 5, 2025 at 7:06 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 8/5/2025 12:39 PM, Paul Moore wrote:
> > On Jul 16, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> >> Fix two indentation errors in audit_log_exit().
> >>
> >> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> >> ---
> >> kernel/auditsc.c | 7 ++++---
> >> 1 file changed, 4 insertions(+), 3 deletions(-)
> > As this is indepdendent of all the other changes in this patchset, I'm
> > going to merge this into audit/dev-staging now and audit/dev later when
> > the merge window is closed.
>
> Spiffy. Thank You.
... and now it's in audit/dev, thanks!
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v2 12/13] selftests/bpf: Enable signature verification for all lskel tests
From: KP Singh @ 2025-08-11 22:20 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: bpf, LSM List, Blaise Boscaccy, Paul Moore, K. Y. Srinivasan,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
In-Reply-To: <CAADnVQJ28MimhbBKr6ck85zBVCa9vf96aZzq0H3ZOQ-zvgzWxg@mail.gmail.com>
[...]
> > $(Q)diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
> > - $(Q)$$(BPFTOOL) gen skeleton -L $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@
> > + $(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)
>
> Does it mean that it makes all lskel tests to be signed tests ?
> It's great that CI green lights it, but imo it's an overkill.
> Let's have a few signed tests instead of making all of them.
Updated:
diff --git a/tools/testing/selftests/bpf/Makefile
b/tools/testing/selftests/bpf/Makefile
index 1295ff8f26ff..e473e2d780fb 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -496,15 +496,16 @@ LINKED_SKELS := test_static_linked.skel.h
linked_funcs.skel.h \
test_subskeleton.skel.h test_subskeleton_lib.skel.h \
test_usdt.skel.h
-LSKELS := fentry_test.c fexit_test.c fexit_sleep.c atomics.c \
- trace_printk.c trace_vprintk.c map_ptr_kern.c \
+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
+
# 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)
+SKEL_BLACKLIST += $$(LSKELS) $$(LSKELS_SIGNED)
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
@@ -551,6 +552,7 @@ TRUNNER_BPF_SKELS := $$(patsubst
%.c,$$(TRUNNER_OUTPUT)/%.skel.h, \
$$(TRUNNER_BPF_SRCS)))
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))
TEST_GEN_FILES += $$(TRUNNER_BPF_OBJS)
# Evaluate rules now with extra TRUNNER_XXX variables above already defined
@@ -602,6 +604,15 @@ $(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o
$(BPFTOOL) | $(TRUNNER_OUTPUT)
$(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 -L $$(<:.o=.llinked3.o) name
$$(notdir $$(<:.bpf.o=_lskel)) > $$@
+ $(Q)rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
+
+$(TRUNNER_BPF_LSKELS_SIGNED): %.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)
$$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@
$(Q)rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
@@ -654,6 +665,7 @@ $(TRUNNER_TEST_OBJS:.o=.d):
$(TRUNNER_OUTPUT)/%.test.d: \
$(TRUNNER_EXTRA_HDRS) \
$(TRUNNER_BPF_SKELS) \
$(TRUNNER_BPF_LSKELS) \
+ $(TRUNNER_BPF_LSKELS_SIGNED) \
$(TRUNNER_BPF_SKELS_LINKED) \
$$(BPFOBJ) | $(TRUNNER_OUTPUT)
^ permalink raw reply related
* Re: [PATCH v2 04/13] libbpf: Support exclusive map creation
From: KP Singh @ 2025-08-11 22:18 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: bpf, LSM List, Blaise Boscaccy, Paul Moore, K. Y. Srinivasan,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
In-Reply-To: <CAADnVQJ=8Y_k=JtbNQuhTTCJn33iAniAEh6MLN1BfTZ6pmP=WA@mail.gmail.com>
On Tue, Jul 29, 2025 at 4:25 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Mon, Jul 21, 2025 at 2:20 PM KP Singh <kpsingh@kernel.org> wrote:
> >
> >
> > +/**
> > + * @brief **bpf_map__get_exclusive_program()** returns the exclusive program
> > + * that is registered with the map (if any).
> > + * @param map BPF map to which the exclusive program is registered.
> > + * @return the registered exclusive program.
> > + */
> > +LIBBPF_API struct bpf_program *bpf_map__get_exclusive_program(struct bpf_map *map);
>
> I couldn't find patches where it's used.
> Do we actually need it?
Andrii asked me to add the getter along with the setter in:
http://lore.kernel.org/bpf/CAEf4BzZghpnHaV+z2GYDNCApzLuxMW6_=4afgpO+D7AG-zTSFQ@mail.gmail.com/
^ permalink raw reply
* Re: [PATCH v2] lsm,selinux: Add LSM blob support for BPF objects
From: Paul Moore @ 2025-08-11 22:16 UTC (permalink / raw)
To: Blaise Boscaccy
Cc: James Morris, Serge E. Hallyn, Stephen Smalley, Ondrej Mosnacek,
Casey Schaufler, John Johansen, Christian Göttsche, Song Liu,
linux-security-module, linux-kernel, selinux
In-Reply-To: <CAHC9VhTPrrgRh7v-H7qpizbxHNcW-V1qj-=24+Z8at2w4Co4uw@mail.gmail.com>
On Thu, Aug 7, 2025 at 1:21 PM Paul Moore <paul@paul-moore.com> wrote:
> On Thu, Aug 7, 2025 at 11:09 AM Blaise Boscaccy
> <bboscaccy@linux.microsoft.com> wrote:
> > Paul Moore <paul@paul-moore.com> writes:
> >
> > > On Jul 22, 2025 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
> > >>
> > >> This patch introduces LSM blob support for BPF maps, programs, and
> > >> tokens to enable LSM stacking and multiplexing of LSM modules that
> > >> govern BPF objects. Additionally, the existing BPF hooks used by
> > >> SELinux have been updated to utilize the new blob infrastructure,
> > >> removing the assumption of exclusive ownership of the security
> > >> pointer.
> > >>
> > >> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> > >> ---
> > >> v2:
> > >> - Use lsm_blob_alloc
> > >> - Remove unneded null check
> > >> - ifdef guard bpf alloc helpers
> > >> ---
> > >> include/linux/lsm_hooks.h | 3 ++
> > >> security/security.c | 86 +++++++++++++++++++++++++++++--
> > >> security/selinux/hooks.c | 56 ++++----------------
> > >> security/selinux/include/objsec.h | 17 ++++++
> > >> 4 files changed, 113 insertions(+), 49 deletions(-)
> > >
> > > This looks good to me, one nit/question below ...
> > >
> > >> @@ -5684,7 +5731,16 @@ int security_bpf_prog(struct bpf_prog *prog)
> > >> int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
> > >> struct bpf_token *token, bool kernel)
> > >> {
> > >> - return call_int_hook(bpf_map_create, map, attr, token, kernel);
> > >> + int rc = 0;
> > >
> > > I understand the motivation behind initializing @rc to zero, but to be
> > > honest it is redundant and will surely result in a follow on patch from
> > > someone to remove the initialization.
> > >
> > > Do you have any objection to me removing the initialization during the
> > > merge? This would obviously apply to the other two as well.
> > >
> >
> > No objections on my end. Thanks.
>
> Okay, merged to lsm/dev-staging with plans to move it to lsm/dev once
> the merge window closes.
Now merged into lsm/dev, thanks!
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH] lsm: use lsm_blob_alloc() in lsm_bdev_alloc()
From: Paul Moore @ 2025-08-11 22:16 UTC (permalink / raw)
To: linux-security-module
In-Reply-To: <CAHC9VhR1rTnv0ARUhAPag2O+bEXzxoww6UJa6pkesHZTEa-BHQ@mail.gmail.com>
On Wed, Aug 6, 2025 at 9:49 PM Paul Moore <paul@paul-moore.com> wrote:
> On Wed, Aug 6, 2025 at 5:26 PM Paul Moore <paul@paul-moore.com> wrote:
> >
> > Convert the lsm_bdev_alloc() function to use the lsm_blob_alloc() helper
> > like all of the other LSM security blob allocators.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> > security/security.c | 12 ++----------
> > 1 file changed, 2 insertions(+), 10 deletions(-)
>
> Normally I might let this sit a bit longer on the mailing list, but
> considering how trivial this is along with a Reviewed-by and an ACK
> I'm going to go ahead and merge this into lsm/dev-staging for testing
> and lsm/dev once the merge window closes.
This is now in lsm/dev, thanks all.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH RFC V10 4/7] KVM: guest_memfd: Use guest mem inodes instead of anonymous inodes
From: Ackerley Tng @ 2025-08-11 21:23 UTC (permalink / raw)
To: David Hildenbrand, Shivank Garg, seanjc, vbabka, willy, akpm,
shuah, pbonzini, brauner, viro
Cc: paul, jmorris, serge, pvorel, bfoster, tabba, vannapurve,
chao.gao, bharata, nikunj, michael.day, shdhiman, yan.y.zhao,
Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik, jgg,
kalyazin, peterx, jack, rppt, hch, cgzones, ira.weiny, rientjes,
roypat, ziy, matthew.brost, joshua.hahnjy, rakie.kim, byungchul,
gourry, kent.overstreet, ying.huang, apopple, chao.p.peng, amit,
ddutile, dan.j.williams, ashish.kalra, gshan, jgowans,
pankaj.gupta, papaluri, yuzhao, suzuki.poulose, quic_eberman,
aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm, linux-kernel,
linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <cee2e489-d3c9-46d4-8d34-37c637c7bbd8@redhat.com>
David Hildenbrand <david@redhat.com> writes:
> On 11.08.25 11:06, Shivank Garg wrote:
>> From: Ackerley Tng <ackerleytng@google.com>
>>
>> [...snip...]
>>
>> +static struct file *kvm_gmem_inode_create_getfile(void *priv, loff_t size,
>> + u64 flags)
>> +{
>> + static const char *name = "[kvm-gmem]";
>> + struct inode *inode;
>> + struct file *file;
>> + int err;
>> +
>> + err = -ENOENT;
>
> Maybe add a comment here when the module reference will get
> dropped. And maybe we should just switch to fops_get() + fops_put?
>
> /* __fput() will take care of fops_put(). */
> if (!fops_get(&kvm_gmem_fops))
> goto err;
>
Sounds good! Please see attached patch. It's exactly what you suggested
except I renamed the goto target to err_fops_put:
>> +
>> + inode = kvm_gmem_inode_make_secure_inode(name, size, flags);
>> + if (IS_ERR(inode)) {
>> + err = PTR_ERR(inode);
>> + goto err_put_module;
>> + }
>> +
>> + file = alloc_file_pseudo(inode, kvm_gmem_mnt, name, O_RDWR,
>> + &kvm_gmem_fops);
>> + if (IS_ERR(file)) {
>> + err = PTR_ERR(file);
>> + goto err_put_inode;
>> + }
>> +
>> + file->f_flags |= O_LARGEFILE;
>> + file->private_data = priv;
>> +
>> +out:
>> + return file;
>> +
>> +err_put_inode:
>> + iput(inode);
>> +err_put_module:
>> + module_put(kvm_gmem_fops.owner);
>
> fops_put(&kvm_gmem_fops);
>
> ?
>
>
> Acked-by: David Hildenbrand <david@redhat.com>
>
> --
> Cheers,
>
> David / dhildenb
From f2bd4499bce4db69bf34be75e009579db4329b7c Mon Sep 17 00:00:00 2001
From: Ackerley Tng <ackerleytng@google.com>
Date: Sun, 13 Jul 2025 17:43:35 +0000
Subject: [PATCH] KVM: guest_memfd: Use guest mem inodes instead of anonymous
inodes
guest_memfd's inode represents memory the guest_memfd is
providing. guest_memfd's file represents a struct kvm's view of that
memory.
Using a custom inode allows customization of the inode teardown
process via callbacks. For example, ->evict_inode() allows
customization of the truncation process on file close, and
->destroy_inode() and ->free_inode() allow customization of the inode
freeing process.
Customizing the truncation process allows flexibility in management of
guest_memfd memory and customization of the inode freeing process
allows proper cleanup of memory metadata stored on the inode.
Memory metadata is more appropriately stored on the inode (as opposed
to the file), since the metadata is for the memory and is not unique
to a specific binding and struct kvm.
Co-developed-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Shivank Garg <shivankg@amd.com>
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
include/uapi/linux/magic.h | 1 +
virt/kvm/guest_memfd.c | 129 ++++++++++++++++++++++++++++++-------
virt/kvm/kvm_main.c | 7 +-
virt/kvm/kvm_mm.h | 9 +--
4 files changed, 119 insertions(+), 27 deletions(-)
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index bb575f3ab45e5..638ca21b7a909 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -103,5 +103,6 @@
#define DEVMEM_MAGIC 0x454d444d /* "DMEM" */
#define SECRETMEM_MAGIC 0x5345434d /* "SECM" */
#define PID_FS_MAGIC 0x50494446 /* "PIDF" */
+#define GUEST_MEMFD_MAGIC 0x474d454d /* "GMEM" */
#endif /* __LINUX_MAGIC_H__ */
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 08a6bc7d25b60..6c66a09740550 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -1,12 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/anon_inodes.h>
#include <linux/backing-dev.h>
#include <linux/falloc.h>
+#include <linux/fs.h>
#include <linux/kvm_host.h>
+#include <linux/pseudo_fs.h>
#include <linux/pagemap.h>
-#include <linux/anon_inodes.h>
#include "kvm_mm.h"
+static struct vfsmount *kvm_gmem_mnt;
+
struct kvm_gmem {
struct kvm *kvm;
struct xarray bindings;
@@ -385,9 +389,45 @@ static struct file_operations kvm_gmem_fops = {
.fallocate = kvm_gmem_fallocate,
};
-void kvm_gmem_init(struct module *module)
+static int kvm_gmem_init_fs_context(struct fs_context *fc)
+{
+ if (!init_pseudo(fc, GUEST_MEMFD_MAGIC))
+ return -ENOMEM;
+
+ fc->s_iflags |= SB_I_NOEXEC;
+ fc->s_iflags |= SB_I_NODEV;
+
+ return 0;
+}
+
+static struct file_system_type kvm_gmem_fs = {
+ .name = "guest_memfd",
+ .init_fs_context = kvm_gmem_init_fs_context,
+ .kill_sb = kill_anon_super,
+};
+
+static int kvm_gmem_init_mount(void)
+{
+ kvm_gmem_mnt = kern_mount(&kvm_gmem_fs);
+
+ if (IS_ERR(kvm_gmem_mnt))
+ return PTR_ERR(kvm_gmem_mnt);
+
+ kvm_gmem_mnt->mnt_flags |= MNT_NOEXEC;
+ return 0;
+}
+
+int kvm_gmem_init(struct module *module)
{
kvm_gmem_fops.owner = module;
+
+ return kvm_gmem_init_mount();
+}
+
+void kvm_gmem_exit(void)
+{
+ kern_unmount(kvm_gmem_mnt);
+ kvm_gmem_mnt = NULL;
}
static int kvm_gmem_migrate_folio(struct address_space *mapping,
@@ -463,11 +503,72 @@ bool __weak kvm_arch_supports_gmem_mmap(struct kvm *kvm)
return true;
}
+static struct inode *kvm_gmem_inode_make_secure_inode(const char *name,
+ loff_t size, u64 flags)
+{
+ struct inode *inode;
+
+ inode = anon_inode_make_secure_inode(kvm_gmem_mnt->mnt_sb, name, NULL);
+ if (IS_ERR(inode))
+ return inode;
+
+ inode->i_private = (void *)(unsigned long)flags;
+ inode->i_op = &kvm_gmem_iops;
+ inode->i_mapping->a_ops = &kvm_gmem_aops;
+ inode->i_mode |= S_IFREG;
+ inode->i_size = size;
+ mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
+ mapping_set_inaccessible(inode->i_mapping);
+ /* Unmovable mappings are supposed to be marked unevictable as well. */
+ WARN_ON_ONCE(!mapping_unevictable(inode->i_mapping));
+
+ return inode;
+}
+
+static struct file *kvm_gmem_inode_create_getfile(void *priv, loff_t size,
+ u64 flags)
+{
+ static const char *name = "[kvm-gmem]";
+ struct inode *inode;
+ struct file *file;
+ int err;
+
+ err = -ENOENT;
+ /* __fput() will take care of fops_put(). */
+ if (!fops_get(&kvm_gmem_fops))
+ goto err;
+
+ inode = kvm_gmem_inode_make_secure_inode(name, size, flags);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto err_fops_put;
+ }
+
+ file = alloc_file_pseudo(inode, kvm_gmem_mnt, name, O_RDWR,
+ &kvm_gmem_fops);
+ if (IS_ERR(file)) {
+ err = PTR_ERR(file);
+ goto err_put_inode;
+ }
+
+ file->f_flags |= O_LARGEFILE;
+ file->private_data = priv;
+
+out:
+ return file;
+
+err_put_inode:
+ iput(inode);
+err_fops_put:
+ fops_put(&kvm_gmem_fops);
+err:
+ file = ERR_PTR(err);
+ goto out;
+}
+
static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags)
{
- const char *anon_name = "[kvm-gmem]";
struct kvm_gmem *gmem;
- struct inode *inode;
struct file *file;
int fd, err;
@@ -481,32 +582,16 @@ static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags)
goto err_fd;
}
- file = anon_inode_create_getfile(anon_name, &kvm_gmem_fops, gmem,
- O_RDWR, NULL);
+ file = kvm_gmem_inode_create_getfile(gmem, size, flags);
if (IS_ERR(file)) {
err = PTR_ERR(file);
goto err_gmem;
}
- file->f_flags |= O_LARGEFILE;
-
- inode = file->f_inode;
- WARN_ON(file->f_mapping != inode->i_mapping);
-
- inode->i_private = (void *)(unsigned long)flags;
- inode->i_op = &kvm_gmem_iops;
- inode->i_mapping->a_ops = &kvm_gmem_aops;
- inode->i_mode |= S_IFREG;
- inode->i_size = size;
- mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
- mapping_set_inaccessible(inode->i_mapping);
- /* Unmovable mappings are supposed to be marked unevictable as well. */
- WARN_ON_ONCE(!mapping_unevictable(inode->i_mapping));
-
kvm_get_kvm(kvm);
gmem->kvm = kvm;
xa_init(&gmem->bindings);
- list_add(&gmem->entry, &inode->i_mapping->i_private_list);
+ list_add(&gmem->entry, &file_inode(file)->i_mapping->i_private_list);
fd_install(fd, file);
return fd;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 18f29ef935437..301d48d6e00d0 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -6489,7 +6489,9 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
if (WARN_ON_ONCE(r))
goto err_vfio;
- kvm_gmem_init(module);
+ r = kvm_gmem_init(module);
+ if (r)
+ goto err_gmem;
r = kvm_init_virtualization();
if (r)
@@ -6510,6 +6512,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
err_register:
kvm_uninit_virtualization();
err_virt:
+ kvm_gmem_exit();
+err_gmem:
kvm_vfio_ops_exit();
err_vfio:
kvm_async_pf_deinit();
@@ -6541,6 +6545,7 @@ void kvm_exit(void)
for_each_possible_cpu(cpu)
free_cpumask_var(per_cpu(cpu_kick_mask, cpu));
kmem_cache_destroy(kvm_vcpu_cache);
+ kvm_gmem_exit();
kvm_vfio_ops_exit();
kvm_async_pf_deinit();
kvm_irqfd_exit();
diff --git a/virt/kvm/kvm_mm.h b/virt/kvm/kvm_mm.h
index 31defb08ccbab..9fcc5d5b7f8d0 100644
--- a/virt/kvm/kvm_mm.h
+++ b/virt/kvm/kvm_mm.h
@@ -68,17 +68,18 @@ static inline void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm,
#endif /* HAVE_KVM_PFNCACHE */
#ifdef CONFIG_KVM_GUEST_MEMFD
-void kvm_gmem_init(struct module *module);
+int kvm_gmem_init(struct module *module);
+void kvm_gmem_exit(void);
int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args);
int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
unsigned int fd, loff_t offset);
void kvm_gmem_unbind(struct kvm_memory_slot *slot);
#else
-static inline void kvm_gmem_init(struct module *module)
+static inline int kvm_gmem_init(struct module *module)
{
-
+ return 0;
}
-
+static inline void kvm_gmem_exit(void) {};
static inline int kvm_gmem_bind(struct kvm *kvm,
struct kvm_memory_slot *slot,
unsigned int fd, loff_t offset)
--
2.51.0.rc0.155.g4a0f42376b-goog
^ permalink raw reply related
* Re: [PATCH RFC V10 4/7] KVM: guest_memfd: Use guest mem inodes instead of anonymous inodes
From: David Hildenbrand @ 2025-08-11 15:33 UTC (permalink / raw)
To: Shivank Garg, seanjc, vbabka, willy, akpm, shuah, pbonzini,
brauner, viro
Cc: ackerleytng, paul, jmorris, serge, pvorel, bfoster, tabba,
vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
jgg, kalyazin, peterx, jack, rppt, hch, cgzones, ira.weiny,
rientjes, roypat, ziy, matthew.brost, joshua.hahnjy, rakie.kim,
byungchul, gourry, kent.overstreet, ying.huang, apopple,
chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra, gshan,
jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
quic_eberman, aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm,
linux-kernel, linux-security-module, kvm, linux-kselftest,
linux-coco
In-Reply-To: <20250811090605.16057-10-shivankg@amd.com>
On 11.08.25 11:06, Shivank Garg wrote:
> From: Ackerley Tng <ackerleytng@google.com>
>
> guest_memfd's inode represents memory the guest_memfd is
> providing. guest_memfd's file represents a struct kvm's view of that
> memory.
>
> Using a custom inode allows customization of the inode teardown
> process via callbacks. For example, ->evict_inode() allows
> customization of the truncation process on file close, and
> ->destroy_inode() and ->free_inode() allow customization of the inode
> freeing process.
>
> Customizing the truncation process allows flexibility in management of
> guest_memfd memory and customization of the inode freeing process
> allows proper cleanup of memory metadata stored on the inode.
>
> Memory metadata is more appropriately stored on the inode (as opposed
> to the file), since the metadata is for the memory and is not unique
> to a specific binding and struct kvm.
>
> Co-developed-by: Fuad Tabba <tabba@google.com>
> Signed-off-by: Fuad Tabba <tabba@google.com>
> Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> Signed-off-by: Shivank Garg <shivankg@amd.com>
> ---
[...]
>
> static int kvm_gmem_migrate_folio(struct address_space *mapping,
> @@ -463,11 +503,71 @@ bool __weak kvm_arch_supports_gmem_mmap(struct kvm *kvm)
> return true;
> }
>
> +static struct inode *kvm_gmem_inode_make_secure_inode(const char *name,
> + loff_t size, u64 flags)
> +{
> + struct inode *inode;
> +
> + inode = anon_inode_make_secure_inode(kvm_gmem_mnt->mnt_sb, name, NULL);
> + if (IS_ERR(inode))
> + return inode;
> +
> + inode->i_private = (void *)(unsigned long)flags;
> + inode->i_op = &kvm_gmem_iops;
> + inode->i_mapping->a_ops = &kvm_gmem_aops;
> + inode->i_mode |= S_IFREG;
> + inode->i_size = size;
> + mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
> + mapping_set_inaccessible(inode->i_mapping);
> + /* Unmovable mappings are supposed to be marked unevictable as well. */
> + WARN_ON_ONCE(!mapping_unevictable(inode->i_mapping));
> +
> + return inode;
> +}
> +
> +static struct file *kvm_gmem_inode_create_getfile(void *priv, loff_t size,
> + u64 flags)
> +{
> + static const char *name = "[kvm-gmem]";
> + struct inode *inode;
> + struct file *file;
> + int err;
> +
> + err = -ENOENT;
Maybe add a comment here when the module reference will get
dropped. And maybe we should just switch to fops_get() + fops_put?
/* __fput() will take care of fops_put(). */
if (!fops_get(&kvm_gmem_fops))
goto err;
> +
> + inode = kvm_gmem_inode_make_secure_inode(name, size, flags);
> + if (IS_ERR(inode)) {
> + err = PTR_ERR(inode);
> + goto err_put_module;
> + }
> +
> + file = alloc_file_pseudo(inode, kvm_gmem_mnt, name, O_RDWR,
> + &kvm_gmem_fops);
> + if (IS_ERR(file)) {
> + err = PTR_ERR(file);
> + goto err_put_inode;
> + }
> +
> + file->f_flags |= O_LARGEFILE;
> + file->private_data = priv;
> +
> +out:
> + return file;
> +
> +err_put_inode:
> + iput(inode);
> +err_put_module:
> + module_put(kvm_gmem_fops.owner);
fops_put(&kvm_gmem_fops);
?
Acked-by: David Hildenbrand <david@redhat.com>
--
Cheers,
David / dhildenb
^ permalink raw reply
* Re: [PATCH RFC V10 0/7] Add NUMA mempolicy support for KVM guest-memfd
From: David Hildenbrand @ 2025-08-11 14:41 UTC (permalink / raw)
To: Sean Christopherson, Shivank Garg
Cc: vbabka, willy, akpm, shuah, pbonzini, brauner, viro, ackerleytng,
paul, jmorris, serge, pvorel, bfoster, tabba, vannapurve,
chao.gao, bharata, nikunj, michael.day, shdhiman, yan.y.zhao,
Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik, jgg,
kalyazin, peterx, jack, rppt, hch, cgzones, ira.weiny, rientjes,
roypat, ziy, matthew.brost, joshua.hahnjy, rakie.kim, byungchul,
gourry, kent.overstreet, ying.huang, apopple, chao.p.peng, amit,
ddutile, dan.j.williams, ashish.kalra, gshan, jgowans,
pankaj.gupta, papaluri, yuzhao, suzuki.poulose, quic_eberman,
aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm, linux-kernel,
linux-security-module, kvm, linux-kselftest, linux-coco
In-Reply-To: <aJn_ZvD2AfZBX4Ox@google.com>
On 11.08.25 16:34, Sean Christopherson wrote:
> On Mon, Aug 11, 2025, Shivank Garg wrote:
>> This series introduces NUMA-aware memory placement support for KVM guests
>> with guest_memfd memory backends. It builds upon Fuad Tabba's work (V17)
>> that enabled host-mapping for guest_memfd memory [1].
>
> Is this still actually an RFC? If so, why? If not, drop tag on the next version
> (if one is needed/sent).
There was the complaint that !RFC meant that it would be based on a
consumable upstream branch.
I think once this series is rebase on top of kvm-next, we can finally
drop the tag.
--
Cheers,
David / dhildenb
^ permalink raw reply
* Re: [PATCH v2 11/13] bpftool: Add support for signing BPF programs
From: Quentin Monnet @ 2025-08-11 14:39 UTC (permalink / raw)
To: KP Singh
Cc: bpf, linux-security-module, bboscaccy, paul, kys, ast, daniel,
andrii
In-Reply-To: <CACYkzJ4_DUx-HXmygptxKDg1PjkwnQGKzkfRMms8O_wN2Urpmg@mail.gmail.com>
2025-08-11 16:23 UTC+0200 ~ KP Singh <kpsingh@kernel.org>
> On Thu, Jul 24, 2025 at 7:07 PM KP Singh <kpsingh@kernel.org> wrote:
>>
>> On Tue, Jul 22, 2025 at 5:51 PM Quentin Monnet <qmo@kernel.org> wrote:
>>>
>>> 2025-07-21 23:19 UTC+0200 ~ KP Singh <kpsingh@kernel.org>
[...]
>>>> @@ -533,6 +547,11 @@ int main(int argc, char **argv)
>>>> if (argc < 0)
>>>> usage();
>>>>
>>>> + if (sign_progs && (private_key_path == NULL || cert_path == NULL)) {
>>>> + p_err("-i <identity_x509_cert> and -k <private> key must be supplied with -S for signing");
>>>> + return -EINVAL;
>>>> + }
>>>
>>>
>>> What if -i and/or -k are passed without -S?
>>
>> We can either print a warning or error out
>>
>> A) User does not want to sign removes --sign and forgets to remove -i
>> -k (better with warning)
>> B) User wants to sign but forgets to --sign (better with error)
>>
>> I'd say we print an error so that we don't accidentally not sign, WDYT?
>>
>> The reason why I think we should keep an explicit --sign is because we
>> can also extend this to have e.g. --verify.
>
> if (!sign_progs && (private_key_path != NULL || cert_path != NULL)) {
> p_err("-i <identity_x509_cert> and -k <private> also need --sign to be
> used for sign programs");
> return -EINVAL;
> }
>
> I will error out, I was waiting for Quentin's reply, we can fix it
> later if needed.
Hi KP, I meant to reply to your email but forgot, apologies.
Yes please, it makes sense to me to error out in that case. Let's make
sure that users have the right syntax rather than letting them
accidentally turn off signing.
Thanks for your other comments and clarification too, looks all good to
me :)
Thanks,
Quentin
^ permalink raw reply
* Re: [PATCH RFC V10 0/7] Add NUMA mempolicy support for KVM guest-memfd
From: Sean Christopherson @ 2025-08-11 14:34 UTC (permalink / raw)
To: Shivank Garg
Cc: david, vbabka, willy, akpm, shuah, pbonzini, brauner, viro,
ackerleytng, paul, jmorris, serge, pvorel, bfoster, tabba,
vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
jgg, kalyazin, peterx, jack, rppt, hch, cgzones, ira.weiny,
rientjes, roypat, ziy, matthew.brost, joshua.hahnjy, rakie.kim,
byungchul, gourry, kent.overstreet, ying.huang, apopple,
chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra, gshan,
jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
quic_eberman, aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm,
linux-kernel, linux-security-module, kvm, linux-kselftest,
linux-coco
In-Reply-To: <20250811090605.16057-2-shivankg@amd.com>
On Mon, Aug 11, 2025, Shivank Garg wrote:
> This series introduces NUMA-aware memory placement support for KVM guests
> with guest_memfd memory backends. It builds upon Fuad Tabba's work (V17)
> that enabled host-mapping for guest_memfd memory [1].
Is this still actually an RFC? If so, why? If not, drop tag on the next version
(if one is needed/sent).
^ permalink raw reply
* Re: [PATCH v2 13/13] selftests/bpf: Add test for signed programs
From: KP Singh @ 2025-08-11 14:24 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: bpf, LSM List, Blaise Boscaccy, Paul Moore, K. Y. Srinivasan,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
In-Reply-To: <CAADnVQ+3XYyJY_zcQtNPt81zyJwK4zv5oA+SLN9ohoLkD9XyZg@mail.gmail.com>
On Tue, Jul 29, 2025 at 4:30 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Mon, Jul 21, 2025 at 2:20 PM KP Singh <kpsingh@kernel.org> wrote:
> > +
> > +SEC("fexit/bpf_prog_verify_signature")
> > +int BPF_PROG(bpf_sign, struct bpf_prog *prog, union bpf_attr *attr, bool is_kernel, int ret)
>
> I don't understand why it needs to peek into the kernel to
> verify that it goes well. The exposed uapi should be good enough.
> If the signature was specified and it is loaded fine we're good.
> Double checking the kernel decisions goes too far.
> Especially since this function can be inlined by the compiler.
Fair, I will drop this patch
- KP
^ permalink raw reply
* Re: [PATCH v2 11/13] bpftool: Add support for signing BPF programs
From: KP Singh @ 2025-08-11 14:23 UTC (permalink / raw)
To: Quentin Monnet
Cc: bpf, linux-security-module, bboscaccy, paul, kys, ast, daniel,
andrii
In-Reply-To: <CACYkzJ42L-w_eXyc1k+E7yK4DGC3xjdiwjBAznYJdXWzuq4-jA@mail.gmail.com>
On Thu, Jul 24, 2025 at 7:07 PM KP Singh <kpsingh@kernel.org> wrote:
>
> On Tue, Jul 22, 2025 at 5:51 PM Quentin Monnet <qmo@kernel.org> wrote:
> >
> > 2025-07-21 23:19 UTC+0200 ~ KP Singh <kpsingh@kernel.org>
> > > Two modes of operation being added:
> > >
> > > Add two modes of operation:
> > >
> > > * For prog load, allow signing a program immediately before loading. This
> > > is essential for command-line testing and administration.
> > >
> > > bpftool prog load -S -k <private_key> -i <identity_cert> fentry_test.bpf.o
> > >
> > > * For gen skeleton, embed a pre-generated signature into the C skeleton
> > > file. This supports the use of signed programs in compiled applications.
> > >
> > > bpftool gen skeleton -S -k <private_key> -i <identity_cert> fentry_test.bpf.o
> > >
> > > Generation of the loader program and its metadata map is implemented in
> > > libbpf (bpf_obj__gen_loader). bpftool generates a skeleton that loads
> > > the program and automates the required steps: freezing the map, creating
> > > an exclusive map, loading, and running. Users can use standard libbpf
> > > APIs directly or integrate loader program generation into their own
> > > toolchains.
> >
> >
> > Thanks KP! Some bpftool-related comments below. Looks good overall, I
> > mostly have minor comments.
> >
> > One concern might be the license for the new file, GPL-2.0 in your
> > patch, whereas bpftool is dual-licensed. I hope this is simply an oversight?
>
> An oversight, fixed.
>
> >
> >
> > >
> > > Signed-off-by: KP Singh <kpsingh@kernel.org>
> > > ---
> > > .../bpf/bpftool/Documentation/bpftool-gen.rst | 12 +
> > > .../bpftool/Documentation/bpftool-prog.rst | 12 +
> > > tools/bpf/bpftool/Makefile | 6 +-
> > > tools/bpf/bpftool/cgroup.c | 5 +-
> > > tools/bpf/bpftool/gen.c | 58 ++++-
> > > tools/bpf/bpftool/main.c | 21 +-
> > > tools/bpf/bpftool/main.h | 11 +
> > > tools/bpf/bpftool/prog.c | 25 +++
> > > tools/bpf/bpftool/sign.c | 210 ++++++++++++++++++
> > > 9 files changed, 352 insertions(+), 8 deletions(-)
> > > create mode 100644 tools/bpf/bpftool/sign.c
> > >
> > > diff --git a/tools/bpf/bpftool/Documentation/bpftool-gen.rst b/tools/bpf/bpftool/Documentation/bpftool-gen.rst
> > > index ca860fd97d8d..2997313003b1 100644
> > > --- a/tools/bpf/bpftool/Documentation/bpftool-gen.rst
> > > +++ b/tools/bpf/bpftool/Documentation/bpftool-gen.rst
> > > @@ -185,6 +185,18 @@ OPTIONS
> > > For skeletons, generate a "light" skeleton (also known as "loader"
> > > skeleton). A light skeleton contains a loader eBPF program. It does not use
> > > the majority of the libbpf infrastructure, and does not need libelf.
> >
> >
> > Blank line separator, please
>
> done
>
> >
> >
> > > +-S, --sign
> > > + For skeletons, generate a signed skeleton. This option must be used with
> > > + **-k** and **-i**. Using this flag implicitly enables **--use-loader**.
> > > + See the "Signed Skeletons" section in the description of the
> > > + **gen skeleton** command for more details.
> > > +
> > > +-k <private_key.pem>
> > > + Path to the private key file in PEM format, required for signing.
> > > +
> > > +-i <certificate.x509>
> > > + Path to the X.509 certificate file in PEM or DER format, required for
> > > + signing.
> >
> >
> > Please also update the options list in the SYNOPSIS section at the top
> > of the page; and the option list at the bottom of gen.c (just like for
> > "--use-loader").
>
> done also, isn't this the right formatting for the SYNOPSIS given that
> some of these are optional?
>
> **bpftool** [*OPTIONS*] **prog** *COMMAND*
> *OPTIONS* := { |COMMON_OPTIONS| [ { **-f** | **--bpffs** } ] [ {
> **-m** | **--mapcompat** } ]
> [ { **-n** | **--nomount** } ] [ { **-L** | **--use-loader** } ]
> [ { { **-S** | **--sign** } **-k** <private_key.pem> **-i**
> <certificate.x509> } ] }
>
> not an expert here but I vaguely remember.
>
> Also do you think we need to:
>
> { "use-loader", no_argument, NULL, 'L' },
> - { "sign", required_argument, NULL, 'S'},
> + { "sign", no_argument, NULL, 'S' },
>
>
> Now that we don't use an argument blob for --sign?
>
>
> >
> > Can you also please take a look at the bash completion update? It
> > shouldn't be too hard if you look at how it deals with other options, in
> > particular --base-btf that also takes one argument - and I can help if
> > necessary.
>
> I will give it a go.
>
> >
> >
> > >
> > > EXAMPLES
> > > ========
> > > diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> > > index f69fd92df8d8..dc2ca196137e 100644
> > > --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> > > +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> > > @@ -248,6 +248,18 @@ OPTIONS
> > > creating the maps, and loading the programs (see **bpftool prog tracelog**
> > > as a way to dump those messages).
> > >
> > > +-S, --sign
> > > + Enable signing of the BPF program before loading. This option must be
> > > + used with **-k** and **-i**. Using this flag implicitly enables
> > > + **--use-loader**.
> > > +
> > > +-k <private_key.pem>
> > > + Path to the private key file in PEM format, required when signing.
> > > +
> > > +-i <certificate.x509>
> > > + Path to the X.509 certificate file in PEM or DER format, required when
> > > + signing.
> >
> >
> > Same as for skeletons: please update the list of options in the synopsis
> > and at the bottom of prog.c (bash completion for skeletons' options
> > should also cover this case, so no additional work required here).
> >
> >
> > > +
> > > EXAMPLES
> > > ========
> > > **# bpftool prog show**
> > > diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile
> > > index 9e9a5f006cd2..586d1b2595d1 100644
> > > --- a/tools/bpf/bpftool/Makefile
> > > +++ b/tools/bpf/bpftool/Makefile
> > > @@ -130,8 +130,8 @@ include $(FEATURES_DUMP)
> > > endif
> > > endif
> > >
> > > -LIBS = $(LIBBPF) -lelf -lz
> > > -LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf -lz
> > > +LIBS = $(LIBBPF) -lelf -lz -lcrypto
> > > +LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf -lz -lcrypto
> > >
> > > ifeq ($(feature-libelf-zstd),1)
> > > LIBS += -lzstd
> > > @@ -194,7 +194,7 @@ endif
> > >
> > > BPFTOOL_BOOTSTRAP := $(BOOTSTRAP_OUTPUT)bpftool
> > >
> > > -BOOTSTRAP_OBJS = $(addprefix $(BOOTSTRAP_OUTPUT),main.o common.o json_writer.o gen.o btf.o)
> > > +BOOTSTRAP_OBJS = $(addprefix $(BOOTSTRAP_OUTPUT),main.o common.o json_writer.o gen.o btf.o sign.o)
> > > $(BOOTSTRAP_OBJS): $(LIBBPF_BOOTSTRAP)
> > >
> > > OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o
> > > diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
> > > index 944ebe21a216..90c9aa297806 100644
> > > --- a/tools/bpf/bpftool/cgroup.c
> > > +++ b/tools/bpf/bpftool/cgroup.c
> > > @@ -1,7 +1,10 @@
> > > // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > // Copyright (C) 2017 Facebook
> > > // Author: Roman Gushchin <guro@fb.com>
> > > -
> >
> >
> > Let's keep the blank line
>
> Done
>
> >
> >
> > > +#undef GCC_VERSION
> > > +#ifndef _GNU_SOURCE
> > > +#define _GNU_SOURCE
> > > +#endif
> >
> >
> > What are these for?
>
> kpsingh@kpsingh-genoa:~/projects/linux/tools/bpf/bpftool$ vmk
>
> Auto-detecting system features:
> ... clang-bpf-co-re: [ on ]
> ... llvm: [ on ]
> ... libcap: [ on ]
> ... libbfd: [ OFF ]
>
> In file included from cgroup.c:19:
> In file included from ./main.h:16:
> /home/kpsingh/projects/linux/tools/bpf/bpftool/libbpf/include/bpf/skel_internal.h:87:9:
> error: call to undeclared function 'syscall'; ISO C99 and later do not
> support implicit function declarations
> [-Wimplicit-function-declaration]
> 87 | return syscall(__NR_bpf, cmd, attr, size);
> | ^
> 1 error generated.
>
> >
> >
> > > #define _XOPEN_SOURCE 500
> > > #include <errno.h>
> > > #include <fcntl.h>
> >
> > [...]
> >
> > > diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
> > > index 2b7f2bd3a7db..fc25bb390ec7 100644
> > > --- a/tools/bpf/bpftool/main.c
> > > +++ b/tools/bpf/bpftool/main.c
> > > @@ -33,6 +33,9 @@ bool relaxed_maps;
> > > bool use_loader;
> > > struct btf *base_btf;
> > > struct hashmap *refs_table;
> > > +bool sign_progs;
> > > +const char *private_key_path;
> > > +const char *cert_path;
> > >
> > > static void __noreturn clean_and_exit(int i)
> > > {
> > > @@ -447,6 +450,7 @@ int main(int argc, char **argv)
> > > { "nomount", no_argument, NULL, 'n' },
> > > { "debug", no_argument, NULL, 'd' },
> > > { "use-loader", no_argument, NULL, 'L' },
> > > + { "sign", required_argument, NULL, 'S'},
> > > { "base-btf", required_argument, NULL, 'B' },
> > > { 0 }
> > > };
> > > @@ -473,7 +477,7 @@ int main(int argc, char **argv)
> > > bin_name = "bpftool";
> > >
> > > opterr = 0;
> > > - while ((opt = getopt_long(argc, argv, "VhpjfLmndB:l",
> > > + while ((opt = getopt_long(argc, argv, "VhpjfLmndSi:k:B:l",
> > > options, NULL)) >= 0) {
> > > switch (opt) {
> > > case 'V':
> > > @@ -519,6 +523,16 @@ int main(int argc, char **argv)
> > > case 'L':
> > > use_loader = true;
> > > break;
> > > + case 'S':
> > > + sign_progs = true;
> > > + use_loader = true;
> > > + break;
> > > + case 'k':
> > > + private_key_path = optarg;
> > > + break;
> > > + case 'i':
> > > + cert_path = optarg;
> > > + break;
> > > default:
> > > p_err("unrecognized option '%s'", argv[optind - 1]);
> > > if (json_output)
> > > @@ -533,6 +547,11 @@ int main(int argc, char **argv)
> > > if (argc < 0)
> > > usage();
> > >
> > > + if (sign_progs && (private_key_path == NULL || cert_path == NULL)) {
> > > + p_err("-i <identity_x509_cert> and -k <private> key must be supplied with -S for signing");
> > > + return -EINVAL;
> > > + }
> >
> >
> > What if -i and/or -k are passed without -S?
>
> We can either print a warning or error out
>
> A) User does not want to sign removes --sign and forgets to remove -i
> -k (better with warning)
> B) User wants to sign but forgets to --sign (better with error)
>
> I'd say we print an error so that we don't accidentally not sign, WDYT?
>
> The reason why I think we should keep an explicit --sign is because we
> can also extend this to have e.g. --verify.
if (!sign_progs && (private_key_path != NULL || cert_path != NULL)) {
p_err("-i <identity_x509_cert> and -k <private> also need --sign to be
used for sign programs");
return -EINVAL;
}
I will error out, I was waiting for Quentin's reply, we can fix it
later if needed.
- KP
>
> - KP
>
> >
> >
> > > +
> > > if (version_requested)
> > > ret = do_version(argc, argv);
> > > else
> > > diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
> > > index 6db704fda5c0..f921af3cda87 100644
> > > --- a/tools/bpf/bpftool/main.h
> > > +++ b/tools/bpf/bpftool/main.h
> > > @@ -6,9 +6,14 @@
> > >
> > > /* BFD and kernel.h both define GCC_VERSION, differently */
> > > #undef GCC_VERSION
> > > +#ifndef _GNU_SOURCE
> > > +#define _GNU_SOURCE
> > > +#endif
> > > #include <stdbool.h>
> > > #include <stdio.h>
> > > +#include <errno.h>
> > > #include <stdlib.h>
> > > +#include <bpf/skel_internal.h>
> >
> >
> > Wnat do you need these includes (and _GNU_SOURCE) in main.h for?
>
> Explained above, let me know if you have better ideas on where to place these.
>
> >
> >
> > > #include <linux/bpf.h>
> > > #include <linux/compiler.h>
> > > #include <linux/kernel.h>
> >
> > [...]
> >
> > > diff --git a/tools/bpf/bpftool/sign.c b/tools/bpf/bpftool/sign.c
> > > new file mode 100644
> > > index 000000000000..f0b5dd10a46b
> > > --- /dev/null
> > > +++ b/tools/bpf/bpftool/sign.c
> > > @@ -0,0 +1,210 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> >
> >
> > Please consider making this file dual-licensed like the rest of
> > bpftool's source code, "(GPL-2.0-only OR BSD-2-Clause)".
>
> Done.
>
> >
> >
> > > +
> > > +/*
> > > + * Copyright (C) 2022 Google LLC.
> >
> >
> > 2025?
>
> Let's keep it 2022, nah just kidding :) Thanks.
>
> >
> >
> > > + */
> > > +#define _GNU_SOURCE
> >
> >
> > Please guard this:
> >
> > #ifndef _GNU_SOURCE
> > #define _GNU_SOURCE
> > #endif
> >
> > This is because "llvm-config --cflags" passes -D_GNU_SOURCE and we may
> > end up with a duplicate definition, otherwise.
>
> ack, done.
>
> >
> >
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <stdint.h>
> > > +#include <stdbool.h>
> > > +#include <string.h>
> > > +#include <string.h>
> > > +#include <getopt.h>
> > > +#include <err.h>
> > > +#include <openssl/opensslv.h>
> > > +#include <openssl/bio.h>
> > > +#include <openssl/evp.h>
> > > +#include <openssl/pem.h>
> > > +#include <openssl/err.h>
> > > +#include <openssl/cms.h>
> > > +#include <linux/keyctl.h>
> > > +#include <errno.h>
> > > +
> > > +#include <bpf/skel_internal.h>
> > > +
> > > +#include "main.h"
> > > +
> > > +#define OPEN_SSL_ERR_BUF_LEN 256
> > > +
> > > +static void display_openssl_errors(int l)
> > > +{
> > > + char buf[OPEN_SSL_ERR_BUF_LEN];
> > > + const char *file;
> > > + const char *data;
> > > + unsigned long e;
> > > + int flags;
> > > + int line;
> > > +
> > > + while ((e = ERR_get_error_all(&file, &line, NULL, &data, &flags))) {
> > > + ERR_error_string_n(e, buf, sizeof(buf));
> > > + if (data && (flags & ERR_TXT_STRING)) {
> > > + p_err("OpenSSL %s: %s:%d: %s\n", buf, file, line, data);
> >
> >
> > Please remove the trailing '\n', p_err() handles it already.
> >
> >
> > > + } else {
> > > + p_err("OpenSSL %s: %s:%d\n", buf, file, line);
> >
> >
> > Same here.
>
> done.
>
> - KP
>
> >
> > [...]
^ permalink raw reply
* Re: [RFC PATCH 2/2] memfd: call security_inode_init_security_anon
From: Stephen Smalley @ 2025-08-11 13:08 UTC (permalink / raw)
To: Thiébaud Weksteen
Cc: Paul Moore, James Morris, Hugh Dickins, Jeff Vander Stoep,
Nick Kralevich, Jeff Xu, linux-kernel, linux-security-module,
selinux
In-Reply-To: <CA+zpnLeaKkXAdxUuA5kNbKwrGVX+UCf+VFLK0XbtrbovvPGUWQ@mail.gmail.com>
On Mon, Aug 11, 2025 at 1:34 AM Thiébaud Weksteen <tweek@google.com> wrote:
>
> On Fri, Aug 8, 2025 at 10:41 PM Stephen Smalley
> <stephen.smalley.work@gmail.com> wrote:
> >
> > On Fri, Aug 8, 2025 at 7:57 AM Stephen Smalley
> > <stephen.smalley.work@gmail.com> wrote:
>
> Thanks for the review Stephen.
>
> > >
> > > On Thu, Aug 7, 2025 at 3:57 AM Thiébaud Weksteen <tweek@google.com> wrote:
> > > >
> > > > Prior to this change, no security hooks were called at the creation of a
> > > > memfd file. It means that, for SELinux as an example, it will receive
> > > > the default type of the filesystem that backs the in-memory inode. In
> > > > most cases, that would be tmpfs, but if MFD_HUGETLB is passed, it will
> > > > be hugetlbfs. Both can be considered implementation details of memfd.
> > > >
> > > > It also means that it is not possible to differentiate between a file
> > > > coming from memfd_create and a file coming from a standard tmpfs mount
> > > > point.
> > > >
> > > > Additionally, no permission is validated at creation, which differs from
> > > > the similar memfd_secret syscall.
> > > >
> > > > Call security_inode_init_security_anon during creation. This ensures
> > > > that the file is setup similarly to other anonymous inodes. On SELinux,
> > > > it means that the file will receive the security context of its task.
> > > >
> > > > The ability to limit fexecve on memfd has been of interest to avoid
> > > > potential pitfalls where /proc/self/exe or similar would be executed
> > > > [1][2]. Reuse the "execute_no_trans" and "entrypoint" access vectors,
> > > > similarly to the file class. These access vectors may not make sense for
> > > > the existing "anon_inode" class. Therefore, define and assign a new
> > > > class "memfd_file" to support such access vectors.
> > >
> > > To provide backward compatibility, I would anticipate that you will
> > > need to define a new SELinux policy capability and make this change
> > > conditional on it being enabled, see:
> > > https://github.com/SELinuxProject/selinux-kernel/wiki/Getting-Started#adding-a-new-selinux-policy-capability
> > > for instructions and links to examples.
> > >
>
> I agree. Thanks, I'll add this to the next patchset.
>
> > > Otherwise, see below.
> > >
> > > >
> > > > [1] https://crbug.com/1305267
> > > > [2] https://lore.kernel.org/lkml/20221215001205.51969-1-jeffxu@google.com/
> > > >
> > > > Signed-off-by: Thiébaud Weksteen <tweek@google.com>
> > > > ---
> > > > mm/memfd.c | 16 ++++++++++++++--
> > > > security/selinux/hooks.c | 15 +++++++++++----
> > > > security/selinux/include/classmap.h | 2 ++
> > > > 3 files changed, 27 insertions(+), 6 deletions(-)
> > > >
> > > > diff --git a/mm/memfd.c b/mm/memfd.c
> > > > index bbe679895ef6..13bff0e91816 100644
> > > > --- a/mm/memfd.c
> > > > +++ b/mm/memfd.c
> > > > @@ -433,6 +433,9 @@ static struct file *alloc_file(const char *name, unsigned int flags)
> > > > {
> > > > unsigned int *file_seals;
> > > > struct file *file;
> > > > + struct inode *inode;
> > > > + int err = 0;
> > > > + const char *anon_name = "[memfd]";
> > > >
> > > > if (flags & MFD_HUGETLB) {
> > > > file = hugetlb_file_setup(name, 0, VM_NORESERVE,
> > > > @@ -444,12 +447,21 @@ static struct file *alloc_file(const char *name, unsigned int flags)
> > > > }
> > > > if (IS_ERR(file))
> > > > return file;
> > > > +
> > > > + inode = file_inode(file);
> > > > + err = security_inode_init_security_anon(inode,
> > > > + LSM_ANON_INODE_MEMFD,
> > > > + &QSTR(anon_name), NULL);
> > >
> > > Since the anon_name already indicates that this is a memfd, so can't
> > > you already distinguish these via name-based type_transition rules?
> > > Why do we need the enum argument?
> >
> > On second thought, I see that you are distinguishing not just the
> > security context/type but also the security class, but the question
> > remains: can't you compare the name to make this determination?
> >
>
> I definitely can. My initial thought was that a string comparison
> would not be adequate here (performance-wise), but I guess calls to
> this method are infrequent enough that a strncmp would work here?
Open to data showing otherwise, but would think that a fixed-size
small string comparison would be in the noise here.
>
> On the option of just relying on name-based type transitions, this has
> an impact on the size of the policy: for Android, the transition from
> ashmem to memfd means that virtually all domains will rely on such a
> file. It means that we would need to define a type transition and a
> new type for all our domains. (This is an argument on top of the need
> for execute_no_trans, as I described in the commit message).
>
> > >
> > > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > > > index 8d36d5ebb6e5..49742930e706 100644
> > > > --- a/security/selinux/hooks.c
> > > > +++ b/security/selinux/hooks.c
> > > > @@ -2367,8 +2367,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
> > > > ad.u.file = bprm->file;
> > > >
> > > > if (new_tsec->sid == old_tsec->sid) {
> > > > - rc = avc_has_perm(old_tsec->sid, isec->sid,
> > > > - SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
> > > > + rc = avc_has_perm(old_tsec->sid, isec->sid, isec->sclass,
> > > > + FILE__EXECUTE_NO_TRANS, &ad);
> > >
> > > Here and below I am a little concerned that we could end up reaching
> > > this code on an inode with an isec->sclass that does not define the
> > > execute_no_trans and entrypoint permissions. We should do something to
> > > make that never happens, or check for it and always deny in that case.
>
> I agree. I can add a condition to make sure only these 2 classes (file
> or memfd_file) are used here.
>
> > >
> > > > if (rc)
> > > > return rc;
> > > > } else {
> > > > @@ -2378,8 +2378,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
> > > > if (rc)
> > > > return rc;
> > > >
> > > > - rc = avc_has_perm(new_tsec->sid, isec->sid,
> > > > - SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
> > > > + rc = avc_has_perm(new_tsec->sid, isec->sid, isec->sclass,
> > > > + FILE__ENTRYPOINT, &ad);
> > > > if (rc)
> > > > return rc;
> > > >
> > > > @@ -2997,6 +2997,13 @@ static int selinux_inode_init_security_anon(struct inode *inode,
> > > >
> > > > isec->sclass = context_isec->sclass;
> > > > isec->sid = context_isec->sid;
> > > > + } else if (type == LSM_ANON_INODE_MEMFD) {
> > > > + isec->sclass = SECCLASS_MEMFD_FILE;
> > > > + rc = security_transition_sid(
> > > > + sid, sid,
> > > > + isec->sclass, name, &isec->sid);
> > >
> > > Again, name-based type_transitions ought to be able to distinguish
> > > memfd based on the name argument IIUC.
^ permalink raw reply
* [PATCH RFC V10 7/7] KVM: guest_memfd: selftests: Add tests for mmap and NUMA policy support
From: Shivank Garg @ 2025-08-11 9:06 UTC (permalink / raw)
To: seanjc, david, vbabka, willy, akpm, shuah, pbonzini, brauner,
viro
Cc: ackerleytng, paul, jmorris, serge, pvorel, bfoster, tabba,
vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
jgg, kalyazin, peterx, shivankg, jack, rppt, hch, cgzones,
ira.weiny, rientjes, roypat, ziy, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, kent.overstreet, ying.huang,
apopple, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
quic_eberman, aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm,
linux-kernel, linux-security-module, kvm, linux-kselftest,
linux-coco
In-Reply-To: <20250811090605.16057-2-shivankg@amd.com>
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
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 b86bf89a71e0..4d33c225d9f7 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)
+
+static void test_mbind(int fd, size_t page_size, size_t total_size)
+{
+ unsigned long nodemask = 1; /* nid: 0 */
+ unsigned long maxnode = 8;
+ unsigned long get_nodemask;
+ int get_policy;
+ char *mem;
+ int ret;
+
+ TEST_REQUIRE_NUMA_MULTIPLE_NODES();
+
+ mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ TEST_ASSERT(mem != MAP_FAILED, "mmap for mbind test should succeed");
+
+ /* Test MPOL_INTERLEAVE policy */
+ ret = syscall(__NR_mbind, mem, page_size * 2, MPOL_INTERLEAVE,
+ &nodemask, maxnode, 0);
+ TEST_ASSERT(!ret, "mbind with INTERLEAVE to node 0 should succeed");
+ ret = syscall(__NR_get_mempolicy, &get_policy, &get_nodemask,
+ maxnode, mem, MPOL_F_ADDR);
+ TEST_ASSERT(!ret && get_policy == MPOL_INTERLEAVE && get_nodemask == nodemask,
+ "Policy should be MPOL_INTERLEAVE and nodes match");
+
+ /* Test basic MPOL_BIND policy */
+ ret = syscall(__NR_mbind, mem + page_size * 2, page_size * 2, MPOL_BIND,
+ &nodemask, maxnode, 0);
+ TEST_ASSERT(!ret, "mbind with MPOL_BIND to node 0 should succeed");
+ ret = syscall(__NR_get_mempolicy, &get_policy, &get_nodemask,
+ maxnode, mem + page_size * 2, MPOL_F_ADDR);
+ TEST_ASSERT(!ret && get_policy == MPOL_BIND && get_nodemask == nodemask,
+ "Policy should be MPOL_BIND and nodes match");
+
+ /* Test MPOL_DEFAULT policy */
+ ret = syscall(__NR_mbind, mem, total_size, MPOL_DEFAULT, NULL, 0, 0);
+ TEST_ASSERT(!ret, "mbind with MPOL_DEFAULT should succeed");
+ ret = syscall(__NR_get_mempolicy, &get_policy, &get_nodemask,
+ maxnode, mem, MPOL_F_ADDR);
+ TEST_ASSERT(!ret && get_policy == MPOL_DEFAULT && get_nodemask == 0,
+ "Policy should be MPOL_DEFAULT and nodes zero");
+
+ /* Test with invalid policy */
+ ret = syscall(__NR_mbind, mem, page_size, 999, &nodemask, maxnode, 0);
+ TEST_ASSERT(ret == -1 && errno == EINVAL,
+ "mbind with invalid policy should fail with EINVAL");
+
+ TEST_ASSERT(munmap(mem, total_size) == 0, "munmap should succeed");
+}
+
+static void test_numa_allocation(int fd, size_t page_size, size_t total_size)
+{
+ unsigned long node0_mask = 1; /* Node 0 */
+ unsigned long node1_mask = 2; /* Node 1 */
+ unsigned long maxnode = 8;
+ void *pages[4];
+ int status[4];
+ char *mem;
+ int ret, i;
+
+ TEST_REQUIRE_NUMA_MULTIPLE_NODES();
+
+ /* Clean slate: deallocate all file space, if any */
+ ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, total_size);
+ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) should succeed");
+
+ mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ TEST_ASSERT(mem != MAP_FAILED, "mmap should succeed");
+
+ for (i = 0; i < 4; i++)
+ pages[i] = (char *)mem + page_size * i;
+
+ /* Set NUMA policy after allocation */
+ memset(mem, 0xaa, page_size);
+ ret = syscall(__NR_mbind, pages[0], page_size, MPOL_BIND, &node0_mask, maxnode, 0);
+ TEST_ASSERT(!ret, "mbind after allocation page 0 to node 0 should succeed");
+ ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, page_size);
+ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) should succeed");
+
+ /* Set NUMA policy before allocation */
+ ret = syscall(__NR_mbind, pages[0], page_size * 2, MPOL_BIND, &node1_mask, maxnode, 0);
+ TEST_ASSERT(!ret, "mbind page 0, 1 to node 1 should succeed");
+ ret = syscall(__NR_mbind, pages[2], page_size * 2, MPOL_BIND, &node0_mask, maxnode, 0);
+ TEST_ASSERT(!ret, "mbind page 2, 3 to node 0 should succeed");
+ memset(mem, 0xaa, total_size);
+
+ /* Validate if pages are allocated on specified NUMA nodes */
+ ret = syscall(__NR_move_pages, 0, 4, pages, NULL, status, 0);
+ TEST_ASSERT(ret >= 0, "move_pages should succeed for status check");
+ TEST_ASSERT(status[0] == 1, "Page 0 should be allocated on node 1");
+ TEST_ASSERT(status[1] == 1, "Page 1 should be allocated on node 1");
+ TEST_ASSERT(status[2] == 0, "Page 2 should be allocated on node 0");
+ TEST_ASSERT(status[3] == 0, "Page 3 should be allocated on node 0");
+
+ /* Punch hole for all pages */
+ ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, total_size);
+ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) should succeed");
+
+ /* Change NUMA policy nodes and reallocate */
+ ret = syscall(__NR_mbind, pages[0], page_size * 2, MPOL_BIND, &node0_mask, maxnode, 0);
+ TEST_ASSERT(!ret, "mbind page 0, 1 to node 0 should succeed");
+ ret = syscall(__NR_mbind, pages[2], page_size * 2, MPOL_BIND, &node1_mask, maxnode, 0);
+ TEST_ASSERT(!ret, "mbind page 2, 3 to node 1 should succeed");
+ memset(mem, 0xaa, total_size);
+
+ ret = syscall(__NR_move_pages, 0, 4, pages, NULL, status, 0);
+ TEST_ASSERT(ret >= 0, "move_pages should succeed after reallocation");
+ TEST_ASSERT(status[0] == 0, "Page 0 should be allocated on node 0");
+ TEST_ASSERT(status[1] == 0, "Page 1 should be allocated on node 0");
+ TEST_ASSERT(status[2] == 1, "Page 2 should be allocated on node 1");
+ TEST_ASSERT(status[3] == 1, "Page 3 should be allocated on node 1");
+
+ TEST_ASSERT(munmap(mem, total_size) == 0, "munmap should succeed");
+}
+
static sigjmp_buf jmpbuf;
void fault_sigbus_handler(int signum)
{
@@ -286,6 +405,8 @@ static void test_guest_memfd(unsigned long vm_type)
if (flags & GUEST_MEMFD_FLAG_MMAP) {
test_mmap_supported(fd, page_size, total_size);
test_fault_overflow(fd, page_size, total_size);
+ test_mbind(fd, page_size, total_size);
+ test_numa_allocation(fd, page_size, total_size);
} else {
test_mmap_not_supported(fd, page_size, total_size);
}
--
2.43.0
^ permalink raw reply related
* [PATCH RFC V10 6/7] KVM: guest_memfd: Enforce NUMA mempolicy using shared policy
From: Shivank Garg @ 2025-08-11 9:06 UTC (permalink / raw)
To: seanjc, david, vbabka, willy, akpm, shuah, pbonzini, brauner,
viro
Cc: ackerleytng, paul, jmorris, serge, pvorel, bfoster, tabba,
vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
jgg, kalyazin, peterx, shivankg, jack, rppt, hch, cgzones,
ira.weiny, rientjes, roypat, ziy, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, kent.overstreet, ying.huang,
apopple, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
quic_eberman, aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm,
linux-kernel, linux-security-module, kvm, linux-kselftest,
linux-coco
In-Reply-To: <20250811090605.16057-2-shivankg@amd.com>
Previously, guest-memfd allocations followed local NUMA node id in absence
of process mempolicy, resulting in arbitrary memory allocation.
Moreover, mbind() couldn't be used by the VMM as guest memory wasn't
mapped into userspace when allocation occurred.
Enable NUMA policy support by implementing vm_ops for guest-memfd mmap
operation. This allows the VMM to map the memory and use mbind() to set the
desired NUMA policy. The policy is stored in the inode structure via
kvm_gmem_inode_info, as memory policy is a property of the memory (struct
inode) itself. The policy is then retrieved via mpol_shared_policy_lookup()
and passed to filemap_grab_folio_mpol() to ensure that allocations follow
the specified memory policy.
This enables the VMM to control guest memory NUMA placement by calling
mbind() on the mapped memory regions, providing fine-grained control over
guest memory allocation across NUMA nodes.
The policy change only affect future allocations and does not migrate
existing memory. This matches mbind(2)'s default behavior which affects
only new allocations unless overridden with MPOL_MF_MOVE/MPOL_MF_MOVE_ALL
flags, which are not supported for guest_memfd as it is unmovable.
Suggested-by: David Hildenbrand <david@redhat.com>
Acked-by: David Hildenbrand <david@redhat.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Shivank Garg <shivankg@amd.com>
---
virt/kvm/guest_memfd.c | 67 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 65 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index d9c23401e770..7821c1036e49 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -4,6 +4,7 @@
#include <linux/falloc.h>
#include <linux/fs.h>
#include <linux/kvm_host.h>
+#include <linux/mempolicy.h>
#include <linux/pseudo_fs.h>
#include <linux/pagemap.h>
@@ -18,6 +19,7 @@ struct kvm_gmem {
};
struct kvm_gmem_inode_info {
+ struct shared_policy policy;
struct inode vfs_inode;
};
@@ -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)
+{
+ struct mempolicy *mpol;
+
+ mpol = mpol_shared_policy_lookup(&info->policy, index);
+ return mpol ? mpol : get_task_policy(current);
+}
+#else
+static struct mempolicy *kvm_gmem_get_pgoff_policy(struct kvm_gmem_inode_info *info,
+ pgoff_t index)
+{
+ return NULL;
+}
+#endif /* CONFIG_NUMA */
+
static const struct vm_operations_struct kvm_gmem_vm_ops = {
- .fault = kvm_gmem_fault_user_mapping,
+ .fault = kvm_gmem_fault_user_mapping,
+#ifdef CONFIG_NUMA
+ .get_policy = kvm_gmem_get_policy,
+ .set_policy = kvm_gmem_set_policy,
+#endif
};
static int kvm_gmem_mmap(struct file *file, struct vm_area_struct *vma)
@@ -408,11 +468,14 @@ static struct inode *kvm_gmem_alloc_inode(struct super_block *sb)
if (!info)
return NULL;
+ mpol_shared_policy_init(&info->policy, NULL);
+
return &info->vfs_inode;
}
static void kvm_gmem_destroy_inode(struct inode *inode)
{
+ mpol_free_shared_policy(&KVM_GMEM_I(inode)->policy);
}
static void kvm_gmem_free_inode(struct inode *inode)
--
2.43.0
^ permalink raw reply related
* [PATCH RFC V10 5/7] KVM: guest_memfd: Add slab-allocated inode cache
From: Shivank Garg @ 2025-08-11 9:06 UTC (permalink / raw)
To: seanjc, david, vbabka, willy, akpm, shuah, pbonzini, brauner,
viro
Cc: ackerleytng, paul, jmorris, serge, pvorel, bfoster, tabba,
vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
jgg, kalyazin, peterx, shivankg, jack, rppt, hch, cgzones,
ira.weiny, rientjes, roypat, ziy, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, kent.overstreet, ying.huang,
apopple, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
quic_eberman, aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm,
linux-kernel, linux-security-module, kvm, linux-kselftest,
linux-coco
In-Reply-To: <20250811090605.16057-2-shivankg@amd.com>
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 | 69 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 67 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 0e93323fc839..d9c23401e770 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 {
+ struct inode vfs_inode;
+};
+
+static inline struct kvm_gmem_inode_info *KVM_GMEM_I(struct inode *inode)
+{
+ return container_of(inode, struct kvm_gmem_inode_info, vfs_inode);
+}
+
/**
* folio_file_pfn - like folio_file_page, but return a pfn.
* @folio: The folio which contains this index.
@@ -389,13 +398,46 @@ static struct file_operations kvm_gmem_fops = {
.fallocate = kvm_gmem_fallocate,
};
+static struct kmem_cache *kvm_gmem_inode_cachep;
+
+static struct inode *kvm_gmem_alloc_inode(struct super_block *sb)
+{
+ struct kvm_gmem_inode_info *info;
+
+ info = alloc_inode_sb(sb, kvm_gmem_inode_cachep, GFP_KERNEL);
+ if (!info)
+ return NULL;
+
+ return &info->vfs_inode;
+}
+
+static void kvm_gmem_destroy_inode(struct inode *inode)
+{
+}
+
+static void kvm_gmem_free_inode(struct inode *inode)
+{
+ kmem_cache_free(kvm_gmem_inode_cachep, KVM_GMEM_I(inode));
+}
+
+static const struct super_operations kvm_gmem_super_operations = {
+ .statfs = simple_statfs,
+ .alloc_inode = kvm_gmem_alloc_inode,
+ .destroy_inode = kvm_gmem_destroy_inode,
+ .free_inode = kvm_gmem_free_inode,
+};
+
static int kvm_gmem_init_fs_context(struct fs_context *fc)
{
+ struct pseudo_fs_context *ctx;
+
if (!init_pseudo(fc, GUEST_MEMFD_MAGIC))
return -ENOMEM;
fc->s_iflags |= SB_I_NOEXEC;
fc->s_iflags |= SB_I_NODEV;
+ ctx = fc->fs_private;
+ ctx->ops = &kvm_gmem_super_operations;
return 0;
}
@@ -417,17 +459,40 @@ static int kvm_gmem_init_mount(void)
return 0;
}
+static void kvm_gmem_init_inode(void *foo)
+{
+ struct kvm_gmem_inode_info *info = foo;
+
+ inode_init_once(&info->vfs_inode);
+}
+
int kvm_gmem_init(struct module *module)
{
- kvm_gmem_fops.owner = module;
+ int ret;
+ struct kmem_cache_args args = {
+ .align = 0,
+ .ctor = kvm_gmem_init_inode,
+ };
- return kvm_gmem_init_mount();
+ kvm_gmem_fops.owner = module;
+ kvm_gmem_inode_cachep = kmem_cache_create("kvm_gmem_inode_cache",
+ sizeof(struct kvm_gmem_inode_info),
+ &args, SLAB_ACCOUNT);
+ if (!kvm_gmem_inode_cachep)
+ return -ENOMEM;
+ ret = kvm_gmem_init_mount();
+ if (ret) {
+ kmem_cache_destroy(kvm_gmem_inode_cachep);
+ return ret;
+ }
+ return 0;
}
void kvm_gmem_exit(void)
{
kern_unmount(kvm_gmem_mnt);
kvm_gmem_mnt = NULL;
+ kmem_cache_destroy(kvm_gmem_inode_cachep);
}
static int kvm_gmem_migrate_folio(struct address_space *mapping,
--
2.43.0
^ permalink raw reply related
* [PATCH RFC V10 4/7] KVM: guest_memfd: Use guest mem inodes instead of anonymous inodes
From: Shivank Garg @ 2025-08-11 9:06 UTC (permalink / raw)
To: seanjc, david, vbabka, willy, akpm, shuah, pbonzini, brauner,
viro
Cc: ackerleytng, paul, jmorris, serge, pvorel, bfoster, tabba,
vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
jgg, kalyazin, peterx, shivankg, jack, rppt, hch, cgzones,
ira.weiny, rientjes, roypat, ziy, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, kent.overstreet, ying.huang,
apopple, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
quic_eberman, aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm,
linux-kernel, linux-security-module, kvm, linux-kselftest,
linux-coco
In-Reply-To: <20250811090605.16057-2-shivankg@amd.com>
From: Ackerley Tng <ackerleytng@google.com>
guest_memfd's inode represents memory the guest_memfd is
providing. guest_memfd's file represents a struct kvm's view of that
memory.
Using a custom inode allows customization of the inode teardown
process via callbacks. For example, ->evict_inode() allows
customization of the truncation process on file close, and
->destroy_inode() and ->free_inode() allow customization of the inode
freeing process.
Customizing the truncation process allows flexibility in management of
guest_memfd memory and customization of the inode freeing process
allows proper cleanup of memory metadata stored on the inode.
Memory metadata is more appropriately stored on the inode (as opposed
to the file), since the metadata is for the memory and is not unique
to a specific binding and struct kvm.
Co-developed-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Shivank Garg <shivankg@amd.com>
---
include/uapi/linux/magic.h | 1 +
virt/kvm/guest_memfd.c | 128 ++++++++++++++++++++++++++++++-------
virt/kvm/kvm_main.c | 7 +-
virt/kvm/kvm_mm.h | 9 +--
4 files changed, 118 insertions(+), 27 deletions(-)
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index bb575f3ab45e..638ca21b7a90 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -103,5 +103,6 @@
#define DEVMEM_MAGIC 0x454d444d /* "DMEM" */
#define SECRETMEM_MAGIC 0x5345434d /* "SECM" */
#define PID_FS_MAGIC 0x50494446 /* "PIDF" */
+#define GUEST_MEMFD_MAGIC 0x474d454d /* "GMEM" */
#endif /* __LINUX_MAGIC_H__ */
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 08a6bc7d25b6..0e93323fc839 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -1,12 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/anon_inodes.h>
#include <linux/backing-dev.h>
#include <linux/falloc.h>
+#include <linux/fs.h>
#include <linux/kvm_host.h>
+#include <linux/pseudo_fs.h>
#include <linux/pagemap.h>
-#include <linux/anon_inodes.h>
#include "kvm_mm.h"
+static struct vfsmount *kvm_gmem_mnt;
+
struct kvm_gmem {
struct kvm *kvm;
struct xarray bindings;
@@ -385,9 +389,45 @@ static struct file_operations kvm_gmem_fops = {
.fallocate = kvm_gmem_fallocate,
};
-void kvm_gmem_init(struct module *module)
+static int kvm_gmem_init_fs_context(struct fs_context *fc)
+{
+ if (!init_pseudo(fc, GUEST_MEMFD_MAGIC))
+ return -ENOMEM;
+
+ fc->s_iflags |= SB_I_NOEXEC;
+ fc->s_iflags |= SB_I_NODEV;
+
+ return 0;
+}
+
+static struct file_system_type kvm_gmem_fs = {
+ .name = "guest_memfd",
+ .init_fs_context = kvm_gmem_init_fs_context,
+ .kill_sb = kill_anon_super,
+};
+
+static int kvm_gmem_init_mount(void)
+{
+ kvm_gmem_mnt = kern_mount(&kvm_gmem_fs);
+
+ if (IS_ERR(kvm_gmem_mnt))
+ return PTR_ERR(kvm_gmem_mnt);
+
+ kvm_gmem_mnt->mnt_flags |= MNT_NOEXEC;
+ return 0;
+}
+
+int kvm_gmem_init(struct module *module)
{
kvm_gmem_fops.owner = module;
+
+ return kvm_gmem_init_mount();
+}
+
+void kvm_gmem_exit(void)
+{
+ kern_unmount(kvm_gmem_mnt);
+ kvm_gmem_mnt = NULL;
}
static int kvm_gmem_migrate_folio(struct address_space *mapping,
@@ -463,11 +503,71 @@ bool __weak kvm_arch_supports_gmem_mmap(struct kvm *kvm)
return true;
}
+static struct inode *kvm_gmem_inode_make_secure_inode(const char *name,
+ loff_t size, u64 flags)
+{
+ struct inode *inode;
+
+ inode = anon_inode_make_secure_inode(kvm_gmem_mnt->mnt_sb, name, NULL);
+ if (IS_ERR(inode))
+ return inode;
+
+ inode->i_private = (void *)(unsigned long)flags;
+ inode->i_op = &kvm_gmem_iops;
+ inode->i_mapping->a_ops = &kvm_gmem_aops;
+ inode->i_mode |= S_IFREG;
+ inode->i_size = size;
+ mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
+ mapping_set_inaccessible(inode->i_mapping);
+ /* Unmovable mappings are supposed to be marked unevictable as well. */
+ WARN_ON_ONCE(!mapping_unevictable(inode->i_mapping));
+
+ return inode;
+}
+
+static struct file *kvm_gmem_inode_create_getfile(void *priv, loff_t size,
+ u64 flags)
+{
+ static const char *name = "[kvm-gmem]";
+ struct inode *inode;
+ struct file *file;
+ int err;
+
+ err = -ENOENT;
+ if (!try_module_get(kvm_gmem_fops.owner))
+ goto err;
+
+ inode = kvm_gmem_inode_make_secure_inode(name, size, flags);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto err_put_module;
+ }
+
+ file = alloc_file_pseudo(inode, kvm_gmem_mnt, name, O_RDWR,
+ &kvm_gmem_fops);
+ if (IS_ERR(file)) {
+ err = PTR_ERR(file);
+ goto err_put_inode;
+ }
+
+ file->f_flags |= O_LARGEFILE;
+ file->private_data = priv;
+
+out:
+ return file;
+
+err_put_inode:
+ iput(inode);
+err_put_module:
+ module_put(kvm_gmem_fops.owner);
+err:
+ file = ERR_PTR(err);
+ goto out;
+}
+
static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags)
{
- const char *anon_name = "[kvm-gmem]";
struct kvm_gmem *gmem;
- struct inode *inode;
struct file *file;
int fd, err;
@@ -481,32 +581,16 @@ static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags)
goto err_fd;
}
- file = anon_inode_create_getfile(anon_name, &kvm_gmem_fops, gmem,
- O_RDWR, NULL);
+ file = kvm_gmem_inode_create_getfile(gmem, size, flags);
if (IS_ERR(file)) {
err = PTR_ERR(file);
goto err_gmem;
}
- file->f_flags |= O_LARGEFILE;
-
- inode = file->f_inode;
- WARN_ON(file->f_mapping != inode->i_mapping);
-
- inode->i_private = (void *)(unsigned long)flags;
- inode->i_op = &kvm_gmem_iops;
- inode->i_mapping->a_ops = &kvm_gmem_aops;
- inode->i_mode |= S_IFREG;
- inode->i_size = size;
- mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
- mapping_set_inaccessible(inode->i_mapping);
- /* Unmovable mappings are supposed to be marked unevictable as well. */
- WARN_ON_ONCE(!mapping_unevictable(inode->i_mapping));
-
kvm_get_kvm(kvm);
gmem->kvm = kvm;
xa_init(&gmem->bindings);
- list_add(&gmem->entry, &inode->i_mapping->i_private_list);
+ list_add(&gmem->entry, &file_inode(file)->i_mapping->i_private_list);
fd_install(fd, file);
return fd;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 18f29ef93543..301d48d6e00d 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -6489,7 +6489,9 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
if (WARN_ON_ONCE(r))
goto err_vfio;
- kvm_gmem_init(module);
+ r = kvm_gmem_init(module);
+ if (r)
+ goto err_gmem;
r = kvm_init_virtualization();
if (r)
@@ -6510,6 +6512,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
err_register:
kvm_uninit_virtualization();
err_virt:
+ kvm_gmem_exit();
+err_gmem:
kvm_vfio_ops_exit();
err_vfio:
kvm_async_pf_deinit();
@@ -6541,6 +6545,7 @@ void kvm_exit(void)
for_each_possible_cpu(cpu)
free_cpumask_var(per_cpu(cpu_kick_mask, cpu));
kmem_cache_destroy(kvm_vcpu_cache);
+ kvm_gmem_exit();
kvm_vfio_ops_exit();
kvm_async_pf_deinit();
kvm_irqfd_exit();
diff --git a/virt/kvm/kvm_mm.h b/virt/kvm/kvm_mm.h
index 31defb08ccba..9fcc5d5b7f8d 100644
--- a/virt/kvm/kvm_mm.h
+++ b/virt/kvm/kvm_mm.h
@@ -68,17 +68,18 @@ static inline void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm,
#endif /* HAVE_KVM_PFNCACHE */
#ifdef CONFIG_KVM_GUEST_MEMFD
-void kvm_gmem_init(struct module *module);
+int kvm_gmem_init(struct module *module);
+void kvm_gmem_exit(void);
int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args);
int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
unsigned int fd, loff_t offset);
void kvm_gmem_unbind(struct kvm_memory_slot *slot);
#else
-static inline void kvm_gmem_init(struct module *module)
+static inline int kvm_gmem_init(struct module *module)
{
-
+ return 0;
}
-
+static inline void kvm_gmem_exit(void) {};
static inline int kvm_gmem_bind(struct kvm *kvm,
struct kvm_memory_slot *slot,
unsigned int fd, loff_t offset)
--
2.43.0
^ permalink raw reply related
* [PATCH RFC V10 3/7] mm/mempolicy: Export memory policy symbols
From: Shivank Garg @ 2025-08-11 9:06 UTC (permalink / raw)
To: seanjc, david, vbabka, willy, akpm, shuah, pbonzini, brauner,
viro
Cc: ackerleytng, paul, jmorris, serge, pvorel, bfoster, tabba,
vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
jgg, kalyazin, peterx, shivankg, jack, rppt, hch, cgzones,
ira.weiny, rientjes, roypat, ziy, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, kent.overstreet, ying.huang,
apopple, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
quic_eberman, aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm,
linux-kernel, linux-security-module, kvm, linux-kselftest,
linux-coco
In-Reply-To: <20250811090605.16057-2-shivankg@amd.com>
KVM guest_memfd wants to implement support for NUMA policies just like
shmem already does using the shared policy infrastructure. As
guest_memfd currently resides in KVM module code, we have to export the
relevant symbols.
In the future, guest_memfd might be moved to core-mm, at which point the
symbols no longer would have to be exported. When/if that happens is
still unclear.
Acked-by: David Hildenbrand <david@redhat.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Shivank Garg <shivankg@amd.com>
---
mm/mempolicy.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index eb83cff7db8c..d385202306db 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -354,6 +354,7 @@ struct mempolicy *get_task_policy(struct task_struct *p)
return &default_policy;
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(get_task_policy, "kvm");
static const struct mempolicy_operations {
int (*create)(struct mempolicy *pol, const nodemask_t *nodes);
@@ -487,6 +488,7 @@ void __mpol_put(struct mempolicy *pol)
return;
kmem_cache_free(policy_cache, pol);
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(__mpol_put, "kvm");
static void mpol_rebind_default(struct mempolicy *pol, const nodemask_t *nodes)
{
@@ -2885,6 +2887,7 @@ struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,
read_unlock(&sp->lock);
return pol;
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(mpol_shared_policy_lookup, "kvm");
static void sp_free(struct sp_node *n)
{
@@ -3170,6 +3173,7 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
mpol_put(mpol); /* drop our incoming ref on sb mpol */
}
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(mpol_shared_policy_init, "kvm");
int mpol_set_shared_policy(struct shared_policy *sp,
struct vm_area_struct *vma, struct mempolicy *pol)
@@ -3188,6 +3192,7 @@ int mpol_set_shared_policy(struct shared_policy *sp,
sp_free(new);
return err;
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(mpol_set_shared_policy, "kvm");
/* Free a backing policy store on inode delete. */
void mpol_free_shared_policy(struct shared_policy *sp)
@@ -3206,6 +3211,7 @@ void mpol_free_shared_policy(struct shared_policy *sp)
}
write_unlock(&sp->lock);
}
+EXPORT_SYMBOL_GPL_FOR_MODULES(mpol_free_shared_policy, "kvm");
#ifdef CONFIG_NUMA_BALANCING
static int __initdata numabalancing_override;
--
2.43.0
^ permalink raw reply related
* [PATCH RFC V10 2/7] mm/filemap: Extend __filemap_get_folio() to support NUMA memory policies
From: Shivank Garg @ 2025-08-11 9:06 UTC (permalink / raw)
To: seanjc, david, vbabka, willy, akpm, shuah, pbonzini, brauner,
viro
Cc: ackerleytng, paul, jmorris, serge, pvorel, bfoster, tabba,
vannapurve, chao.gao, bharata, nikunj, michael.day, shdhiman,
yan.y.zhao, Neeraj.Upadhyay, thomas.lendacky, michael.roth, aik,
jgg, kalyazin, peterx, shivankg, jack, rppt, hch, cgzones,
ira.weiny, rientjes, roypat, ziy, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, kent.overstreet, ying.huang,
apopple, chao.p.peng, amit, ddutile, dan.j.williams, ashish.kalra,
gshan, jgowans, pankaj.gupta, papaluri, yuzhao, suzuki.poulose,
quic_eberman, aneeshkumar.kizhakeveetil, linux-fsdevel, linux-mm,
linux-kernel, linux-security-module, kvm, linux-kselftest,
linux-coco
In-Reply-To: <20250811090605.16057-2-shivankg@amd.com>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Extend __filemap_get_folio() to support NUMA memory policies by
renaming the implementation to __filemap_get_folio_mpol() and adding
a mempolicy parameter. The original function becomes a static inline
wrapper that passes NULL for the mempolicy.
This infrastructure will enable future support for NUMA-aware page cache
allocations in guest_memfd memory backend KVM guests.
Reviewed-by: Pankaj Gupta <pankaj.gupta@amd.com>
Reviewed-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Shivank Garg <shivankg@amd.com>
---
include/linux/pagemap.h | 10 ++++++++--
mm/filemap.c | 11 ++++++-----
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index ce617a35dc35..94d65ced0a1d 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -747,11 +747,17 @@ static inline fgf_t fgf_set_order(size_t size)
}
void *filemap_get_entry(struct address_space *mapping, pgoff_t index);
-struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
- fgf_t fgp_flags, gfp_t gfp);
+struct folio *__filemap_get_folio_mpol(struct address_space *mapping,
+ pgoff_t index, fgf_t fgf_flags, gfp_t gfp, struct mempolicy *policy);
struct page *pagecache_get_page(struct address_space *mapping, pgoff_t index,
fgf_t fgp_flags, gfp_t gfp);
+static inline struct folio *__filemap_get_folio(struct address_space *mapping,
+ pgoff_t index, fgf_t fgf_flags, gfp_t gfp)
+{
+ return __filemap_get_folio_mpol(mapping, index, fgf_flags, gfp, NULL);
+}
+
/**
* write_begin_get_folio - Get folio for write_begin with flags.
* @iocb: The kiocb passed from write_begin (may be NULL).
diff --git a/mm/filemap.c b/mm/filemap.c
index 495f7f5c3d2e..03f223be575c 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1897,11 +1897,12 @@ void *filemap_get_entry(struct address_space *mapping, pgoff_t index)
}
/**
- * __filemap_get_folio - Find and get a reference to a folio.
+ * __filemap_get_folio_mpol - Find and get a reference to a folio.
* @mapping: The address_space to search.
* @index: The page index.
* @fgp_flags: %FGP flags modify how the folio is returned.
* @gfp: Memory allocation flags to use if %FGP_CREAT is specified.
+ * @policy: NUMA memory allocation policy to follow.
*
* Looks up the page cache entry at @mapping & @index.
*
@@ -1912,8 +1913,8 @@ void *filemap_get_entry(struct address_space *mapping, pgoff_t index)
*
* Return: The found folio or an ERR_PTR() otherwise.
*/
-struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
- fgf_t fgp_flags, gfp_t gfp)
+struct folio *__filemap_get_folio_mpol(struct address_space *mapping,
+ pgoff_t index, fgf_t fgp_flags, gfp_t gfp, struct mempolicy *policy)
{
struct folio *folio;
@@ -1983,7 +1984,7 @@ struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
err = -ENOMEM;
if (order > min_order)
alloc_gfp |= __GFP_NORETRY | __GFP_NOWARN;
- folio = filemap_alloc_folio(alloc_gfp, order, NULL);
+ folio = filemap_alloc_folio(alloc_gfp, order, policy);
if (!folio)
continue;
@@ -2030,7 +2031,7 @@ struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
folio_clear_dropbehind(folio);
return folio;
}
-EXPORT_SYMBOL(__filemap_get_folio);
+EXPORT_SYMBOL(__filemap_get_folio_mpol);
static inline struct folio *find_get_entry(struct xa_state *xas, pgoff_t max,
xa_mark_t mark)
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox