Pull MAP_DENYWRITE removal from David Hildenbrand: "Remove all in-tree usage of MAP_DENYWRITE from the kernel and remove VM_DENYWRITE. There are some (minor) user-visible changes: - We no longer deny write access to shared libaries loaded via legacy uselib(); this behavior matches modern user space e.g. dlopen(). - We no longer deny write access to the elf interpreter after exec completed, treating it just like shared libraries (which it often is). - We always deny write access to the file linked via /proc/pid/exe: sys_prctl(PR_SET_MM_MAP/EXE_FILE) will fail if write access to the file cannot be denied, and write access to the file will remain denied until the link is effectivel gone (exec, termination, sys_prctl(PR_SET_MM_MAP/EXE_FILE)) -- just as if exec'ing the file. Cross-compiled for a bunch of architectures (alpha, microblaze, i386, s390x, ...) and verified via ltp that especially the relevant tests (i.e., creat07 and execve04) continue working as expected" * tag 'denywrite-for-5.15' of git://github.com/davidhildenbrand/linux: fs: update documentation of get_write_access() and friends mm: ignore MAP_DENYWRITE in ksys_mmap_pgoff() mm: remove VM_DENYWRITE binfmt: remove in-tree usage of MAP_DENYWRITE kernel/fork: always deny write access to current MM exe_file kernel/fork: factor out replacing the current MM exe_file binfmt: don't use MAP_DENYWRITE when loading shared libraries via uselib()
Unified · Split
| @@ -202,8 +202,7 @@ static int load_aout_binary(struct linux_binprm *bprm) · 201 unmodified lines | ||
| 202 | 202 | |
| 203 | 203 | error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, |
| 204 | 204 | PROT_READ | PROT_EXEC, |
| 205 | − MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | | |
| 206 | − MAP_32BIT, | |
| 205 | + MAP_FIXED | MAP_PRIVATE | MAP_32BIT, | |
| 207 | 206 | fd_offset); |
| 208 | 207 | |
| 209 | 208 | if (error != N_TXTADDR(ex)) |
| @@ -211,8 +210,7 @@ static int load_aout_binary(struct linux_binprm *bprm) · 1 unmodified line | ||
| 211 | 210 | |
| 212 | 211 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, |
| 213 | 212 | PROT_READ | PROT_WRITE | PROT_EXEC, |
| 214 | − MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | | |
| 215 | − MAP_32BIT, | |
| 213 | + MAP_FIXED | MAP_PRIVATE | MAP_32BIT, | |
| 216 | 214 | fd_offset + ex.a_text); |
| 217 | 215 | if (error != N_DATADDR(ex)) |
| 218 | 216 | return error; |
| @@ -293,7 +291,7 @@ static int load_aout_library(struct file *file) · 74 unmodified lines | ||
| 293 | 291 | /* Now use mmap to map the library into memory. */ |
| 294 | 292 | error = vm_mmap(file, start_addr, ex.a_text + ex.a_data, |
| 295 | 293 | PROT_READ | PROT_WRITE | PROT_EXEC, |
| 296 | − MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_32BIT, | |
| 294 | + MAP_FIXED | MAP_PRIVATE | MAP_32BIT, | |
| 297 | 295 | N_TXTOFF(ex)); |
| 298 | 296 | retval = error; |
| 299 | 297 | if (error != start_addr) |
| @@ -221,8 +221,7 @@ static int load_aout_binary(struct linux_binprm * bprm) · 220 unmodified lines | ||
| 221 | 221 | } |
| 222 | 222 | |
| 223 | 223 | error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, |
| 224 | − PROT_READ | PROT_EXEC, | |
| 225 | − MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, | |
| 224 | + PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, | |
| 226 | 225 | fd_offset); |
| 227 | 226 | |
| 228 | 227 | if (error != N_TXTADDR(ex)) |
| @@ -230,7 +229,7 @@ static int load_aout_binary(struct linux_binprm * bprm) · 1 unmodified line | ||
| 230 | 229 | |
| 231 | 230 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, |
| 232 | 231 | PROT_READ | PROT_WRITE | PROT_EXEC, |
| 233 | − MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, | |
| 232 | + MAP_FIXED | MAP_PRIVATE, | |
| 234 | 233 | fd_offset + ex.a_text); |
| 235 | 234 | if (error != N_DATADDR(ex)) |
| 236 | 235 | return error; |
| @@ -309,7 +308,7 @@ static int load_aout_library(struct file *file) · 72 unmodified lines | ||
| 309 | 308 | /* Now use mmap to map the library into memory. */ |
| 310 | 309 | error = vm_mmap(file, start_addr, ex.a_text + ex.a_data, |
| 311 | 310 | PROT_READ | PROT_WRITE | PROT_EXEC, |
| 312 | − MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, | |
| 311 | + MAP_FIXED | MAP_PRIVATE; | |
| 313 | 312 | N_TXTOFF(ex)); |
| 314 | 313 | retval = error; |
| 315 | 314 | if (error != start_addr) |
| @@ -622,7 +622,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, · 621 unmodified lines | ||
| 622 | 622 | eppnt = interp_elf_phdata; |
| 623 | 623 | for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { |
| 624 | 624 | if (eppnt->p_type == PT_LOAD) { |
| 625 | − int elf_type = MAP_PRIVATE | MAP_DENYWRITE; | |
| 625 | + int elf_type = MAP_PRIVATE; | |
| 626 | 626 | int elf_prot = make_prot(eppnt->p_flags, arch_state, |
| 627 | 627 | true, true); |
| 628 | 628 | unsigned long vaddr = 0; |
| @@ -1070,7 +1070,7 @@ out_free_interp: · 441 unmodified lines | ||
| 1070 | 1070 | elf_prot = make_prot(elf_ppnt->p_flags, &arch_state, |
| 1071 | 1071 | !!interpreter, false); |
| 1072 | 1072 | |
| 1073 | − elf_flags = MAP_PRIVATE | MAP_DENYWRITE; | |
| 1073 | + elf_flags = MAP_PRIVATE; | |
| 1074 | 1074 | |
| 1075 | 1075 | vaddr = elf_ppnt->p_vaddr; |
| 1076 | 1076 | /* |
| @@ -1384,7 +1384,7 @@ static int load_elf_library(struct file *file) · 307 unmodified lines | ||
| 1384 | 1384 | (eppnt->p_filesz + |
| 1385 | 1385 | ELF_PAGEOFFSET(eppnt->p_vaddr)), |
| 1386 | 1386 | PROT_READ | PROT_WRITE | PROT_EXEC, |
| 1387 | − MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_DENYWRITE, | |
| 1387 | + MAP_FIXED_NOREPLACE | MAP_PRIVATE, | |
| 1388 | 1388 | (eppnt->p_offset - |
| 1389 | 1389 | ELF_PAGEOFFSET(eppnt->p_vaddr))); |
| 1390 | 1390 | if (error != ELF_PAGESTART(eppnt->p_vaddr)) |
| @@ -1041,7 +1041,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, · 1040 unmodified lines | ||
| 1041 | 1041 | if (phdr->p_flags & PF_W) prot |= PROT_WRITE; |
| 1042 | 1042 | if (phdr->p_flags & PF_X) prot |= PROT_EXEC; |
| 1043 | 1043 | |
| 1044 | − flags = MAP_PRIVATE | MAP_DENYWRITE; | |
| 1044 | + flags = MAP_PRIVATE; | |
| 1045 | 1045 | maddr = 0; |
| 1046 | 1046 | |
| 1047 | 1047 | switch (params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) { |
| @@ -1272,7 +1272,9 @@ int begin_new_exec(struct linux_binprm * bprm) · 1271 unmodified lines | ||
| 1272 | 1272 | * not visibile until then. This also enables the update |
| 1273 | 1273 | * to be lockless. |
| 1274 | 1274 | */ |
| 1275 | − set_mm_exe_file(bprm->mm, bprm->file); | |
| 1275 | + retval = set_mm_exe_file(bprm->mm, bprm->file); | |
| 1276 | + if (retval) | |
| 1277 | + goto out; | |
| 1276 | 1278 | |
| 1277 | 1279 | /* If the binary is not readable then enforce mm->dumpable=0 */ |
| 1278 | 1280 | would_dump(bprm, bprm->file); |
| @@ -619,7 +619,6 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma) · 618 unmodified lines | ||
| 619 | 619 | [ilog2(VM_MAYSHARE)] = "ms", |
| 620 | 620 | [ilog2(VM_GROWSDOWN)] = "gd", |
| 621 | 621 | [ilog2(VM_PFNMAP)] = "pf", |
| 622 | − [ilog2(VM_DENYWRITE)] = "dw", | |
| 623 | 622 | [ilog2(VM_LOCKED)] = "lo", |
| 624 | 623 | [ilog2(VM_IO)] = "io", |
| 625 | 624 | [ilog2(VM_SEQ_READ)] = "sr", |
| @@ -3023,15 +3023,20 @@ static inline void file_end_write(struct file *file) · 3022 unmodified lines | ||
| 3023 | 3023 | } |
| 3024 | 3024 | |
| 3025 | 3025 | /* |
| 3026 | + * This is used for regular files where some users -- especially the | |
| 3027 | + * currently executed binary in a process, previously handled via | |
| 3028 | + * VM_DENYWRITE -- cannot handle concurrent write (and maybe mmap | |
| 3029 | + * read-write shared) accesses. | |
| 3030 | + * | |
| 3026 | 3031 | * get_write_access() gets write permission for a file. |
| 3027 | 3032 | * put_write_access() releases this write permission. |
| 3028 | − * This is used for regular files. | |
| 3029 | − * We cannot support write (and maybe mmap read-write shared) accesses and | |
| 3030 | − * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode | |
| 3031 | − * can have the following values: | |
| 3032 | − * 0: no writers, no VM_DENYWRITE mappings | |
| 3033 | − * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist | |
| 3034 | − * > 0: (i_writecount) users are writing to the file. | |
| 3033 | + * deny_write_access() denies write access to a file. | |
| 3034 | + * allow_write_access() re-enables write access to a file. | |
| 3035 | + * | |
| 3036 | + * The i_writecount field of an inode can have the following values: | |
| 3037 | + * 0: no write access, no denied write access | |
| 3038 | + * < 0: (-i_writecount) users that denied write access to the file. | |
| 3039 | + * > 0: (i_writecount) users that have write access to the file. | |
| 3035 | 3040 | * |
| 3036 | 3041 | * Normally we operate on that counter with atomic_{inc,dec} and it's safe |
| 3037 | 3042 | * except for the cases where we don't hold i_writecount yet. Then we need to |
| @@ -281,7 +281,6 @@ extern unsigned int kobjsize(const void *objp); · 280 unmodified lines | ||
| 281 | 281 | #define VM_GROWSDOWN 0x00000100 /* general info on the segment */ |
| 282 | 282 | #define VM_UFFD_MISSING 0x00000200 /* missing pages tracking */ |
| 283 | 283 | #define VM_PFNMAP 0x00000400 /* Page-ranges managed without "struct page", just pure PFN */ |
| 284 | −#define VM_DENYWRITE 0x00000800 /* ETXTBSY on write attempts.. */ | |
| 285 | 284 | #define VM_UFFD_WP 0x00001000 /* wrprotect pages tracking */ |
| 286 | 285 | |
| 287 | 286 | #define VM_LOCKED 0x00002000 |
| @@ -2573,7 +2572,8 @@ static inline int check_data_rlimit(unsigned long rlim, · 2285 unmodified lines | ||
| 2573 | 2572 | extern int mm_take_all_locks(struct mm_struct *mm); |
| 2574 | 2573 | extern void mm_drop_all_locks(struct mm_struct *mm); |
| 2575 | 2574 | |
| 2576 | −extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file); | |
| 2575 | +extern int set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file); | |
| 2576 | +extern int replace_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file); | |
| 2577 | 2577 | extern struct file *get_mm_exe_file(struct mm_struct *mm); |
| 2578 | 2578 | extern struct file *get_task_exe_file(struct task_struct *task); |
| 2579 | 2579 | |
| @@ -32,7 +32,8 @@ · 31 unmodified lines | ||
| 32 | 32 | * The historical set of flags that all mmap implementations implicitly |
| 33 | 33 | * support when a ->mmap_validate() op is not provided in file_operations. |
| 34 | 34 | * |
| 35 | − * MAP_EXECUTABLE is completely ignored throughout the kernel. | |
| 35 | + * MAP_EXECUTABLE and MAP_DENYWRITE are completely ignored throughout the | |
| 36 | + * kernel. | |
| 36 | 37 | */ |
| 37 | 38 | #define LEGACY_MAP_MASK (MAP_SHARED \ |
| 38 | 39 | | MAP_PRIVATE \ |
| @@ -153,7 +154,6 @@ static inline unsigned long · 114 unmodified lines | ||
| 153 | 154 | calc_vm_flag_bits(unsigned long flags) |
| 154 | 155 | { |
| 155 | 156 | return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) | |
| 156 | − _calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) | | |
| 157 | 157 | _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ) | |
| 158 | 158 | _calc_vm_trans(flags, MAP_SYNC, VM_SYNC ) | |
| 159 | 159 | arch_calc_vm_flag_bits(flags); |
| @@ -165,7 +165,6 @@ IF_HAVE_PG_SKIP_KASAN_POISON(PG_skip_kasan_poison, "skip_kasan_poison") · 164 unmodified lines | ||
| 165 | 165 | {VM_UFFD_MISSING, "uffd_missing" }, \ |
| 166 | 166 | IF_HAVE_UFFD_MINOR(VM_UFFD_MINOR, "uffd_minor" ) \ |
| 167 | 167 | {VM_PFNMAP, "pfnmap" }, \ |
| 168 | − {VM_DENYWRITE, "denywrite" }, \ | |
| 169 | 168 | {VM_UFFD_WP, "uffd_wp" }, \ |
| 170 | 169 | {VM_LOCKED, "locked" }, \ |
| 171 | 170 | {VM_IO, "io" }, \ |
| @@ -8320,8 +8320,6 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) · 8319 unmodified lines | ||
| 8320 | 8320 | else |
| 8321 | 8321 | flags = MAP_PRIVATE; |
| 8322 | 8322 | |
| 8323 | − if (vma->vm_flags & VM_DENYWRITE) | |
| 8324 | − flags |= MAP_DENYWRITE; | |
| 8325 | 8323 | if (vma->vm_flags & VM_LOCKED) |
| 8326 | 8324 | flags |= MAP_LOCKED; |
| 8327 | 8325 | if (is_vm_hugetlb_page(vma)) |
| @@ -471,6 +471,20 @@ void free_task(struct task_struct *tsk) · 470 unmodified lines | ||
| 471 | 471 | } |
| 472 | 472 | EXPORT_SYMBOL(free_task); |
| 473 | 473 | |
| 474 | +static void dup_mm_exe_file(struct mm_struct *mm, struct mm_struct *oldmm) | |
| 475 | +{ | |
| 476 | + struct file *exe_file; | |
| 477 | + | |
| 478 | + exe_file = get_mm_exe_file(oldmm); | |
| 479 | + RCU_INIT_POINTER(mm->exe_file, exe_file); | |
| 480 | + /* | |
| 481 | + * We depend on the oldmm having properly denied write access to the | |
| 482 | + * exe_file already. | |
| 483 | + */ | |
| 484 | + if (exe_file && deny_write_access(exe_file)) | |
| 485 | + pr_warn_once("deny_write_access() failed in %s\n", __func__); | |
| 486 | +} | |
| 487 | + | |
| 474 | 488 | #ifdef CONFIG_MMU |
| 475 | 489 | static __latent_entropy int dup_mmap(struct mm_struct *mm, |
| 476 | 490 | struct mm_struct *oldmm) |
| @@ -494,7 +508,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, · 17 unmodified lines | ||
| 494 | 508 | mmap_write_lock_nested(mm, SINGLE_DEPTH_NESTING); |
| 495 | 509 | |
| 496 | 510 | /* No ordering required: file already has been exposed. */ |
| 497 | − RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm)); | |
| 511 | + dup_mm_exe_file(mm, oldmm); | |
| 498 | 512 | |
| 499 | 513 | mm->total_vm = oldmm->total_vm; |
| 500 | 514 | mm->data_vm = oldmm->data_vm; |
| @@ -557,12 +571,9 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, · 56 unmodified lines | ||
| 557 | 571 | tmp->vm_flags &= ~(VM_LOCKED | VM_LOCKONFAULT); |
| 558 | 572 | file = tmp->vm_file; |
| 559 | 573 | if (file) { |
| 560 | − struct inode *inode = file_inode(file); | |
| 561 | 574 | struct address_space *mapping = file->f_mapping; |
| 562 | 575 | |
| 563 | 576 | get_file(file); |
| 564 | − if (tmp->vm_flags & VM_DENYWRITE) | |
| 565 | − put_write_access(inode); | |
| 566 | 577 | i_mmap_lock_write(mapping); |
| 567 | 578 | if (tmp->vm_flags & VM_SHARED) |
| 568 | 579 | mapping_allow_writable(mapping); |
| @@ -640,7 +651,7 @@ static inline void mm_free_pgd(struct mm_struct *mm) · 71 unmodified lines | ||
| 640 | 651 | static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) |
| 641 | 652 | { |
| 642 | 653 | mmap_write_lock(oldmm); |
| 643 | − RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm)); | |
| 654 | + dup_mm_exe_file(mm, oldmm); | |
| 644 | 655 | mmap_write_unlock(oldmm); |
| 645 | 656 | return 0; |
| 646 | 657 | } |
| @@ -1150,11 +1161,11 @@ void mmput_async(struct mm_struct *mm) · 503 unmodified lines | ||
| 1150 | 1161 | * |
| 1151 | 1162 | * Main users are mmput() and sys_execve(). Callers prevent concurrent |
| 1152 | 1163 | * invocations: in mmput() nobody alive left, in execve task is single |
| 1153 | − * threaded. sys_prctl(PR_SET_MM_MAP/EXE_FILE) also needs to set the | |
| 1154 | − * mm->exe_file, but does so without using set_mm_exe_file() in order | |
| 1155 | − * to avoid the need for any locks. | |
| 1164 | + * threaded. | |
| 1165 | + * | |
| 1166 | + * Can only fail if new_exe_file != NULL. | |
| 1156 | 1167 | */ |
| 1157 | −void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) | |
| 1168 | +int set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) | |
| 1158 | 1169 | { |
| 1159 | 1170 | struct file *old_exe_file; |
| 1160 | 1171 | |
| @@ -1165,11 +1176,73 @@ void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) · 4 unmodified lines | ||
| 1165 | 1176 | */ |
| 1166 | 1177 | old_exe_file = rcu_dereference_raw(mm->exe_file); |
| 1167 | 1178 | |
| 1168 | − if (new_exe_file) | |
| 1179 | + if (new_exe_file) { | |
| 1180 | + /* | |
| 1181 | + * We expect the caller (i.e., sys_execve) to already denied | |
| 1182 | + * write access, so this is unlikely to fail. | |
| 1183 | + */ | |
| 1184 | + if (unlikely(deny_write_access(new_exe_file))) | |
| 1185 | + return -EACCES; | |
| 1169 | 1186 | get_file(new_exe_file); |
| 1187 | + } | |
| 1170 | 1188 | rcu_assign_pointer(mm->exe_file, new_exe_file); |
| 1171 | − if (old_exe_file) | |
| 1189 | + if (old_exe_file) { | |
| 1190 | + allow_write_access(old_exe_file); | |
| 1172 | 1191 | fput(old_exe_file); |
| 1192 | + } | |
| 1193 | + return 0; | |
| 1194 | +} | |
| 1195 | + | |
| 1196 | +/** | |
| 1197 | + * replace_mm_exe_file - replace a reference to the mm's executable file | |
| 1198 | + * | |
| 1199 | + * This changes mm's executable file (shown as symlink /proc/[pid]/exe), | |
| 1200 | + * dealing with concurrent invocation and without grabbing the mmap lock in | |
| 1201 | + * write mode. | |
| 1202 | + * | |
| 1203 | + * Main user is sys_prctl(PR_SET_MM_MAP/EXE_FILE). | |
| 1204 | + */ | |
| 1205 | +int replace_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) | |
| 1206 | +{ | |
| 1207 | + struct vm_area_struct *vma; | |
| 1208 | + struct file *old_exe_file; | |
| 1209 | + int ret = 0; | |
| 1210 | + | |
| 1211 | + /* Forbid mm->exe_file change if old file still mapped. */ | |
| 1212 | + old_exe_file = get_mm_exe_file(mm); | |
| 1213 | + if (old_exe_file) { | |
| 1214 | + mmap_read_lock(mm); | |
| 1215 | + for (vma = mm->mmap; vma && !ret; vma = vma->vm_next) { | |
| 1216 | + if (!vma->vm_file) | |
| 1217 | + continue; | |
| 1218 | + if (path_equal(&vma->vm_file->f_path, | |
| 1219 | + &old_exe_file->f_path)) | |
| 1220 | + ret = -EBUSY; | |
| 1221 | + } | |
| 1222 | + mmap_read_unlock(mm); | |
| 1223 | + fput(old_exe_file); | |
| 1224 | + if (ret) | |
| 1225 | + return ret; | |
| 1226 | + } | |
| 1227 | + | |
| 1228 | + /* set the new file, lockless */ | |
| 1229 | + ret = deny_write_access(new_exe_file); | |
| 1230 | + if (ret) | |
| 1231 | + return -EACCES; | |
| 1232 | + get_file(new_exe_file); | |
| 1233 | + | |
| 1234 | + old_exe_file = xchg(&mm->exe_file, new_exe_file); | |
| 1235 | + if (old_exe_file) { | |
| 1236 | + /* | |
| 1237 | + * Don't race with dup_mmap() getting the file and disallowing | |
| 1238 | + * write access while someone might open the file writable. | |
| 1239 | + */ | |
| 1240 | + mmap_read_lock(mm); | |
| 1241 | + allow_write_access(old_exe_file); | |
| 1242 | + fput(old_exe_file); | |
| 1243 | + mmap_read_unlock(mm); | |
| 1244 | + } | |
| 1245 | + return 0; | |
| 1173 | 1246 | } |
| 1174 | 1247 | |
| 1175 | 1248 | /** |
| @@ -1847,7 +1847,6 @@ SYSCALL_DEFINE1(umask, int, mask) · 1846 unmodified lines | ||
| 1847 | 1847 | static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) |
| 1848 | 1848 | { |
| 1849 | 1849 | struct fd exe; |
| 1850 | − struct file *old_exe, *exe_file; | |
| 1851 | 1850 | struct inode *inode; |
| 1852 | 1851 | int err; |
| 1853 | 1852 | |
| @@ -1870,40 +1869,10 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) · 16 unmodified lines | ||
| 1870 | 1869 | if (err) |
| 1871 | 1870 | goto exit; |
| 1872 | 1871 | |
| 1873 | − /* | |
| 1874 | − * Forbid mm->exe_file change if old file still mapped. | |
| 1875 | − */ | |
| 1876 | − exe_file = get_mm_exe_file(mm); | |
| 1877 | − err = -EBUSY; | |
| 1878 | − if (exe_file) { | |
| 1879 | − struct vm_area_struct *vma; | |
| 1880 | − | |
| 1881 | − mmap_read_lock(mm); | |
| 1882 | − for (vma = mm->mmap; vma; vma = vma->vm_next) { | |
| 1883 | − if (!vma->vm_file) | |
| 1884 | − continue; | |
| 1885 | − if (path_equal(&vma->vm_file->f_path, | |
| 1886 | − &exe_file->f_path)) | |
| 1887 | − goto exit_err; | |
| 1888 | − } | |
| 1889 | − | |
| 1890 | − mmap_read_unlock(mm); | |
| 1891 | − fput(exe_file); | |
| 1892 | − } | |
| 1893 | − | |
| 1894 | − err = 0; | |
| 1895 | − /* set the new file, lockless */ | |
| 1896 | − get_file(exe.file); | |
| 1897 | − old_exe = xchg(&mm->exe_file, exe.file); | |
| 1898 | − if (old_exe) | |
| 1899 | − fput(old_exe); | |
| 1872 | + err = replace_mm_exe_file(mm, exe.file); | |
| 1900 | 1873 | exit: |
| 1901 | 1874 | fdput(exe); |
| 1902 | 1875 | return err; |
| 1903 | −exit_err: | |
| 1904 | − mmap_read_unlock(mm); | |
| 1905 | − fput(exe_file); | |
| 1906 | − goto exit; | |
| 1907 | 1876 | } |
| 1908 | 1877 | |
| 1909 | 1878 | /* |
| @@ -675,9 +675,8 @@ flags(void) · 674 unmodified lines | ||
| 675 | 675 | "uptodate|dirty|lru|active|swapbacked", |
| 676 | 676 | cmp_buffer); |
| 677 | 677 | |
| 678 | − flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | |
| 679 | − | VM_DENYWRITE; | |
| 680 | − test("read|exec|mayread|maywrite|mayexec|denywrite", "%pGv", &flags); | |
| 678 | + flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; | |
| 679 | + test("read|exec|mayread|maywrite|mayexec", "%pGv", &flags); | |
| 681 | 680 | |
| 682 | 681 | gfp = GFP_TRANSHUGE; |
| 683 | 682 | test("GFP_TRANSHUGE", "%pGg", &gfp); |
| @@ -148,8 +148,6 @@ void vma_set_page_prot(struct vm_area_struct *vma) · 147 unmodified lines | ||
| 148 | 148 | static void __remove_shared_vm_struct(struct vm_area_struct *vma, |
| 149 | 149 | struct file *file, struct address_space *mapping) |
| 150 | 150 | { |
| 151 | − if (vma->vm_flags & VM_DENYWRITE) | |
| 152 | − allow_write_access(file); | |
| 153 | 151 | if (vma->vm_flags & VM_SHARED) |
| 154 | 152 | mapping_unmap_writable(mapping); |
| 155 | 153 | |
| @@ -667,8 +665,6 @@ static void __vma_link_file(struct vm_area_struct *vma) · 511 unmodified lines | ||
| 667 | 665 | if (file) { |
| 668 | 666 | struct address_space *mapping = file->f_mapping; |
| 669 | 667 | |
| 670 | − if (vma->vm_flags & VM_DENYWRITE) | |
| 671 | − put_write_access(file_inode(file)); | |
| 672 | 668 | if (vma->vm_flags & VM_SHARED) |
| 673 | 669 | mapping_allow_writable(mapping); |
| 674 | 670 | |
| @@ -1625,8 +1621,6 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len, · 950 unmodified lines | ||
| 1625 | 1621 | return PTR_ERR(file); |
| 1626 | 1622 | } |
| 1627 | 1623 | |
| 1628 | − flags &= ~MAP_DENYWRITE; | |
| 1629 | − | |
| 1630 | 1624 | retval = vm_mmap_pgoff(file, addr, len, prot, flags, pgoff); |
| 1631 | 1625 | out_fput: |
| 1632 | 1626 | if (file) |
| @@ -1783,22 +1777,12 @@ unsigned long mmap_region(struct file *file, unsigned long addr, · 150 unmodified lines | ||
| 1783 | 1777 | vma->vm_pgoff = pgoff; |
| 1784 | 1778 | |
| 1785 | 1779 | if (file) { |
| 1786 | − if (vm_flags & VM_DENYWRITE) { | |
| 1787 | − error = deny_write_access(file); | |
| 1788 | − if (error) | |
| 1789 | − goto free_vma; | |
| 1790 | − } | |
| 1791 | 1780 | if (vm_flags & VM_SHARED) { |
| 1792 | 1781 | error = mapping_map_writable(file->f_mapping); |
| 1793 | 1782 | if (error) |
| 1794 | − goto allow_write_and_free_vma; | |
| 1783 | + goto free_vma; | |
| 1795 | 1784 | } |
| 1796 | 1785 | |
| 1797 | − /* ->mmap() can change vma->vm_file, but must guarantee that | |
| 1798 | − * vma_link() below can deny write-access if VM_DENYWRITE is set | |
| 1799 | − * and map writably if VM_SHARED is set. This usually means the | |
| 1800 | − * new file must not have been exposed to user-space, yet. | |
| 1801 | − */ | |
| 1802 | 1786 | vma->vm_file = get_file(file); |
| 1803 | 1787 | error = call_mmap(file, vma); |
| 1804 | 1788 | if (error) |
| @@ -1855,13 +1839,9 @@ unsigned long mmap_region(struct file *file, unsigned long addr, · 50 unmodified lines | ||
| 1855 | 1839 | |
| 1856 | 1840 | vma_link(mm, vma, prev, rb_link, rb_parent); |
| 1857 | 1841 | /* Once vma denies write, undo our temporary denial count */ |
| 1858 | − if (file) { | |
| 1859 | 1842 | unmap_writable: |
| 1860 | − if (vm_flags & VM_SHARED) | |
| 1861 | − mapping_unmap_writable(file->f_mapping); | |
| 1862 | − if (vm_flags & VM_DENYWRITE) | |
| 1863 | − allow_write_access(file); | |
| 1864 | − } | |
| 1843 | + if (file && vm_flags & VM_SHARED) | |
| 1844 | + mapping_unmap_writable(file->f_mapping); | |
| 1865 | 1845 | file = vma->vm_file; |
| 1866 | 1846 | out: |
| 1867 | 1847 | perf_event_mmap(vma); |
| @@ -1901,9 +1881,6 @@ unmap_and_free_vma: · 33 unmodified lines | ||
| 1901 | 1881 | charged = 0; |
| 1902 | 1882 | if (vm_flags & VM_SHARED) |
| 1903 | 1883 | mapping_unmap_writable(file->f_mapping); |
| 1904 | −allow_write_and_free_vma: | |
| 1905 | − if (vm_flags & VM_DENYWRITE) | |
| 1906 | − allow_write_access(file); | |
| 1907 | 1884 | free_vma: |
| 1908 | 1885 | vm_area_free(vma); |
| 1909 | 1886 | unacct_error: |
| @@ -1293,8 +1293,6 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len, · 1292 unmodified lines | ||
| 1293 | 1293 | goto out; |
| 1294 | 1294 | } |
| 1295 | 1295 | |
| 1296 | − flags &= ~MAP_DENYWRITE; | |
| 1297 | − | |
| 1298 | 1296 | retval = vm_mmap_pgoff(file, addr, len, prot, flags, pgoff); |
| 1299 | 1297 | |
| 1300 | 1298 | if (file) |