mseal sysmap: Choose system mapping sealing at boot
Subsystems (6)
cover mseal sysmap: Choose system mapping sealing at boot
System mapping sealing is currently a build time choice. Hosts which want it and hosts which need to move or unmap these mappings therefore need separate kernels, which is not ideal. Let's allow the administrator to choose at boot time.
Chris Down (3):
mseal sysmap: Add mseal_system_mappings= boot parameter mseal sysmap: Allow with CHECKPOINT_RESTORE, default off selftests/mseal_system_mappings: Test vdso unmap and remap
.../admin-guide/kernel-parameters.txt | 7 + Documentation/userspace-api/mseal.rst | 5 +- include/linux/mm.h | 3 +- mm/mseal.c | 13 + security/Kconfig | 17 +- .../selftests/mseal_system_mappings/Makefile | 2 + .../selftests/mseal_system_mappings/config | 2 + .../mseal_system_mappings/sysmap_is_sealed.c | 236 ++++++++++++++++-- 8 files changed, 268 insertions(+), 17 deletions(-)
base-commit: bae9a042b03b27924c6fd5bdc00a20d6a44d6041
Signature · 1 line
2.54.0
PATCH 1/3 mseal sysmap: Add mseal_system_mappings= boot parameter
CONFIG_MSEAL_SYSTEM_MAPPINGS seals each process' system mappings when they are created. As it is today this can only be toggled at build time, so hosts that need sealing and hosts running software which moves or unmaps these mappings end up with separate kernels. This is not ideal since it adds more complexity of deployment, it would be great to be able to have one kernel which can configurably do both.
So, to improve this, let's add mseal_system_mappings= so that this can be chosen at boot.
--- .../admin-guide/kernel-parameters.txt | 7 ++ Documentation/userspace-api/mseal.rst | 3 +- include/linux/mm.h | 3 +- mm/mseal.c | 12 ++ security/Kconfig | 2 + .../mseal_system_mappings/sysmap_is_sealed.c | 104 +++++++++++++++--- 6 files changed, 115 insertions(+), 16 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +7 -0
@@ -4270,6 +4270,13 @@ Kernel parameters MTD_Region= [MTD] Format: <name>,<region-number>[,<base>,<size>,<buswidth>,<altbuswidth>] + mseal_system_mappings= + [KNL,EARLY] Under CONFIG_MSEAL_SYSTEM_MAPPINGS, + whether system mappings are sealed for this boot. + See Documentation/userspace-api/mseal.rst. + Format: <bool> + Default: 1 (enabled). + mtdparts= [MTD] See drivers/mtd/parsers/cmdlinepart.c
Documentation/userspace-api/mseal.rst +2 -1
@@ -142,7 +142,8 @@ Use cases If supported by an architecture (CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS), the CONFIG_MSEAL_SYSTEM_MAPPINGS seals all system mappings of this - architecture. + architecture. The kernel command line parameter + ``mseal_system_mappings=0`` turns this off at boot. WARNING: This feature breaks programs which rely on relocating or unmapping system mappings. Known broken software at the time
include/linux/mm.h +2 -1
@@ -568,7 +568,8 @@ enum {#define VM_STACK_FLAGS vma_flags_to_legacy(VMA_STACK_FLAGS)#ifdef CONFIG_MSEAL_SYSTEM_MAPPINGS -#define VM_SEALED_SYSMAP VM_SEALED +extern bool mseal_sysmap_enabled; +#define VM_SEALED_SYSMAP (mseal_sysmap_enabled ? VM_SEALED : VM_NONE)#else #define VM_SEALED_SYSMAP VM_NONE#endif
mm/mseal.c +12 -0
@@ -7,6 +7,8 @@* Author: Jeff Xu <[email protected]> */ +#include <linux/init.h> +#include <linux/kstrtox.h> #include <linux/mempolicy.h> #include <linux/minmax.h> #include <linux/mman.h>
@@ -16,6 +18,16 @@#include <linux/sched.h> #include "internal.h" +#ifdef CONFIG_MSEAL_SYSTEM_MAPPINGS +bool mseal_sysmap_enabled__ro_after_init = true; + +static int __init early_mseal_sysmap (char *buf) +{ +return kstrtobool (buf, &mseal_sysmap_enabled); +} +early_param ("mseal_system_mappings" , early_mseal_sysmap); +#endif +static bool range_contains_unmapped (unsigned long start,unsigned long end) {VMA_ITERATOR (vmi, current->mm, start);
security/Kconfig +2 -0
@@ -67,6 +67,8 @@ config MSEAL_SYSTEM_MAPPINGS of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore this config can't be enabled universally. + Sealing can be turned off at boot with "mseal_system_mappings=0". + For complete descriptions of memory sealing, please see Documentation/userspace-api/mseal.rst
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +90 -14
175 lines not on this page · raw message
Signature · 1 line
2.54.0
Lorenzo Stoakes (ARM)
maintainerRe: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
The existing implementation is a bit of a mess, so any work that extends it has to put in the work to improve things first.
I _hate_ VM_SEALED_SYSMAP. It's a hack. A tasteful way of doing this is really required for a series touching this to be taken, honestly.
See below for implementation ideas.
(Also it's the merge window, so no more revisions until -rc1, when you need to resend, thanks.)
Quoted 6 lines · Chris Down
CONFIG_MSEAL_SYSTEM_MAPPINGSseals each process' system mappings when they are created. As it is today this can only be toggled at build time, so hosts that need sealing and hosts running software which moves or unmaps these mappings end up with separate kernels. This is not ideal since it adds more complexity of deployment, it would be great to be able to have one kernel which can configurably do both.
Could we have some actual justification for the use of the feature please? So far I've seen arm-waving.
Quoted 19 lines
So, to improve this, let's add mseal_system_mappings= so that this can be chosen at boot.
Signed-off-by Chris Down <[email protected]>--- .../admin-guide/kernel-parameters.txt | 7 ++ Documentation/userspace-api/mseal.rst | 3 +- include/linux/mm.h | 3 +- mm/mseal.c | 12 ++ security/Kconfig | 2 + .../mseal_system_mappings/sysmap_is_sealed.c | 104 +++++++++++++++--- 6 files changed, 115 insertions(+), 16 deletions(-)Documentation/admin-guide/kernel-parameters.txt +0
-0
Documentation/admin-guide/kernel-parameters.txt Kernel parameters · line 4278
Quoted 9 lines
Documentation/admin-guide/kernel-parameters.txt +6
-0@@ -4270,6 +4270,13 @@ Kernel parameters MTD_Region= [MTD] Format: <name>,<region-number>[,<base>,<size>,<buswidth>,<altbuswidth>] + mseal_system_mappings= + [KNL,EARLY] Under CONFIG_MSEAL_SYSTEM_MAPPINGS, + whether system mappings are sealed for this boot. + See Documentation/userspace-api/mseal.rst. + Format: <bool> + Default: 1 (enabled).
You _have_ to duplicate the list of things this breaks here please.
Quoted 9 lines
Documentation/admin-guide/kernel-parameters.txt +1
-0+ mtdparts= [MTD] See drivers/mtd/parsers/cmdlinepart.cDocumentation/userspace-api/mseal.rst +0
-0
Documentation/userspace-api/mseal.rst Use cases · line 146
Quoted 6 lines
Documentation/userspace-api/mseal.rst +2
-1@@ -142,7 +142,8 @@ Use cases If supported by an architecture (CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS), the CONFIG_MSEAL_SYSTEM_MAPPINGS seals all system mappings of this - architecture. + architecture. The kernel command line parameter + ``mseal_system_mappings=0`` turns this off at boot.
This is just really confusing.
Adding a flag that defaults to on but only defaults to on if the config option is enabled...
Let's just refactor this properly to stop abusing a 'VMA flag' (which is really not a VMA flag, but an alias).
Let's negate things first. Make the boot flag 'no_mseal_sys_mappings' rather than confusingly implying mseal_system_mappings=1 could enable it even with a config option not provided.
Then add something like:
static inline bool mseal_system_mappings(void)
{
return IS_ENABLED(CONFIG_MSEAL_SYSTEM_MAPPINGS) &&
!mseal_system_mappings_disabled;
}And call that in _install_special_mapping().
The LLM overlords tell me that only uprobe trampolines would see a delta from this given the ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS restriction.
This would improve things a lot.
Quoted 8 lines
Documentation/userspace-api/mseal.rst +0
-0WARNING: This feature breaks programs which rely on relocating or unmapping system mappings. Known broken software at the timeinclude/linux/mm.h +0
-0
include/linux/mm.h enum { · line 572
Quoted 6 lines
include/linux/mm.h +2
-1@@ -568,7 +568,8 @@ enum {#define VM_STACK_FLAGS vma_flags_to_legacy(VMA_STACK_FLAGS)#ifdef CONFIG_MSEAL_SYSTEM_MAPPINGS -#define VM_SEALED_SYSMAP VM_SEALED +extern bool mseal_sysmap_enabled; +#define VM_SEALED_SYSMAP (mseal_sysmap_enabled ? VM_SEALED : VM_NONE)
No, you don't use the legacy VMA flags API for new work. Sorry.
See above as to a pointer as to how this should look.
Quoted 17 lines
include/linux/mm.h +0
-0#else #define VM_SEALED_SYSMAP VM_NONE#endif mm/mseal.c +2
-0@@ -7,6 +7,8 @@* Author: Jeff Xu <[email protected]> */ +#include <linux/init.h> +#include <linux/kstrtox.h> #include <linux/mempolicy.h> #include <linux/minmax.h> #include <linux/mman.h>
mm/mseal.c line 22
Quoted 5 lines
mm/mseal.c +2
-0@@ -16,6 +18,16 @@#include <linux/sched.h> #include "internal.h" +#ifdef CONFIG_MSEAL_SYSTEM_MAPPINGS +bool mseal_sysmap_enabled__ro_after_init = true;
See above re: rework of this.
Quoted 16 lines
mm/mseal.c +8
-0+ +static int __init early_mseal_sysmap (char *buf) +{ +return kstrtobool (buf, &mseal_sysmap_enabled); +} +early_param ("mseal_system_mappings" , early_mseal_sysmap); +#endif +static bool range_contains_unmapped (unsigned long start,unsigned long end) {VMA_ITERATOR (vmi, current->mm, start);security/Kconfig +0
-0
security/Kconfig config MSEAL_SYSTEM_MAPPINGS · line 71
Quoted 5 lines
security/Kconfig +2
-0@@ -67,6 +67,8 @@ config MSEAL_SYSTEM_MAPPINGS of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore this config can't be enabled universally. + Sealing can be turned off at boot with "mseal_system_mappings=0". +
'With this configuration option set, sealing can...' right now this reads a little like it's defaulted on.
Also can we move this Kconfig option out of security and into mm please? This is explicitly an mm feature, and it should never have been added there (mm needs to know if somebody sets this default=y or something for instance).
In any case, as above, no_mseal_sys_mappings is probably a better way, then this becomes something like:
"With this configuration option set, the feature can be disabled with the no_mseal_sys_mappings boot parameter.'
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c
Quoted 7 lines
security/Kconfig +0
-0For complete descriptions of memory sealing, please see Documentation/userspace-api/mseal.rsttools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +0
-0
Tests as separate commits please.
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c line 4
Quoted 7 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +1
-2@@ -1,12 +1,12 @@// SPDX-License-Identifier: GPL-2.0-only /* -* test system mappings are sealed when -* KCONFIG_MSEAL_SYSTEM_MAPPINGS=y +* Test system mapping sealing and the mseal_system_mappings= boot parameter. */
Can we have test changes as separate commits please.
Quoted 69 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +58
-0#define _GNU_SOURCE#include <stdio.h> #include <errno.h> +#include <ctype.h> #include <unistd.h> #include <string.h> #include <stdbool.h> @@ -17,6 +17,73 @@#define VMFLAGS "VmFlags:"#define MSEAL_FLAGS "sl"#define MAX_LINE_LEN 512 +#define SYSMAP_PARAM "mseal_system_mappings=" + +static int parse_bool (const char *s,bool *res) +{ +if (!s) +return -EINVAL ; + +switch (tolower ((unsigned char )s[0 ])) { +case 'e' : +case 'y' : +case 't' : +case '1' : + *res = true; +return 0 ; +case 'd' : +case 'n' : +case 'f' : +case '0' : + *res = false; +return 0 ; +case 'o' : +switch (tolower ((unsigned char )s[1 ])) { +case 'n' : + *res = true; +return 0 ; +case 'f' : + *res = false; +return 0 ; + } +break ; + } + +return -EINVAL ; +} + +static int sysmap_sealed_expected (void ) +{ +char cmdline[4096 ], *tok, *save; +int sealed =1 ; +bool value; +size_t len; +FILE *f; + + f =fopen ("/proc/cmdline" ,"r" ); +if (!f) +return -1 ; + len =fread (cmdline,1 ,sizeof (cmdline) -1 , f); +if (ferror (f) || !feof (f)) { +fclose (f); +return -1 ; + } +fclose (f); + cmdline[len] ='\0' ; + +for (tok =strtok_r (cmdline," \t\n" , &save); tok; + tok =strtok_r (NULL ," \t\n" , &save)) { +if (!strcmp (tok,"--" ))
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c line 86
Quoted 10 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +10
-0+break ; +if (strncmp (tok,SYSMAP_PARAM ,strlen (SYSMAP_PARAM ))) +continue ; + +if (!parse_bool (tok +strlen (SYSMAP_PARAM ), &value)) + sealed = value; + } + +return sealed; +}
This seems total overkill, you're checking whether a boot parameter works?
Quoted 95 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +21
-13bool has_mapping (char *name,FILE *maps) {@@ -30,7 +97,7 @@ bool has_mapping(char *name, FILE *maps)return false; } -bool mapping_is_sealed (char *name,FILE *maps) +int mapping_is_sealed (FILE *maps) {char line[MAX_LINE_LEN ];@@ -43,7 +110,7 @@ bool mapping_is_sealed(char *name, FILE *maps) } } -return false; +return -1 ; }FIXTURE (basic) {@@ -67,53 +134,62 @@ FIXTURE_TEARDOWN(basic)FIXTURE_VARIANT (basic) {char *name; -bool sealed; +bool sysmap; }; FIXTURE_VARIANT_ADD(basic, vdso) { .name = "[vdso]", - .sealed = true, + .sysmap = true, }; FIXTURE_VARIANT_ADD(basic, vvar) { .name ="[vvar]" , - .sealed = true, + .sysmap = true, }; FIXTURE_VARIANT_ADD(basic, vvar_vclock) { .name ="[vvar_vclock]" , - .sealed = true, + .sysmap = true, }; FIXTURE_VARIANT_ADD(basic, sigpage) { .name ="[sigpage]" , - .sealed = true, + .sysmap = true, }; FIXTURE_VARIANT_ADD(basic, vectors) { .name ="[vectors]" , - .sealed = true, + .sysmap = true, }; FIXTURE_VARIANT_ADD(basic, uprobes) { .name ="[uprobes]" , - .sealed = true, + .sysmap = true, }; FIXTURE_VARIANT_ADD(basic, stack) { .name ="[stack]" , - .sealed = false, + .sysmap = false, }; TEST_F(basic, check_sealed) { +int expected =0 , sealed; +if (!has_mapping (variant->name, self->maps)) {SKIP (return,"could not find the mapping, %s" , variant->name); } -EXPECT_EQ (variant->sealed, -mapping_is_sealed (variant->name, self->maps)); + sealed =mapping_is_sealed (self->maps); +if (sealed <0 ) +SKIP (return,"could not read the mapping's sealing state" ); +if (variant->sysmap) { + expected =sysmap_sealed_expected (); +if (expected <0 ) +SKIP (return,"could not determine the expected sealing state" ); + } +EXPECT_EQ (expected, sealed); };TEST_HARNESS_MAIN --
Quoted 2 lines
2.54.0
--
Cheers, Lorenzo
Re: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
Hi Lorenzo,
Thanks for the quick and thorough review!
Quoted 7 lines · Lorenzo Stoakes (ARM)
The existing implementation is a bit of a mess, so any work that extends it has to put in the work to improve things first.
I _hate_
VM_SEALED_SYSMAP. It's a hack. A tasteful way of doing this is really required for a series touching this to be taken, honestly.See below for implementation ideas.
That's fair, I'll do the cleanup first in v2.
Quoted 2 lines
(Also it's the merge window, so no more revisions until -rc1, when you need to resend, thanks.)
Sure, I'll wait until after -rc1.
Quoted 2 lines
Could we have some actual justification for the use of the feature please? So far I've seen arm-waving.
Sure. At Meta, we build sealing into the kernel for our VM hosts, and we'd like it on as much of the rest of the fleet as possible. The problem is that the rest of the fleet also runs things which it breaks. Just as one example among many, Reverie (which Hermit our deterministic execution tool is built on) patches the vDSO of the processes it traces by injecting an mprotect()[0].
So right now the hosts which want sealing need their own kernel image, and this option is one of the things which forces that. We're working towards hopefully running one kernel across the fleet, and with a boot parameter we can build it with CONFIG_MSEAL_SYSTEM_MAPPINGS=y, keep sealing on by default, and turn it off only on the hosts which run those tools.
Let me know if you'd like more information. I can also put that in the commit message for v2.
0: https://docs.rs/reverie-core/latest/reverie/vdso/index.html
Quoted 8 lines
Quoted 8 lines
Documentation/admin-guide/kernel-parameters.txt +0
-0@@ -4270,6 +4270,13 @@ Kernel parameters MTD_Region= [MTD] Format: <name>,<region-number>[,<base>,<size>,<buswidth>,<altbuswidth>]
Quoted 8 lines
Documentation/admin-guide/kernel-parameters.txt Kernel parameters · line 4278
Quoted 6 lines
Documentation/admin-guide/kernel-parameters.txt +6
-0+ mseal_system_mappings= + [KNL,EARLY] Under CONFIG_MSEAL_SYSTEM_MAPPINGS, + whether system mappings are sealed for this boot. + See Documentation/userspace-api/mseal.rst. + Format: <bool> + Default: 1 (enabled).You _have_ to duplicate the list of things this breaks here please.
Will do.
Quoted 6 lines
Let's negate things first. Make the boot flag '
no_mseal_sys_mappings' rather than confusingly implying mseal_system_mappings=1 could enable it even with a config option not provided.Then add something like:
Quoted 7 lines
static inline bool
mseal_system_mappings(void){ return IS_ENABLED(CONFIG_MSEAL_SYSTEM_MAPPINGS) && !mseal_system_mappings_disabled; }And call that in
_install_special_mapping().
Makes sense. I'll call it in __install_special_mapping(), since that's where we already have a vma_flags_t, so it can just set VMA_SEALED_BIT without going near the legacy flags at all, if that sounds good? Then VM_SEALED_SYSMAP and all of its users can hopefully go away.
Quoted 4 lines
The LLM overlords tell me that only uprobe trampolines would see a delta from this given the
ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGSrestriction.This would improve things a lot.
Yes, but there is a wrinkle. Since 07c308eb2bcf ("uprobes/x86: Do not leak trampoline vma mapping on optimization failure"), __arch_uprobe_optimize() unmaps a trampoline it has just created if swbp_optimize() fails, and with the trampoline sealed that would now fail with -EPERM. I can see two ways to deal with that:
One is to seal trampolines too, and just leave a sealed trampoline in place on that path. It's already a WARN_ON_ONCE(), and get_uprobe_trampoline() reuses any trampoline which is in reach, so nothing is really leaked.
Another way would be to keep trampolines unsealed, but that means bringing back some kind of per-mapping opt-in, which is exactly what we're trying to get rid of.
What do you think? Either way I'll Cc Jiri and Oleg on it.
Quoted 5 lines
Documentation/admin-guide/kernel-parameters.txt Kernel parameters · line 4279
Quoted 1 line
Documentation/admin-guide/kernel-parameters.txt +1
-0+#define VM_SEALED_SYSMAP (mseal_sysmap_enabled ? VM_SEALED : VM_NONE)No, you don't use the legacy VMA flags API for new work. Sorry.
See above as to a pointer as to how this should look.
Sure thing.
Quoted 17 lines
security/Kconfig config MSEAL_SYSTEM_MAPPINGS · line 71
Quoted 13 lines
Documentation/admin-guide/kernel-parameters.txt +0
-0static bool range_contains_unmapped(unsigned long start, unsigned long end) { VMA_ITERATOR(vmi, current->mm, start);security/Kconfig +2
-0@@ -67,6 +67,8 @@ config MSEAL_SYSTEM_MAPPINGS of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore this config can't be enabled universally. + Sealing can be turned off at boot with "mseal_system_mappings=0". +'With this configuration option set, sealing can...' right now this reads a little like it's defaulted on.
Quoted 4 lines
Also can we move this
Kconfigoption out of security and into mm please? This is explicitly an mm feature, and it should never have been added there (mm needs to know if somebody sets this default=y or something for instance).
Sure thing.
Quoted 1 line
Tests as separate commits please.
Happy to do so, but aren't you worried about bisect safety? Or would you suggest another way?
Quoted 1 line
This seems total overkill, you're checking whether a boot parameter works?
It was mostly there so that the existing test wouldn't fail when booted with mseal_system_mappings=0, which meant parsing a bool. With a negated flag it can be a lot simpler, but I'm not sure which of these you'd prefer:
One option is to skip if [vdso] isn't sealed, and otherwise expect all system mappings to be sealed. Then there's parsing at all, and it also stops failing on kernels built without CONFIG_MSEAL_SYSTEM_MAPPINGS, which matters more once it's in run_vmtests.sh. The downside is that it can't notice sealing being broken entirely.
Another is to check /proc/cmdline for no_mseal_sys_mappings and expect the mappings to be unsealed if it's there. That's only a few lines now, but the test still fails on kernels without the option, as it does today.
Do you have a preference between the two?
Thanks a lot for the review!
Lorenzo Stoakes (ARM)
maintainerRe: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
Quoted 3 lines · Chris Down
Hi Lorenzo,
Thanks for the quick and thorough review!
No worries!
Quoted 11 lines
Quoted 7 lines · Lorenzo Stoakes (ARM)
The existing implementation is a bit of a mess, so any work that extends it has to put in the work to improve things first.
I _hate_
VM_SEALED_SYSMAP. It's a hack. A tasteful way of doing this is really required for a series touching this to be taken, honestly.See below for implementation ideas.
That's fair, I'll do the cleanup first in v2.
Thanks!
Quoted 5 lines
Quoted 3 lines
(Also it's the merge window, so no more revisions until -rc1, when you need to resend, thanks.)
Sure, I'll wait until after -rc1.
Yup :) we are a bit inundated with AI fixes these days.
Quoted 11 lines
Quoted 3 lines
Could we have some actual justification for the use of the feature please? So far I've seen arm-waving.
Sure. At Meta, we build sealing into the kernel for our VM hosts, and we'd like it on as much of the rest of the fleet as possible. The problem is that the rest of the fleet also runs things which it breaks. Just as one example among many, Reverie (which Hermit our deterministic execution tool is built on) patches the vDSO of the processes it traces by injecting an mprotect()[0].
Quoted 8 lines
So right now the hosts which want sealing need their own kernel image, and this option is one of the things which forces that. We're working towards hopefully running one kernel across the fleet, and with a boot parameter we can build it with
CONFIG_MSEAL_SYSTEM_MAPPINGS=y, keep sealing on by default, and turn it off only on the hosts which run those tools.Let me know if you'd like more information. I can also put that in the commit message for v2.
Great, thanks for the background! Yeah it'd be good to include all that!
I guess I'm fishing for the security justification, but maybe that ship sailed :) but it'd be helpful to also include that.
Quoted 20 lines
0: https://docs.rs/reverie-core/latest/reverie/vdso/index.html
Quoted 8 lines
Quoted 8 lines
Documentation/admin-guide/kernel-parameters.txt +0
-0@@ -4270,6 +4270,13 @@ Kernel parameters MTD_Region= [MTD] Format: <name>,<region-number>[,<base>,<size>,<buswidth>,<altbuswidth>]Quoted 8 lines
Documentation/admin-guide/kernel-parameters.txt Kernel parameters · line 4278
Quoted 6 lines
Documentation/admin-guide/kernel-parameters.txt +6
-0+ mseal_system_mappings= + [KNL,EARLY] Under CONFIG_MSEAL_SYSTEM_MAPPINGS, + whether system mappings are sealed for this boot. + See Documentation/userspace-api/mseal.rst. + Format: <bool> + Default: 1 (enabled).You _have_ to duplicate the list of things this breaks here please.
Quoted 1 line
Will do.
Thanks!
Quoted 13 lines
Quoted 13 lines
Let's negate things first. Make the boot flag '
no_mseal_sys_mappings' rather than confusingly implying mseal_system_mappings=1 could enable it even with a config option not provided.Then add something like:
static inline bool
mseal_system_mappings(void){ return IS_ENABLED(CONFIG_MSEAL_SYSTEM_MAPPINGS) && !mseal_system_mappings_disabled; }
Quoted 6 lines
Quoted 1 line
And call that in
_install_special_mapping().Makes sense. I'll call it in
__install_special_mapping(), since that's where we already have avma_flags_t, so it can just setVMA_SEALED_BITwithout going near the legacy flags at all, if that sounds good? ThenVM_SEALED_SYSMAPand all of its users can hopefully go away.
Yeah I typo'd that haha, doh! And it just happens to be a function :) yes __install_special_mapping().
Quoted 16 lines
Quoted 5 lines
The LLM overlords tell me that only uprobe trampolines would see a delta from this given the
ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGSrestriction.This would improve things a lot.
Yes, but there is a wrinkle. Since
07c308eb2bcf("uprobes/x86: Do not leak trampoline vma mapping on optimization failure"),__arch_uprobe_optimize()unmaps a trampoline it has just created ifswbp_optimize()fails, and with the trampoline sealed that would now fail with-EPERM. I can see two ways to deal with that:One is to seal trampolines too, and just leave a sealed trampoline in place on that path. It's already a
WARN_ON_ONCE(), andget_uprobe_trampoline()reuses any trampoline which is in reach, so nothing is really leaked.
Quoted 5 lines
Another way would be to keep trampolines unsealed, but that means bringing back some kind of per-mapping opt-in, which is exactly what we're trying to get rid of.
What do you think? Either way I'll Cc Jiri and Oleg on it.
I think the easiest would be to just seal them too.
Quoted 8 lines
Quoted 6 lines
Documentation/admin-guide/kernel-parameters.txt Kernel parameters · line 4279
Quoted 2 lines
Documentation/admin-guide/kernel-parameters.txt +1
-0+#define VM_SEALED_SYSMAP (mseal_sysmap_enabled ? VM_SEALED : VM_NONE)No, you don't use the legacy VMA flags API for new work. Sorry.
See above as to a pointer as to how this should look.
Sure thing.
Thanks, but with the proposed alternative approach, we can just yeet this from the code anyway! :)
Quoted 18 lines
Quoted 18 lines
Quoted 9 lines
Documentation/admin-guide/kernel-parameters.txt +0
-0static bool range_contains_unmapped(unsigned long start, unsigned long end) { VMA_ITERATOR(vmi, current->mm, start);security/Kconfig +0
-0security/Kconfig config MSEAL_SYSTEM_MAPPINGS · line 71
Quoted 5 lines
security/Kconfig +2
-0@@ -67,6 +67,8 @@ config MSEAL_SYSTEM_MAPPINGS of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore this config can't be enabled universally. + Sealing can be turned off at boot with "mseal_system_mappings=0". +'With this configuration option set, sealing can...' right now this reads a little like it's defaulted on.
Quoted 6 lines
Quoted 4 lines
Also can we move this
Kconfigoption out of security and into mm please? This is explicitly an mm feature, and it should never have been added there (mm needs to know if somebody sets this default=y or something for instance).Sure thing.
Thank!
Quoted 18 lines
Quoted 2 lines
Tests as separate commits please.
Happy to do so, but aren't you worried about bisect safety? Or would you suggest another way?
Quoted 1 line
This seems total overkill, you're checking whether a boot parameter works?
It was mostly there so that the existing test wouldn't fail when booted with mseal_system_mappings=0, which meant parsing a bool. With a negated flag it can be a lot simpler, but I'm not sure which of these you'd prefer:
One option is to skip if [vdso] isn't sealed, and otherwise expect all system mappings to be sealed. Then there's parsing at all, and it also stops failing on kernels built without
CONFIG_MSEAL_SYSTEM_MAPPINGS, which matters more once it's inrun_vmtests.sh. The downside is that it can't notice sealing being broken entirely.
Quoted 6 lines
Another is to check
/proc/cmdlineforno_mseal_sys_mappingsand expect the mappings to be unsealed if it's there. That's only a few lines now, but the test still fails on kernels without the option, as it does today.Do you have a preference between the two?
Yeah it's awkward, really moving the tests to mm we'd have to skip them if the vdso isn't sealed, then assume a sealed vdso for a new process = feature enabled.
I guess at that point it's redundant to check if disabled?
Quoted 1 line
Thanks a lot for the review!
No worries!
--
Cheers, Lorenzo
Re: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
Hi Chris, Lorenzo,
Quoted 12 lines · Lorenzo Stoakes (ARM)
Quoted 12 lines
One option is to skip if [vdso] isn't sealed, and otherwise expect all system mappings to be sealed. Then there's parsing at all, and it also stops failing on kernels built without
CONFIG_MSEAL_SYSTEM_MAPPINGS, which matters more once it's inrun_vmtests.sh. The downside is that it can't notice sealing being broken entirely.Another is to check
/proc/cmdlineforno_mseal_sys_mappingsand expect the mappings to be unsealed if it's there. That's only a few lines now, but the test still fails on kernels without the option, as it does today.
Quoted 7 lines
Quoted 1 line
Do you have a preference between the two?
Yeah it's awkward, really moving the tests to mm we'd have to skip them if the vdso isn't sealed, then assume a sealed vdso for a new process = feature enabled.
I guess at that point it's redundant to check if disabled?
Thanks for working on this series!
Could we please keep the test coverage for the unsealed [vdso] case and avoid unconditionally skipping whenever [vdso] is unsealed?
There are two regressions I'd love for us to still be able to catch:
1. Kernel or config regressions when sealing is expected to be on:
Distros/platforms such as ChromeOS and Android enable CONFIG_MSEAL_SYSTEM_MAPPINGS=y. Originally this test lived in its own selftest directory with CONFIG_MSEAL_SYSTEM_MAPPINGS=y in its config fragment specifically so that if a kernel change accidentally broke system mapping sealing completely, [vdso] being unsealed would trigger a hard FAIL rather than silently turning into a SKIP in CI (whereas run_vmtests.sh runs on kernels with MSEAL_SYSTEM_MAPPINGS=n).
2. Regressions in the new no_mseal_sys_mappings boot parameter itself:
When booted with no_mseal_sys_mappings (or when unsealed), running the assertions in Patch 3 (verifying system mappings have no sl flag and that munmap() / mremap() -- and ideally mprotect(PROT_READ | PROT_WRITE) -- on [vdso] succeed) directly verifies that the boot parameter works and doesn't regress.
If we move the test into tools/testing/selftests/mm/, perhaps we could:
- Check /proc/cmdline for no_mseal_sys_mappings and actively test the unsealed behavior when it is set (rather than skipping), and
- Either enable CONFIG_MSEAL_SYSTEM_MAPPINGS=y in selftests/mm/config, or keep strict failure as an option (e.g. ./sysmap_is_sealed fails if unsealed without the boot param, while run_vmtests.sh passes a flag like --allow-disabled when CONFIG_MSEAL_SYSTEM_MAPPINGS may not be enabled), so CI environments that expect sealing still catch a broken seal.
Thanks,
Jeff
Re: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
Hi Jeff,
Thanks for the review!
Quoted 6 lines · Jeff Xu
Could we please keep the test coverage for the unsealed [vdso] case and avoid unconditionally skipping whenever [vdso] is unsealed?
There are two regressions I'd love for us to still be able to catch:
1. Kernel or config regressions when sealing is expected to be on:
Yeah agreed. With the cleanup it matters even more I think because when sealing is set in one place the most likely regression is probably one that unseals everything at once.
Quoted 1 line
2. Regressions in the new
no_mseal_sys_mappingsboot parameter itself:
In v2 I can check /proc/cmdline for no_mseal_sys_mappings to do that.
Lorenzo, I think that also may inform your question about whether checking for the disabled case is redundant, right?
Quoted 5 lines
When booted with
no_mseal_sys_mappings(or when unsealed), running the assertions in Patch 3 (verifying system mappings have noslflag and thatmunmap()/mremap()-- and ideallymprotect(PROT_READ | PROT_WRITE)-- on [vdso] succeed) directly verifies that the boot parameter works and doesn't regress.
Sounds good.
Quoted 5 lines
or keep strict failure as an option (e.g.
./sysmap_is_sealedfails if unsealed without the boot param, whilerun_vmtests.shpasses a flag like--allow-disabledwhenCONFIG_MSEAL_SYSTEM_MAPPINGSmay not be enabled), so CI environments that expect sealing still catch a broken seal.
I like this and I think we can do it without adding some of the complexity that Lorenzo was not so happy about:
- Have check_sealed skip as usual when [vdso] isn't sealed and param is not set
- A new test, say expect_sealed, fails in the same case
- run_vmtests runs with -T expect_sealed when CONFIG_MSEAL_SYSTEM_MAPPINGS=y
That should be pretty minimal. Lorenzo, Jeff, how does that sound?
Re: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
Quoted 1 line · Chris Down
-
run_vmtestsruns with -Texpect_sealedwhenCONFIG_MSEAL_SYSTEM_MAPPINGS=y
Er, the other way around. I meant vm_runtests passes -T expect_sealed _unless_ CONFIG_MSEAL_SYSTEM_MAPPINGS=y.
Re: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
Hi Chris,
Quoted 9 lines · Chris Down
Quoted 5 lines · Chris Down
- Have
check_sealedskip as usual when [vdso] isn't sealed and param is not set
- A new test, sayexpect_sealed, fails in the same case
-run_vmtestsruns with -Texpect_sealedwhenCONFIG_MSEAL_SYSTEM_MAPPINGS=yEr, the other way around. I meant
vm_runtestspasses -Texpect_sealed_unless_CONFIG_MSEAL_SYSTEM_MAPPINGS=y.
Using kselftest_harness's -T expect_sealed together with checking /proc/cmdline for no_mseal_sys_mappings in check_sealed sounds great to me -- very clean and covers both regression cases without extra argument parsing.
Thanks!
Jeff
Lorenzo Stoakes (ARM)
maintainerRe: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
In reply to Chris DownQuoted 37 lines · Chris Down
Hi Jeff,
Thanks for the review!
Quoted 6 lines · Jeff Xu
Could we please keep the test coverage for the unsealed [vdso] case and avoid unconditionally skipping whenever [vdso] is unsealed?
There are two regressions I'd love for us to still be able to catch:
1. Kernel or config regressions when sealing is expected to be on:
Yeah agreed. With the cleanup it matters even more I think because when sealing is set in one place the most likely regression is probably one that unseals everything at once.
Quoted 1 line
2. Regressions in the new
no_mseal_sys_mappingsboot parameter itself:In v2 I can check
/proc/cmdlineforno_mseal_sys_mappingsto do that.Lorenzo, I think that also may inform your question about whether checking for the disabled case is redundant, right?
Quoted 5 lines
When booted with
no_mseal_sys_mappings(or when unsealed), running the assertions in Patch 3 (verifying system mappings have noslflag and thatmunmap()/mremap()-- and ideallymprotect(PROT_READ | PROT_WRITE)-- on [vdso] succeed) directly verifies that the boot parameter works and doesn't regress.Sounds good.
Quoted 5 lines
or keep strict failure as an option (e.g.
./sysmap_is_sealedfails if unsealed without the boot param, whilerun_vmtests.shpasses a flag like--allow-disabledwhenCONFIG_MSEAL_SYSTEM_MAPPINGSmay not be enabled), so CI environments that expect sealing still catch a broken seal.
Quoted 5 lines
I like this and I think we can do it without adding some of the complexity that Lorenzo was not so happy about:
- Have
check_sealedskip as usual when [vdso] isn't sealed and param is not set
- A new test, sayexpect_sealed, fails in the same case
I'm confused about this one - we want to skip altogether if the feature isn't enabled, right?
Quoted 1 line
-
run_vmtestsruns with -Texpect_sealedwhenCONFIG_MSEAL_SYSTEM_MAPPINGS=y
run_vmtests I will have to best-guess it, e.g. if /proc/config.gz is present check it, I suppose?
Quoted 2 lines
That should be pretty minimal. Lorenzo, Jeff, how does that sound?
Sounds reasonable!
I am a bit leery though of requiring a CI to enable the option when it is known to break things, however, as CI's might rely on some of the software this impacts.
--
Cheers, Lorenzo
[email protected]
AI reviewRe: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
In reply to Chris DownSashiko has reviewed this patch and found no issues.
Quoted 11 lines
CONFIG_MSEAL_SYSTEM_MAPPINGSseals each process' system mappings when they are created. As it is today this can only be toggled at build time, so hosts that need sealing and hosts running software which moves or unmaps these mappings end up with separate kernels. This is not ideal since it adds more complexity of deployment, it would be great to be able to have one kernel which can configurably do both.So, to improve this, let's add mseal_system_mappings= so that this can be chosen at boot.
Signed-off-by Chris Down <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Pedro Falcato
reviewerRe: [PATCH 1/3] mseal sysmap: Add mseal_system_mappings= boot parameter
In reply to Chris DownQuoted 9 lines · Chris Down
CONFIG_MSEAL_SYSTEM_MAPPINGSseals each process' system mappings when they are created. As it is today this can only be toggled at build time, so hosts that need sealing and hosts running software which moves or unmaps these mappings end up with separate kernels. This is not ideal since it adds more complexity of deployment, it would be great to be able to have one kernel which can configurably do both.So, to improve this, let's add mseal_system_mappings= so that this can be chosen at boot.
I'm very curious, do you actually have a usecase for this?
Signature · 1 line
Pedro
PATCH 2/3 mseal sysmap: Allow with CHECKPOINT_RESTORE, default off
In reply to Chris DownMSEAL_SYSTEM_MAPPINGS depends on !CHECKPOINT_RESTORE because CRIU moves system mappings when restoring a process. Now that sealing can be chosen at boot we should instead use this to determine defaults.
Let's add MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON and move the dependency there. Existing configurations retain their behaviour. Kernels built with CHECKPOINT_RESTORE can build sealing in, but will only seal mappings when explicitly requested with mseal_system_mappings=1.
Hosts can also share a kernel built with MSEAL_SYSTEM_MAPPINGS=y and MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON=n, enabling sealing only where needed. This lets hosts which need sealing share the kernel image with hosts which need their system mappings to remain movable, which simplifies deployment.
--- .../admin-guide/kernel-parameters.txt | 2 +- Documentation/userspace-api/mseal.rst | 4 +- mm/mseal.c | 3 +- security/Kconfig | 17 +++++++- .../selftests/mseal_system_mappings/Makefile | 2 + .../selftests/mseal_system_mappings/config | 2 + .../mseal_system_mappings/sysmap_is_sealed.c | 42 ++++++++++++++++++- 7 files changed, 66 insertions(+), 6 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +1 -1
@@ -4275,7 +4275,7 @@ Kernel parameters whether system mappings are sealed for this boot. See Documentation/userspace-api/mseal.rst. Format: <bool> - Default: 1 (enabled). + Default set by CONFIG_MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON. mtdparts= [MTD] See drivers/mtd/parsers/cmdlinepart.c
Documentation/userspace-api/mseal.rst +3 -1
@@ -143,7 +143,9 @@ Use cases If supported by an architecture (CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS), the CONFIG_MSEAL_SYSTEM_MAPPINGS seals all system mappings of this architecture. The kernel command line parameter - ``mseal_system_mappings=0`` turns this off at boot. + ``mseal_system_mappings=0|1`` turns this off or on at boot. The default is + set by CONFIG_MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON, which is off with + CONFIG_CHECKPOINT_RESTORE. WARNING: This feature breaks programs which rely on relocating or unmapping system mappings. Known broken software at the time
mm/mseal.c +2 -1
@@ -19,7 +19,8 @@#include "internal.h" #ifdef CONFIG_MSEAL_SYSTEM_MAPPINGS -bool mseal_sysmap_enabled__ro_after_init = true; +bool mseal_sysmap_enabled__ro_after_init = +IS_ENABLED (CONFIG_MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON );static int __init early_mseal_sysmap (char *buf) {
security/Kconfig +15 -2
@@ -53,7 +53,6 @@ config MSEAL_SYSTEM_MAPPINGS bool "mseal system mappings" depends on 64BIT depends on ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS - depends on !CHECKPOINT_RESTORE help Apply mseal on system mappings. The system mappings includes vdso, vvar, vvar_vclock,
@@ -67,11 +66,25 @@ config MSEAL_SYSTEM_MAPPINGS of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore this config can't be enabled universally. - Sealing can be turned off at boot with "mseal_system_mappings=0". + The "mseal_system_mappings=" kernel command line parameter can + be used to enable or disable sealing at boot. The default is set + by MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON. For complete descriptions of memory sealing, please see Documentation/userspace-api/mseal.rst +config MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON + bool "Seal system mappings by default" + depends on MSEAL_SYSTEM_MAPPINGS + depends on !CHECKPOINT_RESTORE + default y + help + Sets the default for the "mseal_system_mappings=" boot parameter. + + With CHECKPOINT_RESTORE=y, system mappings are only sealed when + "mseal_system_mappings=1" is given, since CRIU needs to move them + when restoring a process. + config SECURITY bool "Enable different security models" depends on SYSFS
tools/testing/selftests/mseal_system_mappings/Makefile +2 -0
@@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only CFLAGS += -std=c99 -pthread -Wall $(KHDR_INCLUDES) +LDLIBS += -lz + TEST_GEN_PROGS := sysmap_is_sealed include ../lib.mk
tools/testing/selftests/mseal_system_mappings/config +2 -0
@@ -1 +1,3 @@ CONFIG_MSEAL_SYSTEM_MAPPINGS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +41 -1
61 lines not on this page · raw message
Signature · 1 line
2.54.0
Lorenzo Stoakes (ARM)
maintainerRe: [PATCH 2/3] mseal sysmap: Allow with CHECKPOINT_RESTORE, default off
Quoted 9 lines · Chris Down
MSEAL_SYSTEM_MAPPINGSdepends on !CHECKPOINT_RESTORE because CRIU moves system mappings when restoring a process. Now that sealing can be chosen at boot we should instead use this to determine defaults.Let's add
MSEAL_SYSTEM_MAPPINGS_DEFAULT_ONand move the dependency there. Existing configurations retain their behaviour. Kernels built withCHECKPOINT_RESTOREcan build sealing in, but will only seal mappings when explicitly requested with mseal_system_mappings=1.
Quoted 7 lines
Hosts can also share a kernel built with MSEAL_SYSTEM_MAPPINGS=y and MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON=n, enabling sealing only where needed. This lets hosts which need sealing share the kernel image with hosts which need their system mappings to remain movable, which simplifies deployment.
Signed-off-by Chris Down <[email protected]>
Sorry, NAK to this patch. It's adding far too much complexity.
The honest version of this is removing the CRIU dependency, and since it's well documented that many things break if you use it, and the config option is default-no, then it's kinda your own fault if you insist on doing the broken thing.
So I don't think I'd mind that, and it'd make the change simpler, as you could fold it into patch 1 also ;)
--
Cheers, Lorenzo
Re: [PATCH 2/3] mseal sysmap: Allow with CHECKPOINT_RESTORE, default off
Ok, sounds good. I'll drop MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON, and fold dropping the !CHECKPOINT_RESTORE dependency into the boot parameter patch. Thanks!
Lorenzo Stoakes (ARM)
maintainerRe: [PATCH 2/3] mseal sysmap: Allow with CHECKPOINT_RESTORE, default off
Quoted 3 lines · Chris Down
Ok, sounds good. I'll drop
MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON, and fold dropping the !CHECKPOINT_RESTORE dependency into the boot parameter patch. Thanks!
Thanks!
--
Cheers, Lorenzo
[email protected]
AI reviewRe: [PATCH 2/3] mseal sysmap: Allow with CHECKPOINT_RESTORE, default off
In reply to Chris DownSashiko has reviewed this patch and found no issues.
Quoted 9 lines
MSEAL_SYSTEM_MAPPINGSdepends on !CHECKPOINT_RESTORE because CRIU moves system mappings when restoring a process. Now that sealing can be chosen at boot we should instead use this to determine defaults.Let's add
MSEAL_SYSTEM_MAPPINGS_DEFAULT_ONand move the dependency there. Existing configurations retain their behaviour. Kernels built withCHECKPOINT_RESTOREcan build sealing in, but will only seal mappings when explicitly requested with mseal_system_mappings=1.
Quoted 7 lines
Hosts can also share a kernel built with MSEAL_SYSTEM_MAPPINGS=y and MSEAL_SYSTEM_MAPPINGS_DEFAULT_ON=n, enabling sealing only where needed. This lets hosts which need sealing share the kernel image with hosts which need their system mappings to remain movable, which simplifies deployment.
Signed-off-by Chris Down <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
PATCH 3/3 selftests/mseal_system_mappings: Test vdso unmap and remap
In reply to Chris Down--- .../mseal_system_mappings/sysmap_is_sealed.c | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+)
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +92 -0
@@ -10,6 +10,7 @@#include <unistd.h> #include <string.h> #include <stdbool.h> +#include <sys/mman.h> #include <sys/utsname.h> #include <zlib.h>
@@ -232,4 +233,95 @@ TEST_F(basic, check_sealed)EXPECT_EQ (expected, sealed); }; +static bool find_vdso (unsigned long *start,unsigned long *end) +{ +char line[MAX_LINE_LEN ]; +bool found = false; +FILE *maps; + + maps =fopen ("/proc/self/maps" ,"r" ); +if (!maps) +return false; + +while (fgets (line,sizeof (line), maps)) { +if (strstr (line,"[vdso]" ) && +sscanf (line,"%lx-%lx" , start, end) ==2 ) { + found = true; +break ; + } + } + +fclose (maps); +return found; +} + +static int vdso_is_sealed (void ) +{ +int sealed =-1 ; +FILE *maps; + + maps =fopen ("/proc/self/smaps" ,"r" ); +if (!maps) +return -1 ; +if (has_mapping ("[vdso]" , maps)) + sealed =mapping_is_sealed (maps); +fclose (maps); +return sealed; +} + +/* +* Unmapping or moving [vdso] must fail with EPERM when it is sealed. When it +* is not sealed, it succeeds and leaves glibc with a stale vdso pointer, which +* is fine because each test runs in its own forked child. +*/ +TEST (vdso_munmap) +{ +int sealed; +unsigned long start, end; +int ret; + +if (!find_vdso (&start, &end)) +SKIP (return,"could not find the mapping, [vdso]" ); + sealed =vdso_is_sealed (); +if (sealed <0 ) +SKIP (return,"could not read the [vdso] sealing state" ); + + ret =munmap ((void *)start, end - start); +if (sealed) { +EXPECT_EQ (-1 , ret); +EXPECT_EQ (EPERM , errno); + }else { +EXPECT_EQ (0 , ret); + } +EXPECT_EQ (sealed,find_vdso (&start, &end)); +} + +TEST (vdso_mremap) +{ +int sealed; +unsigned long start, end, size, new_start; +void *dst, *ret; + +if (!find_vdso (&start, &end)) +SKIP (return,"could not find the mapping, [vdso]" ); + sealed =vdso_is_sealed (); +if (sealed <0 ) +SKIP (return,"could not read the [vdso] sealing state" ); + size = end - start; + + dst =mmap (NULL , size,PROT_NONE ,MAP_PRIVATE |MAP_ANONYMOUS ,-1 ,0 ); +ASSERT_NE (MAP_FAILED , dst); + + ret =mremap ((void *)start, size, size,MREMAP_MAYMOVE |MREMAP_FIXED , + dst); +if (sealed) { +EXPECT_EQ (MAP_FAILED , ret); +EXPECT_EQ (EPERM , errno); + }else { +EXPECT_EQ (dst, ret); + } +ASSERT_TRUE (find_vdso (&new_start, &end)); +EXPECT_EQ (sealed ? start : (unsigned long )dst, new_start); +} +TEST_HARNESS_MAIN
Signature · 1 line
2.54.0
Lorenzo Stoakes (ARM)
maintainerRe: [PATCH 3/3] selftests/mseal_system_mappings: Test vdso unmap and remap
Sorry, in mm we require commit messages. Even for tests :)
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c
Quoted 9 lines · Chris Down
Signed-off-by Chris Down <[email protected]>--- .../mseal_system_mappings/sysmap_is_sealed.c | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+)tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +0
-0
Why on earth does 'mseal_system_mappings' have its own directory...??
Ugh I don't know how I let this stuff go on the original series :/
Please, for the love of all that's sacred, move these tests over to tools/selftests/mm/. This is an mm feature, for our sins...
You can do the move as a prerequisite patch in the series.
(And, again, I really do insist on your change doing some cleanup here as
well rather than extending this stuff.)
Quoted 23 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +12
-0@@ -10,6 +10,7 @@#include <unistd.h> #include <string.h> #include <stdbool.h> +#include <sys/mman.h> #include <sys/utsname.h> #include <zlib.h> @@ -232,4 +233,95 @@ TEST_F(basic, check_sealed)EXPECT_EQ (expected, sealed); }; +static bool find_vdso (unsigned long *start,unsigned long *end) +{ +char line[MAX_LINE_LEN ]; +bool found = false; +FILE *maps; + + maps =fopen ("/proc/self/maps" ,"r" ); +if (!maps) +return false; + +while (fgets (line,sizeof (line), maps)) {
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c TEST_F(basic, check_sealed) · line 256
Quoted 10 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +10
-0+if (strstr (line,"[vdso]" ) && +sscanf (line,"%lx-%lx" , start, end) ==2 ) { + found = true; +break ; + } + } + +fclose (maps); +return found; +}
There's shared code for this kind of thing, please don't duplicate a /proc/self/maps thing if unnecessary. Also there's a nicer ioctl interface for all this.
See vm_utils.[ch].
Quoted 50 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +50
-0+ +static int vdso_is_sealed (void ) +{ +int sealed =-1 ; +FILE *maps; + + maps =fopen ("/proc/self/smaps" ,"r" ); +if (!maps) +return -1 ; +if (has_mapping ("[vdso]" , maps)) + sealed =mapping_is_sealed (maps); +fclose (maps); +return sealed; +} + +/* +* Unmapping or moving [vdso] must fail with EPERM when it is sealed. When it +* is not sealed, it succeeds and leaves glibc with a stale vdso pointer, which +* is fine because each test runs in its own forked child. +*/ +TEST (vdso_munmap) +{ +int sealed; +unsigned long start, end; +int ret; + +if (!find_vdso (&start, &end)) +SKIP (return,"could not find the mapping, [vdso]" ); + sealed =vdso_is_sealed (); +if (sealed <0 ) +SKIP (return,"could not read the [vdso] sealing state" ); + + ret =munmap ((void *)start, end - start); +if (sealed) { +EXPECT_EQ (-1 , ret); +EXPECT_EQ (EPERM , errno); + }else { +EXPECT_EQ (0 , ret); + } +EXPECT_EQ (sealed,find_vdso (&start, &end)); +} + +TEST (vdso_mremap) +{ +int sealed; +unsigned long start, end, size, new_start; +void *dst, *ret; + +if (!find_vdso (&start, &end)) +SKIP (return,"could not find the mapping, [vdso]" );
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c TEST_F(basic, check_sealed) · line 316
Quoted 10 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +10
-0+ sealed =vdso_is_sealed (); +if (sealed <0 ) +SKIP (return,"could not read the [vdso] sealing state" ); + size = end - start; + + dst =mmap (NULL , size,PROT_NONE ,MAP_PRIVATE |MAP_ANONYMOUS ,-1 ,0 ); +ASSERT_NE (MAP_FAILED , dst); + + ret =mremap ((void *)start, size, size,MREMAP_MAYMOVE |MREMAP_FIXED , + dst);
I mean arguably this is an mremap test that belongs with mremap? I guess debatable...
Quoted 12 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +10
-1+if (sealed) { +EXPECT_EQ (MAP_FAILED , ret); +EXPECT_EQ (EPERM , errno); + }else { +EXPECT_EQ (dst, ret); + } +ASSERT_TRUE (find_vdso (&new_start, &end)); +EXPECT_EQ (sealed ? start : (unsigned long )dst, new_start); +} +TEST_HARNESS_MAIN --
Quoted 2 lines
2.54.0
This all just seems like work that should have been done in the past when this feature was proposed, and doesn't depend on your changes at all AFAICT? Maybe I missed it though.
Valuable in itself, but probably worth sending separately as a result? Otherwise it's a little disconnected from the actual change you're making.
--
Cheers, Lorenzo
Re: [PATCH 3/3] selftests/mseal_system_mappings: Test vdso unmap and remap
Quoted 1 line · Lorenzo Stoakes (ARM)
Sorry, in mm we require commit messages. Even for tests :)
Sure thing, I'll add one.
Quoted 13 lines · Chris Down
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c
Quoted 9 lines
Signed-off-by Chris Down <[email protected]>--- .../mseal_system_mappings/sysmap_is_sealed.c | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+)tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +0
-0Why on earth does '
mseal_system_mappings' have its own directory...??
Quoted 6 lines
Ugh I don't know how I let this stuff go on the original series :/
Please, for the love of all that's sacred, move these tests over to
tools/selftests/mm/. This is an mm feature, for our sins...You can do the move as a prerequisite patch in the series.
Will do, I'll make the move the first patch.
Quoted 2 lines
(And, again, I really do insist on your change doing some cleanup here as well rather than extending this stuff.)
Yep, see my reply to 1/3.
Quoted 38 lines
Quoted 23 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +12
-0@@ -10,6 +10,7 @@#include <unistd.h> #include <string.h> #include <stdbool.h> +#include <sys/mman.h> #include <sys/utsname.h> #include <zlib.h> @@ -232,4 +233,95 @@ TEST_F(basic, check_sealed)EXPECT_EQ (expected, sealed); }; +static bool find_vdso (unsigned long *start,unsigned long *end) +{ +char line[MAX_LINE_LEN ]; +bool found = false; +FILE *maps; + + maps =fopen ("/proc/self/maps" ,"r" ); +if (!maps) +return false; + +while (fgets (line,sizeof (line), maps)) {tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c TEST_F(basic, check_sealed) · line 256
Quoted 10 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +10
-0+if (strstr (line,"[vdso]" ) && +sscanf (line,"%lx-%lx" , start, end) ==2 ) { + found = true; +break ; + } + } + +fclose (maps); +return found; +}There's shared code for this kind of thing, please don't duplicate a
/proc/self/mapsthing if unnecessary. Also there's a nicer ioctl interface for all this.
Quoted 1 line
See vm_utils.[ch].
Oh thank you! I will use that.
Quoted 2 lines
I mean arguably this is an mremap test that belongs with mremap? I guess debatable...
Hmm, I'd lean towards keeping it with the sysmap test, since it's really testing that the seal is enforced on these mappings rather than anything about mremap() itself, but I don't feel strongly if you insist, just let me know.
Quoted 6 lines
This all just seems like work that should have been done in the past when this feature was proposed, and doesn't depend on your changes at all AFAICT? Maybe I missed it though.
Valuable in itself, but probably worth sending separately as a result? Otherwise it's a little disconnected from the actual change you're making.
Yeah, it doesn't depend on it. I can send it separately on top of the move if you like, I just don't like touching things without tests where possible.
Thanks for the review!
Lorenzo Stoakes (ARM)
maintainerRe: [PATCH 3/3] selftests/mseal_system_mappings: Test vdso unmap and remap
Quoted 74 lines · Chris Down
Quoted 1 line · Lorenzo Stoakes (ARM)
Sorry, in mm we require commit messages. Even for tests :)
Sure thing, I'll add one.
Quoted 13 lines · Chris Down
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c
Quoted 9 lines
Signed-off-by Chris Down <[email protected]>--- .../mseal_system_mappings/sysmap_is_sealed.c | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+)tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +0
-0Why on earth does '
mseal_system_mappings' have its own directory...??Quoted 6 lines
Ugh I don't know how I let this stuff go on the original series :/
Please, for the love of all that's sacred, move these tests over to
tools/selftests/mm/. This is an mm feature, for our sins...You can do the move as a prerequisite patch in the series.
Will do, I'll make the move the first patch.
Quoted 2 lines
(And, again, I really do insist on your change doing some cleanup here as well rather than extending this stuff.)
Yep, see my reply to 1/3.
Quoted 38 lines
Quoted 23 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +12
-0@@ -10,6 +10,7 @@#include <unistd.h> #include <string.h> #include <stdbool.h> +#include <sys/mman.h> #include <sys/utsname.h> #include <zlib.h> @@ -232,4 +233,95 @@ TEST_F(basic, check_sealed)EXPECT_EQ (expected, sealed); }; +static bool find_vdso (unsigned long *start,unsigned long *end) +{ +char line[MAX_LINE_LEN ]; +bool found = false; +FILE *maps; + + maps =fopen ("/proc/self/maps" ,"r" ); +if (!maps) +return false; + +while (fgets (line,sizeof (line), maps)) {tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c TEST_F(basic, check_sealed) · line 256
Quoted 10 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +10
-0+if (strstr (line,"[vdso]" ) && +sscanf (line,"%lx-%lx" , start, end) ==2 ) { + found = true; +break ; + } + } + +fclose (maps); +return found; +}There's shared code for this kind of thing, please don't duplicate a
/proc/self/mapsthing if unnecessary. Also there's a nicer ioctl interface for all this.Quoted 1 line
See vm_utils.[ch].
Oh thank you! I will use that.
Quoted 7 lines
Quoted 2 lines
I mean arguably this is an mremap test that belongs with mremap? I guess debatable...
Hmm, I'd lean towards keeping it with the sysmap test, since it's really testing that the seal is enforced on these mappings rather than anything about
mremap()itself, but I don't feel strongly if you insist, just let me know.
Actually let's keep them together :) It's always a bit blurry...
Quoted 10 lines
Quoted 7 lines
This all just seems like work that should have been done in the past when this feature was proposed, and doesn't depend on your changes at all AFAICT? Maybe I missed it though.
Valuable in itself, but probably worth sending separately as a result? Otherwise it's a little disconnected from the actual change you're making.
Yeah, it doesn't depend on it. I can send it separately on top of the move if you like, I just don't like touching things without tests where possible.
Well that's a good instinct for sure :)
I mean alternatively you could send as patch 1 and explicitly say you're providing a tested foundation for the other changes.
Quoted 2 lines
Thanks for the review!
No worries!
--
Cheers, Lorenzo
[email protected]
AI reviewRe: [PATCH 3/3] selftests/mseal_system_mappings: Test vdso unmap and remap
In reply to Chris DownThank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] selftests/mseal: SIGSEGV in vdso_munmap() and vdso_mremap() on 32-bit x86 --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] selftests/mseal: SIGSEGV in vdso_munmap() and vdso_mremap() on 32-bit x86 --
commit c39ca555b3d21581707989b9c4e4f219f86ffc25
Author: Chris Down <[email protected]>
selftests/mseal_system_mappings: Test vdso unmap and remap
This patch adds vdso_munmap and vdso_mremap tests to tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c to verify that unmapping or moving [vdso] fails with EPERM when sealed and succeeds when unsealed.
Quoted 4 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +0
-0
[ ... ]
Quoted 84 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +80
-0@@ -232,4 +233,95 @@ TEST_F(basic, check_sealed)EXPECT_EQ (expected, sealed); }; +static bool find_vdso (unsigned long *start,unsigned long *end) +{ +char line[MAX_LINE_LEN ]; +bool found = false; +FILE *maps; + + maps =fopen ("/proc/self/maps" ,"r" ); +if (!maps) +return false; + +while (fgets (line,sizeof (line), maps)) { +if (strstr (line,"[vdso]" ) && +sscanf (line,"%lx-%lx" , start, end) ==2 ) { + found = true; +break ; + } + } + +fclose (maps); +return found; +} + +static int vdso_is_sealed (void ) +{ +int sealed =-1 ; +FILE *maps; + + maps =fopen ("/proc/self/smaps" ,"r" ); +if (!maps) +return -1 ; +if (has_mapping ("[vdso]" , maps)) + sealed =mapping_is_sealed (maps); +fclose (maps); +return sealed; +} + +/* +* Unmapping or moving [vdso] must fail with EPERM when it is sealed. When it +* is not sealed, it succeeds and leaves glibc with a stale vdso pointer, which +* is fine because each test runs in its own forked child. +*/ +TEST (vdso_munmap) +{ +int sealed; +unsigned long start, end; +int ret; + +if (!find_vdso (&start, &end)) +SKIP (return,"could not find the mapping, [vdso]" ); + sealed =vdso_is_sealed (); +if (sealed <0 ) +SKIP (return,"could not read the [vdso] sealing state" ); + + ret =munmap ((void *)start, end - start); +if (sealed) { +EXPECT_EQ (-1 , ret); +EXPECT_EQ (EPERM , errno); + }else { +EXPECT_EQ (0 , ret); + } +EXPECT_EQ (sealed,find_vdso (&start, &end)); +} + +TEST (vdso_mremap) +{ +int sealed; +unsigned long start, end, size, new_start; +void *dst, *ret; + +if (!find_vdso (&start, &end)) +SKIP (return,"could not find the mapping, [vdso]" ); + sealed =vdso_is_sealed (); +if (sealed <0 ) +SKIP (return,"could not read the [vdso] sealing state" ); + size = end - start; + + dst =mmap (NULL , size,PROT_NONE ,MAP_PRIVATE |MAP_ANONYMOUS ,-1 ,0 ); +ASSERT_NE (MAP_FAILED , dst); + + ret = mremap((void *)start, size, size, MREMAP_MAYMOVE | MREMAP_FIXED,
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c TEST_F(basic, check_sealed) · line 325
Quoted 10 lines
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +10
-0+ dst); +if (sealed) { +EXPECT_EQ (MAP_FAILED , ret); +EXPECT_EQ (EPERM , errno); + }else { +EXPECT_EQ (dst, ret); + } +ASSERT_TRUE (find_vdso (&new_start, &end)); +EXPECT_EQ (sealed ? start : (unsigned long )dst, new_start); +}
[Severity: Medium]
When sealed == 0 on 32-bit x86 (__i386__), will vdso_munmap and vdso_mremap in tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c crash with SIGSEGV and cause the test harness to report a failure?
On 32-bit x86, the kernel passes AT_SYSINFO in the ELF auxiliary vector pointing to __kernel_vsyscall inside [vdso], and glibc caches this pointer in %gs:0x10 and routes all system calls through it.
Neither vdso_munmap nor vdso_mremap skips on 32-bit builds or when CONFIG_MSEAL_SYSTEM_MAPPINGS is disabled (which depends on 64BIT, or may be disabled via CONFIG_CHECKPOINT_RESTORE=y or mseal_system_mappings=0).
In vdso_munmap, when sealed == 0, calling munmap() via glibc enters the kernel through __kernel_vsyscall inside [vdso] with the userspace return address pointing to the landing pad in [vdso]. Once [vdso] is unmapped, returning to userspace or calling find_vdso() and _exit() in the child jumps to the unmapped [vdso] range and faults with SIGSEGV.
Similarly, in vdso_mremap, when sealed == 0, arch/x86/entry/vdso/vma.c updates the return instruction pointer for the mremap() syscall itself via vdso_fix_landing(), but glibc's cached %gs:0x10 pointer still points to the old unmapped start address. The subsequent find_vdso() call (which invokes fopen(), fgets(), and fclose()) and _exit() in the test harness jump through the stale pointer into the unmapped address and fault with SIGSEGV, as noted in tools/testing/selftests/x86/test_mremap_vdso.c:main():
#ifdef __i386__
/* Glibc is likely to explode now - exit with raw syscall */
asm volatile ("int $0x80" : : "a" (__NR_exit), "b" (!!ret));
#else /* __x86_64__ */
syscall(SYS_exit, ret);#endif
Should vdso_munmap and vdso_mremap be skipped on 32-bit x86 or when [vdso] is unsealed on __i386__?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Quoted 9 lines · Chris Down
System mapping sealing is currently a build time choice. Hosts which want it and hosts which need to move or unmap these mappings therefore need separate kernels, which is not ideal. Let's allow the administrator to choose at boot time.
Chris Down (3):
mseal sysmap: Add mseal_system_mappings= boot parameter mseal sysmap: Allow withCHECKPOINT_RESTORE, default off
This isn't just about CRIU. For example, gVisor does not depend on CHECKPOINT_RESTORE, but it still needs to unmap the vDSO. Other sandboxing solutions likely need to manipulate vDSO mappings as well. I think this toggle should be off by default, regardless of CHECKPOINT_RESTORE.
Thanks,
Andrei