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()
Showing the changes to kernel (3 of 16 files). Show all
Unified · Split
| @@ -8320,8 +8320,6 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) · 8319 unmodified lines | |||
| 8320 | else | 8320 | else |
| 8321 | flags = MAP_PRIVATE; | 8321 | flags = MAP_PRIVATE; |
| 8322 | 8322 | ||
| 8323 | if (vma->vm_flags & VM_DENYWRITE) | ||
| 8324 | flags |= MAP_DENYWRITE; | ||
| 8325 | if (vma->vm_flags & VM_LOCKED) | 8323 | if (vma->vm_flags & VM_LOCKED) |
| 8326 | flags |= MAP_LOCKED; | 8324 | flags |= MAP_LOCKED; |
| 8327 | if (is_vm_hugetlb_page(vma)) | 8325 | if (is_vm_hugetlb_page(vma)) |
| @@ -471,6 +471,20 @@ void free_task(struct task_struct *tsk) · 470 unmodified lines | |||
| 471 | } | 471 | } |
| 472 | EXPORT_SYMBOL(free_task); | 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 | #ifdef CONFIG_MMU | 488 | #ifdef CONFIG_MMU |
| 475 | static __latent_entropy int dup_mmap(struct mm_struct *mm, | 489 | static __latent_entropy int dup_mmap(struct mm_struct *mm, |
| 476 | struct mm_struct *oldmm) | 490 | struct mm_struct *oldmm) |
| @@ -494,7 +508,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, · 17 unmodified lines | |||
| 494 | mmap_write_lock_nested(mm, SINGLE_DEPTH_NESTING); | 508 | mmap_write_lock_nested(mm, SINGLE_DEPTH_NESTING); |
| 495 | 509 | ||
| 496 | /* No ordering required: file already has been exposed. */ | 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 | mm->total_vm = oldmm->total_vm; | 513 | mm->total_vm = oldmm->total_vm; |
| 500 | mm->data_vm = oldmm->data_vm; | 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 | tmp->vm_flags &= ~(VM_LOCKED | VM_LOCKONFAULT); | 571 | tmp->vm_flags &= ~(VM_LOCKED | VM_LOCKONFAULT); |
| 558 | file = tmp->vm_file; | 572 | file = tmp->vm_file; |
| 559 | if (file) { | 573 | if (file) { |
| 560 | struct inode *inode = file_inode(file); | ||
| 561 | struct address_space *mapping = file->f_mapping; | 574 | struct address_space *mapping = file->f_mapping; |
| 562 | 575 | ||
| 563 | get_file(file); | 576 | get_file(file); |
| 564 | if (tmp->vm_flags & VM_DENYWRITE) | ||
| 565 | put_write_access(inode); | ||
| 566 | i_mmap_lock_write(mapping); | 577 | i_mmap_lock_write(mapping); |
| 567 | if (tmp->vm_flags & VM_SHARED) | 578 | if (tmp->vm_flags & VM_SHARED) |
| 568 | mapping_allow_writable(mapping); | 579 | mapping_allow_writable(mapping); |
| @@ -640,7 +651,7 @@ static inline void mm_free_pgd(struct mm_struct *mm) · 71 unmodified lines | |||
| 640 | static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) | 651 | static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) |
| 641 | { | 652 | { |
| 642 | mmap_write_lock(oldmm); | 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 | mmap_write_unlock(oldmm); | 655 | mmap_write_unlock(oldmm); |
| 645 | return 0; | 656 | return 0; |
| 646 | } | 657 | } |
| @@ -1150,11 +1161,11 @@ void mmput_async(struct mm_struct *mm) · 503 unmodified lines | |||
| 1150 | * | 1161 | * |
| 1151 | * Main users are mmput() and sys_execve(). Callers prevent concurrent | 1162 | * Main users are mmput() and sys_execve(). Callers prevent concurrent |
| 1152 | * invocations: in mmput() nobody alive left, in execve task is single | 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 | 1164 | * threaded. |
| 1154 | * mm->exe_file, but does so without using set_mm_exe_file() in order | 1165 | * |
| 1155 | * to avoid the need for any locks. | 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 | struct file *old_exe_file; | 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 | old_exe_file = rcu_dereference_raw(mm->exe_file); | 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 | get_file(new_exe_file); | 1186 | get_file(new_exe_file); |
| 1187 | } | ||
| 1170 | rcu_assign_pointer(mm->exe_file, new_exe_file); | 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 | fput(old_exe_file); | 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 | static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) | 1847 | static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) |
| 1848 | { | 1848 | { |
| 1849 | struct fd exe; | 1849 | struct fd exe; |
| 1850 | struct file *old_exe, *exe_file; | ||
| 1851 | struct inode *inode; | 1850 | struct inode *inode; |
| 1852 | int err; | 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 | if (err) | 1869 | if (err) |
| 1871 | goto exit; | 1870 | goto exit; |
| 1872 | 1871 | ||
| 1873 | /* | 1872 | err = replace_mm_exe_file(mm, exe.file); |
| 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); | ||
| 1900 | exit: | 1873 | exit: |
| 1901 | fdput(exe); | 1874 | fdput(exe); |
| 1902 | return err; | 1875 | return err; |
| 1903 | exit_err: | ||
| 1904 | mmap_read_unlock(mm); | ||
| 1905 | fput(exe_file); | ||
| 1906 | goto exit; | ||
| 1907 | } | 1876 | } |
| 1908 | 1877 | ||
| 1909 | /* | 1878 | /* |