linux-stable/kernel
Isaac J. Manjarres 17c5d49beb mm: drop the assumption that VM_SHARED always implies writable
From: Lorenzo Stoakes <lstoakes@gmail.com>

[ Upstream commit e8e17ee90e ]

Patch series "permit write-sealed memfd read-only shared mappings", v4.

The man page for fcntl() describing memfd file seals states the following
about F_SEAL_WRITE:-

    Furthermore, trying to create new shared, writable memory-mappings via
    mmap(2) will also fail with EPERM.

With emphasis on 'writable'.  In turns out in fact that currently the
kernel simply disallows all new shared memory mappings for a memfd with
F_SEAL_WRITE applied, rendering this documentation inaccurate.

This matters because users are therefore unable to obtain a shared mapping
to a memfd after write sealing altogether, which limits their usefulness.
This was reported in the discussion thread [1] originating from a bug
report [2].

This is a product of both using the struct address_space->i_mmap_writable
atomic counter to determine whether writing may be permitted, and the
kernel adjusting this counter when any VM_SHARED mapping is performed and
more generally implicitly assuming VM_SHARED implies writable.

It seems sensible that we should only update this mapping if VM_MAYWRITE
is specified, i.e.  whether it is possible that this mapping could at any
point be written to.

If we do so then all we need to do to permit write seals to function as
documented is to clear VM_MAYWRITE when mapping read-only.  It turns out
this functionality already exists for F_SEAL_FUTURE_WRITE - we can
therefore simply adapt this logic to do the same for F_SEAL_WRITE.

We then hit a chicken and egg situation in mmap_region() where the check
for VM_MAYWRITE occurs before we are able to clear this flag.  To work
around this, perform this check after we invoke call_mmap(), with careful
consideration of error paths.

Thanks to Andy Lutomirski for the suggestion!

[1]:https://lore.kernel.org/all/20230324133646.16101dfa666f253c4715d965@linux-foundation.org/
[2]:https://bugzilla.kernel.org/show_bug.cgi?id=217238

This patch (of 3):

There is a general assumption that VMAs with the VM_SHARED flag set are
writable.  If the VM_MAYWRITE flag is not set, then this is simply not the
case.

Update those checks which affect the struct address_space->i_mmap_writable
field to explicitly test for this by introducing
[vma_]is_shared_maywrite() helper functions.

This remains entirely conservative, as the lack of VM_MAYWRITE guarantees
that the VMA cannot be written to.

Link: https://lkml.kernel.org/r/cover.1697116581.git.lstoakes@gmail.com
Link: https://lkml.kernel.org/r/d978aefefa83ec42d18dfa964ad180dbcde34795.1697116581.git.lstoakes@gmail.com
Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
Suggested-by: Andy Lutomirski <luto@kernel.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Hugh Dickins <hughd@google.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Muchun Song <muchun.song@linux.dev>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: stable@vger.kernel.org
[isaacmanjarres: resolved merge conflicts due to
due to refactoring that happened in upstream commit
5de195060b ("mm: resolve faulty mmap_region() error path behaviour")]
Signed-off-by: Isaac J. Manjarres <isaacmanjarres@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2025-08-28 16:28:39 +02:00
..
bpf bpf: Make reg_not_null() true for CONST_PTR_TO_MAP 2025-08-28 16:28:24 +02:00
cgroup
configs
debug
dma
entry
events perf/core: Prevent VMA split of buffer mappings 2025-08-15 12:09:05 +02:00
futex
gcov
irq
kcsan
livepatch
locking
module module: Prevent silent truncation of module name in delete_module(2) 2025-08-28 16:28:28 +02:00
power PM: sleep: console: Fix the black screen issue 2025-08-28 16:28:17 +02:00
printk
rcu rcu: Fix racy re-initialization of irq_work causing hangs 2025-08-28 16:28:32 +02:00
sched sched/fair: Bump sd->max_newidle_lb_cost when newidle balance fails 2025-08-28 16:28:21 +02:00
time
trace tracing: fprobe-event: Sanitize wildcard for fprobe event name 2025-08-28 16:28:34 +02:00
.gitignore
acct.c
async.c
audit_fsnotify.c
audit_tree.c
audit_watch.c
audit.c
audit.h
auditfilter.c
auditsc.c
backtracetest.c
bounds.c
capability.c
cfi.c
compat.c
configs.c
context_tracking.c
cpu_pm.c
cpu.c
crash_core.c
crash_dump.c
cred.c
delayacct.c
dma.c
exec_domain.c
exit.c
extable.c
fail_function.c
fork.c mm: drop the assumption that VM_SHARED always implies writable 2025-08-28 16:28:39 +02:00
freezer.c sched,freezer: Remove unnecessary warning in __thaw_task 2025-08-15 12:09:07 +02:00
gen_kheaders.sh
groups.c
hung_task.c
iomem.c
irq_work.c
jump_label.c
kallsyms_internal.h
kallsyms_selftest.c
kallsyms_selftest.h
kallsyms.c
kcmp.c
Kconfig.freezer
Kconfig.hz
Kconfig.kexec
Kconfig.locks
Kconfig.preempt
kcov.c
kexec_core.c
kexec_elf.c
kexec_file.c
kexec_internal.h
kexec.c
kheaders.c
kprobes.c
ksyms_common.c
ksysfs.c
kthread.c
latencytop.c
Makefile
module_signature.c
notifier.c
nsproxy.c
numa.c
padata.c
panic.c
params.c
pid_namespace.c
pid_sysctl.h
pid.c
profile.c
ptrace.c
range.c
reboot.c
regset.c
relay.c
resource_kunit.c
resource.c
rseq.c
scftorture.c
scs.c
seccomp.c
signal.c
smp.c
smpboot.c
smpboot.h
softirq.c
stackleak.c
stacktrace.c
static_call_inline.c
static_call.c
stop_machine.c
sys_ni.c
sys.c
sysctl-test.c
sysctl.c
task_work.c
taskstats.c
torture.c
tracepoint.c
tsacct.c
ucount.c ucount: fix atomic_long_inc_below() argument type 2025-08-15 12:08:57 +02:00
uid16.c
uid16.h
umh.c
up.c
user_namespace.c
user-return-notifier.c
user.c
usermode_driver.c
utsname_sysctl.c
utsname.c
vhost_task.c
watch_queue.c
watchdog_buddy.c
watchdog_perf.c
watchdog.c
workqueue_internal.h
workqueue.c