Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: add a NO_INHERIT flag to the PR_SET_MDWE prctl

This extends the current PR_SET_MDWE prctl arg with a bit to indicate that
the process doesn't want MDWE protection to propagate to children.

To implement this no-inherit mode, the tag in current->mm->flags must be
absent from MMF_INIT_MASK. This means that the encoding for "MDWE but
without inherit" is different in the prctl than in the mm flags. This
leads to a bit of bit-mangling in the prctl implementation.

Link: https://lkml.kernel.org/r/20230828150858.393570-6-revest@chromium.org
Signed-off-by: Florent Revest <revest@chromium.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Alexey Izbyshev <izbyshev@ispras.ru>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Ayush Jain <ayush.jain3@amd.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Joey Gouly <joey.gouly@arm.com>
Cc: KP Singh <kpsingh@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Szabolcs Nagy <Szabolcs.Nagy@arm.com>
Cc: Topi Miettinen <toiwoton@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Florent Revest and committed by
Andrew Morton
24e41bf8 0da66833

+39 -7
+10
include/linux/sched/coredump.h
··· 91 91 MMF_DISABLE_THP_MASK | MMF_HAS_MDWE_MASK) 92 92 93 93 #define MMF_VM_MERGE_ANY 29 94 + #define MMF_HAS_MDWE_NO_INHERIT 30 95 + 96 + static inline unsigned long mmf_init_flags(unsigned long flags) 97 + { 98 + if (flags & (1UL << MMF_HAS_MDWE_NO_INHERIT)) 99 + flags &= ~((1UL << MMF_HAS_MDWE) | 100 + (1UL << MMF_HAS_MDWE_NO_INHERIT)); 101 + return flags & MMF_INIT_MASK; 102 + } 103 + 94 104 #endif /* _LINUX_SCHED_COREDUMP_H */
+1
include/uapi/linux/prctl.h
··· 284 284 /* Memory deny write / execute */ 285 285 #define PR_SET_MDWE 65 286 286 # define PR_MDWE_REFUSE_EXEC_GAIN (1UL << 0) 287 + # define PR_MDWE_NO_INHERIT (1UL << 1) 287 288 288 289 #define PR_GET_MDWE 66 289 290
+1 -1
kernel/fork.c
··· 1288 1288 hugetlb_count_init(mm); 1289 1289 1290 1290 if (current->mm) { 1291 - mm->flags = current->mm->flags & MMF_INIT_MASK; 1291 + mm->flags = mmf_init_flags(current->mm->flags); 1292 1292 mm->def_flags = current->mm->def_flags & VM_INIT_DEF_MASK; 1293 1293 } else { 1294 1294 mm->flags = default_dump_filter;
+26 -6
kernel/sys.c
··· 2368 2368 } 2369 2369 #endif /* CONFIG_ANON_VMA_NAME */ 2370 2370 2371 + static inline unsigned long get_current_mdwe(void) 2372 + { 2373 + unsigned long ret = 0; 2374 + 2375 + if (test_bit(MMF_HAS_MDWE, &current->mm->flags)) 2376 + ret |= PR_MDWE_REFUSE_EXEC_GAIN; 2377 + if (test_bit(MMF_HAS_MDWE_NO_INHERIT, &current->mm->flags)) 2378 + ret |= PR_MDWE_NO_INHERIT; 2379 + 2380 + return ret; 2381 + } 2382 + 2371 2383 static inline int prctl_set_mdwe(unsigned long bits, unsigned long arg3, 2372 2384 unsigned long arg4, unsigned long arg5) 2373 2385 { 2386 + unsigned long current_bits; 2387 + 2374 2388 if (arg3 || arg4 || arg5) 2375 2389 return -EINVAL; 2376 2390 2377 - if (bits & ~(PR_MDWE_REFUSE_EXEC_GAIN)) 2391 + if (bits & ~(PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT)) 2378 2392 return -EINVAL; 2379 2393 2394 + /* NO_INHERIT only makes sense with REFUSE_EXEC_GAIN */ 2395 + if (bits & PR_MDWE_NO_INHERIT && !(bits & PR_MDWE_REFUSE_EXEC_GAIN)) 2396 + return -EINVAL; 2397 + 2398 + current_bits = get_current_mdwe(); 2399 + if (current_bits && current_bits != bits) 2400 + return -EPERM; /* Cannot unset the flags */ 2401 + 2402 + if (bits & PR_MDWE_NO_INHERIT) 2403 + set_bit(MMF_HAS_MDWE_NO_INHERIT, &current->mm->flags); 2380 2404 if (bits & PR_MDWE_REFUSE_EXEC_GAIN) 2381 2405 set_bit(MMF_HAS_MDWE, &current->mm->flags); 2382 - else if (test_bit(MMF_HAS_MDWE, &current->mm->flags)) 2383 - return -EPERM; /* Cannot unset the flag */ 2384 2406 2385 2407 return 0; 2386 2408 } ··· 2412 2390 { 2413 2391 if (arg2 || arg3 || arg4 || arg5) 2414 2392 return -EINVAL; 2415 - 2416 - return test_bit(MMF_HAS_MDWE, &current->mm->flags) ? 2417 - PR_MDWE_REFUSE_EXEC_GAIN : 0; 2393 + return get_current_mdwe(); 2418 2394 } 2419 2395 2420 2396 static int prctl_get_auxv(void __user *addr, unsigned long len)
+1
tools/include/uapi/linux/prctl.h
··· 284 284 /* Memory deny write / execute */ 285 285 #define PR_SET_MDWE 65 286 286 # define PR_MDWE_REFUSE_EXEC_GAIN (1UL << 0) 287 + # define PR_MDWE_NO_INHERIT (1UL << 1) 287 288 288 289 #define PR_GET_MDWE 66 289 290