From c43ea7d629daf737c5d66b5d8f8ae5e163fe9e4b Mon Sep 17 00:00:00 2001 From: Tomasz Duda Date: Mon, 24 Feb 2025 23:53:01 +0100 Subject: [PATCH] exeseal: do not use F_SEAL_FUTURE_WRITE Prior to kernel Linux 5.5, F_SEAL_FUTURE_WRITE has a bug which maps memory as shared between processes even if it is set as private. See kernel commit 05d351102dbe ("mm, memfd: fix COW issue on MAP_PRIVATE and F_SEAL_FUTURE_WRITE mappings") for more details. According to the fcntl(2) man pages, F_SEAL_WRITE is enough: > Furthermore, trying to create new shared, writable memory-mappings via > mmap(2) will also fail with EPERM. > > Using the F_ADD_SEALS operation to set the F_SEAL_WRITE seal fails > with EBUSY if any writable, shared mapping exists. Such mappings must > be unmapped before you can add this seal. F_SEAL_FUTURE_WRITE only makes sense if a read-write shared mapping in one process should be read-only in another process. This is not case for runc, especially not for the /proc/self/exe we are protecting. Signed-off-by: Tomasz Duda (cyphar: improve the comment regarding F_SEAL_FUTURE_WRITE) (cyphar: improve commit message) Signed-off-by: Aleksa Sarai --- libcontainer/exeseal/cloned_binary_linux.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libcontainer/exeseal/cloned_binary_linux.go b/libcontainer/exeseal/cloned_binary_linux.go index 0c8231ee8..3bafc96a6 100644 --- a/libcontainer/exeseal/cloned_binary_linux.go +++ b/libcontainer/exeseal/cloned_binary_linux.go @@ -47,11 +47,15 @@ func sealMemfd(f **os.File) error { // errors because they are not needed and we want to continue // to work on older kernels. fd := (*f).Fd() - // F_SEAL_FUTURE_WRITE -- Linux 5.1 - _, _ = unix.FcntlInt(fd, unix.F_ADD_SEALS, unix.F_SEAL_FUTURE_WRITE) + + // Skip F_SEAL_FUTURE_WRITE, it is not needed because we alreadu use the + // stronger F_SEAL_WRITE (and is buggy on Linux <5.5 -- see kernel commit + // 05d351102dbe and ). + // F_SEAL_EXEC -- Linux 6.3 const F_SEAL_EXEC = 0x20 //nolint:revive // this matches the unix.* name _, _ = unix.FcntlInt(fd, unix.F_ADD_SEALS, F_SEAL_EXEC) + // Apply all original memfd seals. _, err := unix.FcntlInt(fd, unix.F_ADD_SEALS, baseMemfdSeals) return os.NewSyscallError("fcntl(F_ADD_SEALS)", err)