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

Configure Feed

Select the types of activity you want to include in your feed.

mm: make mmap_region() internal

Now that we have removed the one user of mmap_region() outside of mm, make
it internal and add it to vma.c so it can be userland tested.

This ensures that all external memory mappings are performed using the
appropriate interfaces and allows us to modify memory mapping logic as we
see fit.

Additionally expand test stubs to allow for the mmap_region() code to
compile and be userland testable.

Link: https://lkml.kernel.org/r/de5a3c574d35c26237edf20a1d8652d7305709c9.1735819274.git.lorenzo.stoakes@oracle.com
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
Cc: Jann Horn <jannh@google.com>
Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Lorenzo Stoakes and committed by
Andrew Morton
f8d4a6ca c4f1b56f

+126 -64
-3
include/linux/mm.h
··· 3363 3363 return __get_unmapped_area(file, addr, len, pgoff, flags, 0); 3364 3364 } 3365 3365 3366 - extern unsigned long mmap_region(struct file *file, unsigned long addr, 3367 - unsigned long len, vm_flags_t vm_flags, unsigned long pgoff, 3368 - struct list_head *uf); 3369 3366 extern unsigned long do_mmap(struct file *file, unsigned long addr, 3370 3367 unsigned long len, unsigned long prot, unsigned long flags, 3371 3368 vm_flags_t vm_flags, unsigned long pgoff, unsigned long *populate,
-59
mm/mmap.c
··· 1072 1072 return do_vmi_munmap(&vmi, mm, start, len, uf, false); 1073 1073 } 1074 1074 1075 - /** 1076 - * mmap_region() - Actually perform the userland mapping of a VMA into 1077 - * current->mm with known, aligned and overflow-checked @addr and @len, and 1078 - * correctly determined VMA flags @vm_flags and page offset @pgoff. 1079 - * 1080 - * This is an internal memory management function, and should not be used 1081 - * directly. 1082 - * 1083 - * The caller must write-lock current->mm->mmap_lock. 1084 - * 1085 - * @file: If a file-backed mapping, a pointer to the struct file describing the 1086 - * file to be mapped, otherwise NULL. 1087 - * @addr: The page-aligned address at which to perform the mapping. 1088 - * @len: The page-aligned, non-zero, length of the mapping. 1089 - * @vm_flags: The VMA flags which should be applied to the mapping. 1090 - * @pgoff: If @file is specified, the page offset into the file, if not then 1091 - * the virtual page offset in memory of the anonymous mapping. 1092 - * @uf: Optionally, a pointer to a list head used for tracking userfaultfd unmap 1093 - * events. 1094 - * 1095 - * Returns: Either an error, or the address at which the requested mapping has 1096 - * been performed. 1097 - */ 1098 - unsigned long mmap_region(struct file *file, unsigned long addr, 1099 - unsigned long len, vm_flags_t vm_flags, unsigned long pgoff, 1100 - struct list_head *uf) 1101 - { 1102 - unsigned long ret; 1103 - bool writable_file_mapping = false; 1104 - 1105 - mmap_assert_write_locked(current->mm); 1106 - 1107 - /* Check to see if MDWE is applicable. */ 1108 - if (map_deny_write_exec(vm_flags, vm_flags)) 1109 - return -EACCES; 1110 - 1111 - /* Allow architectures to sanity-check the vm_flags. */ 1112 - if (!arch_validate_flags(vm_flags)) 1113 - return -EINVAL; 1114 - 1115 - /* Map writable and ensure this isn't a sealed memfd. */ 1116 - if (file && is_shared_maywrite(vm_flags)) { 1117 - int error = mapping_map_writable(file->f_mapping); 1118 - 1119 - if (error) 1120 - return error; 1121 - writable_file_mapping = true; 1122 - } 1123 - 1124 - ret = __mmap_region(file, addr, len, vm_flags, pgoff, uf); 1125 - 1126 - /* Clear our write mapping regardless of error. */ 1127 - if (writable_file_mapping) 1128 - mapping_unmap_writable(file->f_mapping); 1129 - 1130 - validate_mm(current->mm); 1131 - return ret; 1132 - } 1133 - 1134 1075 int vm_munmap(unsigned long start, size_t len) 1135 1076 { 1136 1077 return __vm_munmap(start, len, false);
+60 -1
mm/vma.c
··· 2431 2431 vma_set_page_prot(vma); 2432 2432 } 2433 2433 2434 - unsigned long __mmap_region(struct file *file, unsigned long addr, 2434 + static unsigned long __mmap_region(struct file *file, unsigned long addr, 2435 2435 unsigned long len, vm_flags_t vm_flags, unsigned long pgoff, 2436 2436 struct list_head *uf) 2437 2437 { ··· 2481 2481 abort_munmap: 2482 2482 vms_abort_munmap_vmas(&map.vms, &map.mas_detach); 2483 2483 return error; 2484 + } 2485 + 2486 + /** 2487 + * mmap_region() - Actually perform the userland mapping of a VMA into 2488 + * current->mm with known, aligned and overflow-checked @addr and @len, and 2489 + * correctly determined VMA flags @vm_flags and page offset @pgoff. 2490 + * 2491 + * This is an internal memory management function, and should not be used 2492 + * directly. 2493 + * 2494 + * The caller must write-lock current->mm->mmap_lock. 2495 + * 2496 + * @file: If a file-backed mapping, a pointer to the struct file describing the 2497 + * file to be mapped, otherwise NULL. 2498 + * @addr: The page-aligned address at which to perform the mapping. 2499 + * @len: The page-aligned, non-zero, length of the mapping. 2500 + * @vm_flags: The VMA flags which should be applied to the mapping. 2501 + * @pgoff: If @file is specified, the page offset into the file, if not then 2502 + * the virtual page offset in memory of the anonymous mapping. 2503 + * @uf: Optionally, a pointer to a list head used for tracking userfaultfd unmap 2504 + * events. 2505 + * 2506 + * Returns: Either an error, or the address at which the requested mapping has 2507 + * been performed. 2508 + */ 2509 + unsigned long mmap_region(struct file *file, unsigned long addr, 2510 + unsigned long len, vm_flags_t vm_flags, unsigned long pgoff, 2511 + struct list_head *uf) 2512 + { 2513 + unsigned long ret; 2514 + bool writable_file_mapping = false; 2515 + 2516 + mmap_assert_write_locked(current->mm); 2517 + 2518 + /* Check to see if MDWE is applicable. */ 2519 + if (map_deny_write_exec(vm_flags, vm_flags)) 2520 + return -EACCES; 2521 + 2522 + /* Allow architectures to sanity-check the vm_flags. */ 2523 + if (!arch_validate_flags(vm_flags)) 2524 + return -EINVAL; 2525 + 2526 + /* Map writable and ensure this isn't a sealed memfd. */ 2527 + if (file && is_shared_maywrite(vm_flags)) { 2528 + int error = mapping_map_writable(file->f_mapping); 2529 + 2530 + if (error) 2531 + return error; 2532 + writable_file_mapping = true; 2533 + } 2534 + 2535 + ret = __mmap_region(file, addr, len, vm_flags, pgoff, uf); 2536 + 2537 + /* Clear our write mapping regardless of error. */ 2538 + if (writable_file_mapping) 2539 + mapping_unmap_writable(file->f_mapping); 2540 + 2541 + validate_mm(current->mm); 2542 + return ret; 2484 2543 } 2485 2544 2486 2545 /*
+1 -1
mm/vma.h
··· 241 241 int mm_take_all_locks(struct mm_struct *mm); 242 242 void mm_drop_all_locks(struct mm_struct *mm); 243 243 244 - unsigned long __mmap_region(struct file *file, unsigned long addr, 244 + unsigned long mmap_region(struct file *file, unsigned long addr, 245 245 unsigned long len, vm_flags_t vm_flags, unsigned long pgoff, 246 246 struct list_head *uf); 247 247
+65
tools/testing/vma/vma_internal.h
··· 41 41 #define VM_BUG_ON(_expr) (BUG_ON(_expr)) 42 42 #define VM_BUG_ON_VMA(_expr, _vma) (BUG_ON(_expr)) 43 43 44 + #define MMF_HAS_MDWE 28 45 + 44 46 #define VM_NONE 0x00000000 45 47 #define VM_READ 0x00000001 46 48 #define VM_WRITE 0x00000002 ··· 228 226 unsigned long stack_vm; /* VM_STACK */ 229 227 230 228 unsigned long def_flags; 229 + 230 + unsigned long flags; /* Must use atomic bitops to access */ 231 231 }; 232 232 233 233 struct vma_lock { ··· 1187 1183 static inline void userfaultfd_unmap_complete(struct mm_struct *mm, 1188 1184 struct list_head *uf) 1189 1185 { 1186 + } 1187 + 1188 + /* 1189 + * Denies creating a writable executable mapping or gaining executable permissions. 1190 + * 1191 + * This denies the following: 1192 + * 1193 + * a) mmap(PROT_WRITE | PROT_EXEC) 1194 + * 1195 + * b) mmap(PROT_WRITE) 1196 + * mprotect(PROT_EXEC) 1197 + * 1198 + * c) mmap(PROT_WRITE) 1199 + * mprotect(PROT_READ) 1200 + * mprotect(PROT_EXEC) 1201 + * 1202 + * But allows the following: 1203 + * 1204 + * d) mmap(PROT_READ | PROT_EXEC) 1205 + * mmap(PROT_READ | PROT_EXEC | PROT_BTI) 1206 + * 1207 + * This is only applicable if the user has set the Memory-Deny-Write-Execute 1208 + * (MDWE) protection mask for the current process. 1209 + * 1210 + * @old specifies the VMA flags the VMA originally possessed, and @new the ones 1211 + * we propose to set. 1212 + * 1213 + * Return: false if proposed change is OK, true if not ok and should be denied. 1214 + */ 1215 + static inline bool map_deny_write_exec(unsigned long old, unsigned long new) 1216 + { 1217 + /* If MDWE is disabled, we have nothing to deny. */ 1218 + if (!test_bit(MMF_HAS_MDWE, &current->mm->flags)) 1219 + return false; 1220 + 1221 + /* If the new VMA is not executable, we have nothing to deny. */ 1222 + if (!(new & VM_EXEC)) 1223 + return false; 1224 + 1225 + /* Under MDWE we do not accept newly writably executable VMAs... */ 1226 + if (new & VM_WRITE) 1227 + return true; 1228 + 1229 + /* ...nor previously non-executable VMAs becoming executable. */ 1230 + if (!(old & VM_EXEC)) 1231 + return true; 1232 + 1233 + return false; 1234 + } 1235 + 1236 + static inline int mapping_map_writable(struct address_space *mapping) 1237 + { 1238 + int c = atomic_read(&mapping->i_mmap_writable); 1239 + 1240 + /* Derived from the raw_atomic_inc_unless_negative() implementation. */ 1241 + do { 1242 + if (c < 0) 1243 + return -EPERM; 1244 + } while (!__sync_bool_compare_and_swap(&mapping->i_mmap_writable, c, c+1)); 1245 + 1246 + return 0; 1190 1247 } 1191 1248 1192 1249 #endif /* __MM_VMA_INTERNAL_H */