[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <qrxmfa6jvaojedmo6fle2e6vd5k4hzihcuxdc6zk43dclf6nsd@dvuzolusdtz4>
Date: Wed, 12 Feb 2025 10:05:03 -0500
From: "Liam R. Howlett" <Liam.Howlett@...cle.com>
To: jeffxu@...omium.org
Cc: akpm@...ux-foundation.org, keescook@...omium.org, jannh@...gle.com,
torvalds@...ux-foundation.org, vbabka@...e.cz,
lorenzo.stoakes@...cle.com, adhemerval.zanella@...aro.org,
oleg@...hat.com, avagin@...il.com, benjamin@...solutions.net,
linux-kernel@...r.kernel.org, linux-hardening@...r.kernel.org,
linux-mm@...ck.org, jorgelo@...omium.org, sroettger@...gle.com,
hch@....de, ojeda@...nel.org, thomas.weissschuh@...utronix.de,
adobriyan@...il.com, johannes@...solutions.net,
pedro.falcato@...il.com, hca@...ux.ibm.com, willy@...radead.org,
anna-maria@...utronix.de, mark.rutland@....com,
linus.walleij@...aro.org, Jason@...c4.com, deller@....de,
rdunlap@...radead.org, davem@...emloft.net, peterx@...hat.com,
f.fainelli@...il.com, gerg@...nel.org, dave.hansen@...ux.intel.com,
mingo@...nel.org, ardb@...nel.org, mhocko@...e.com,
42.hyeyoo@...il.com, peterz@...radead.org, ardb@...gle.com,
enh@...gle.com, rientjes@...gle.com, groeck@...omium.org,
mpe@...erman.id.au, aleksandr.mikhalitsyn@...onical.com,
mike.rapoport@...il.com
Subject: Re: [RFC PATCH v5 1/7] mseal, system mappings: kernel config and
header change
* jeffxu@...omium.org <jeffxu@...omium.org> [250211 22:22]:
> From: Jeff Xu <jeffxu@...omium.org>
>
> Provide infrastructure to mseal system mappings. Establish
> two kernel configs (CONFIG_MSEAL_SYSTEM_MAPPINGS,
> ARCH_HAS_MSEAL_SYSTEM_MAPPINGS) and a header file (userprocess.h)
> for future patches.
>
> As discussed during mseal() upstream process [1], mseal() protects
> the VMAs of a given virtual memory range against modifications, such
> as the read/write (RW) and no-execute (NX) bits. For complete
> descriptions of memory sealing, please see mseal.rst [2].
>
> The mseal() is useful to mitigate memory corruption issues where a
> corrupted pointer is passed to a memory management system. For
> example, such an attacker primitive can break control-flow integrity
> guarantees since read-only memory that is supposed to be trusted can
> become writable or .text pages can get remapped.
>
> The system mappings are readonly only, memory sealing can protect
> them from ever changing to writable or unmmap/remapped as different
> attributes.
>
> System mappings such as vdso, vvar, and sigpage (arm), vectors (arm)
> are created by the kernel during program initialization, and could
> be sealed after creation.
>
> Unlike the aforementioned mappings, the uprobe mapping is not
> established during program startup. However, its lifetime is the same
> as the process's lifetime [3]. It could be sealed from creation.
>
> The vsyscall on x86-64 uses a special address (0xffffffffff600000),
> which is outside the mm managed range. This means mprotect, munmap, and
> mremap won't work on the vsyscall. Since sealing doesn't enhance
> the vsyscall's security, it is skipped in this patch. If we ever seal
> the vsyscall, it is probably only for decorative purpose, i.e. showing
> the 'sl' flag in the /proc/pid/smaps. For this patch, it is ignored.
>
> It is important to note that the CHECKPOINT_RESTORE feature (CRIU) may
> alter the system mappings during restore operations. UML(User Mode Linux)
> and gVisor are also known to change the vdso/vvar mappings. Consequently,
> this feature cannot be universally enabled across all systems. As such,
> CONFIG_MSEAL_SYSTEM_MAPPINGS is disabled by default.
>
> To support mseal of system mappings, architectures must define
> CONFIG_ARCH_HAS_MSEAL_SYSTEM_MAPPINGS and update their special mappings
> calls to pass mseal flag. Additionally, architectures must confirm they
> do not unmap/remap system mappings during the process lifetime.
>
> In this version, we've improved the handling of system mapping sealing from
> previous versions, instead of modifying the _install_special_mapping
> function itself, which would affect all architectures, we now call
> _install_special_mapping with a sealing flag only within the specific
> architecture that requires it. This targeted approach offers two key
> advantages: 1) It limits the code change's impact to the necessary
> architectures, and 2) It aligns with the software architecture by keeping
> the core memory management within the mm layer, while delegating the
> decision of sealing system mappings to the individual architecture, which
> is particularly relevant since 32-bit architectures never require sealing.
>
> Additionally, this patch introduces a new header,
> include/linux/usrprocess.h, which contains the mseal_system_mappings()
> function. This function helps the architecture determine if system
> mapping is enabled within the current kernel configuration. It can be
> extended in the future to handle opt-in/out prctl for enabling system
> mapping sealing at the process level or a kernel cmdline feature.
>
> A new header file was introduced because it was difficult to find the
> best location for this function. Although include/linux/mm.h was
> considered, this feature is more closely related to user processes
> than core memory management. Additionally, future prctl or kernel
> cmd-line implementations for this feature would not fit within the
> scope of core memory management or mseal.c. This is relevant because
> if we add unit-tests for mseal.c in the future, we would want to limit
> mseal.c's dependencies to core memory management.
>
> Prior to this patch series, we explored sealing special mappings from
> userspace using glibc's dynamic linker. This approach revealed several
> issues:
> - The PT_LOAD header may report an incorrect length for vdso, (smaller
> than its actual size). The dynamic linker, which relies on PT_LOAD
> information to determine mapping size, would then split and partially
> seal the vdso mapping. Since each architecture has its own vdso/vvar
> code, fixing this in the kernel would require going through each
> archiecture. Our initial goal was to enable sealing readonly mappings,
> e.g. .text, across all architectures, sealing vdso from kernel since
> creation appears to be simpler than sealing vdso at glibc.
> - The [vvar] mapping header only contains address information, not length
> information. Similar issues might exist for other special mappings.
> - Mappings like uprobe are not covered by the dynamic linker,
> and there is no effective solution for them.
>
> This feature's security enhancements will benefit ChromeOS, Android,
> and other high security systems.
>
> Testing:
> This feature was tested on ChromeOS and Android for both x86-64 and ARM64.
> - Enable sealing and verify vdso/vvar, sigpage, vector are sealed properly,
> i.e. "sl" shown in the smaps for those mappings, and mremap is blocked.
> - Passing various automation tests (e.g. pre-checkin) on ChromeOS and
> Android to ensure the sealing doesn't affect the functionality of
> Chromebook and Android phone.
>
> I also tested the feature on Ubuntu on x86-64:
> - With config disabled, vdso/vvar is not sealed,
> - with config enabled, vdso/vvar is sealed, and booting up Ubuntu is OK,
> normal operations such as browsing the web, open/edit doc are OK.
>
> In addition, Benjamin Berg tested this on UML.
>
> Link: https://lore.kernel.org/all/20240415163527.626541-1-jeffxu@chromium.org/ [1]
> Link: Documentation/userspace-api/mseal.rst [2]
> Link: https://lore.kernel.org/all/CABi2SkU9BRUnqf70-nksuMCQ+yyiWjo3fM4XkRkL-NrCZxYAyg@mail.gmail.com/ [3]
I found it odd that the history and V4 links were not here, but I
realised that was in 0/7 instead.
>
> Signed-off-by: Jeff Xu <jeffxu@...omium.org>
> ---
> include/linux/userprocess.h | 18 ++++++++++++++++++
> init/Kconfig | 18 ++++++++++++++++++
> security/Kconfig | 18 ++++++++++++++++++
> 3 files changed, 54 insertions(+)
> create mode 100644 include/linux/userprocess.h
>
> diff --git a/include/linux/userprocess.h b/include/linux/userprocess.h
> new file mode 100644
> index 000000000000..bd11e2e972c5
> --- /dev/null
> +++ b/include/linux/userprocess.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _LINUX_USER_PROCESS_H
> +#define _LINUX_USER_PROCESS_H
> +#include <linux/mm.h>
Why is this in a new file and not mm.h directly? Anyone who needs to
use this will pull in mm.h anyways, and probably already has mm.h
included.
> +
> +/*
> + * mseal of userspace process's system mappings.
> + */
> +static inline unsigned long mseal_system_mappings(void)
> +{
> +#ifdef CONFIG_MSEAL_SYSTEM_MAPPINGS
> + return VM_SEALED;
> +#else
> + return 0;
> +#endif
> +}
> +
> +#endif
Looking in mm.h, there are examples of config checks which either set
the bit or set it to 0. This means you wouldn't need the function at
all and the precompiler would do all the work (although with a static
inline, I'm not sure it would make a big difference in instructions).
For instance, you could do:
#ifdef CONFIG_64BIT
/* VM is sealed, in vm_flags */
#define VM_SEALED _BITUL(63)
#ifdef CONFIG_MSEAL_SYSTEM_MAPPINGS
#define VM_SYSTEM_SEAL VM_SEALED
else
#define VM_SYSTEM_SEAL VM_NONE
#endif
#else /* CONFIG_64BIT */
#define VM_SYSTEM_SEAL VM_NONE
#endif
Then you can use VM_SYSTEM_SEAL in the system mappings function in the
list of flags instead of having a variable + calling the static
function.
I didn't look close enough to see if the 32bit version is necessary.
> diff --git a/init/Kconfig b/init/Kconfig
> index d0d021b3fa3b..892d2bcdf397 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -1882,6 +1882,24 @@ config ARCH_HAS_MEMBARRIER_CALLBACKS
> config ARCH_HAS_MEMBARRIER_SYNC_CORE
> bool
>
> +config ARCH_HAS_MSEAL_SYSTEM_MAPPINGS
ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS is more clear. HAS may mean it's
supported or it could mean it's enabled. SUPPORTS is more clear that
this is set if an arch supports the feature. After all, I think HAS
here means it "has support for" mseal system mappings.
I see that both are used (HAS and SUPPORTS), but I'm still not sure what
HAS means in other contexts without digging.
> + bool
> + help
> + Control MSEAL_SYSTEM_MAPPINGS access based on architecture.
> +
> + A 64-bit kernel is required for the memory sealing feature.
> + No specific hardware features from the CPU are needed.
> +
> + To enable this feature, the architecture needs to update their
> + speical mappings calls to include the sealing flag and confirm
> + that it doesn't unmap/remap system mappings during the life
> + time of the process. After the architecture enables this, a
> + distribution can set CONFIG_MSEAL_SYSTEM_MAPPING to manage access
> + to the feature.
> +
> + For complete descriptions of memory sealing, please see
> + Documentation/userspace-api/mseal.rst
> +
> config HAVE_PERF_EVENTS
> bool
> help
> diff --git a/security/Kconfig b/security/Kconfig
> index f10dbf15c294..bfb35fc7a3c6 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -51,6 +51,24 @@ config PROC_MEM_NO_FORCE
>
> endchoice
>
> +config MSEAL_SYSTEM_MAPPINGS
> + bool "mseal system mappings"
> + depends on 64BIT
> + depends on ARCH_HAS_MSEAL_SYSTEM_MAPPINGS
> + depends on !CHECKPOINT_RESTORE
> + help
> + Seal system mappings such as vdso, vvar, sigpage, uprobes, etc.
> +
> + A 64-bit kernel is required for the memory sealing feature.
> + No specific hardware features from the CPU are needed.
> +
> + Note: CHECKPOINT_RESTORE, UML, gVisor are known to relocate or
> + unmap system mapping, therefore this config can't be enabled
> + universally.
I guess add rr to the list, since that's also reported to have issues as
well.
> +
> + For complete descriptions of memory sealing, please see
> + Documentation/userspace-api/mseal.rst
> +
> config SECURITY
> bool "Enable different security models"
> depends on SYSFS
> --
> 2.48.1.502.g6dc24dfdaf-goog
>
Powered by blists - more mailing lists