History

Merge tag 'denywrite-for-5.15' of git://github.com/davidhildenbrand/linux

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()

Linus Torvalds committed 5 years ago

Commit 49624ef2 parents f746406 592ca0916 files · +119 −103Browse files

Showing the changes to kernel (3 of 16 files). Show all

Unified · Split

3 files
  1. kernel/events/core.c +0 −2
  2. kernel/fork.c +84 −11
  3. kernel/sys.c +1 −32
kernel/events/core.c+0−2
@@ -8320,8 +8320,6 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) · 8319 unmodified lines
83208320 else
83218321 flags = MAP_PRIVATE;
83228322
8323− if (vma->vm_flags & VM_DENYWRITE)
8324− flags |= MAP_DENYWRITE;
83258323 if (vma->vm_flags & VM_LOCKED)
83268324 flags |= MAP_LOCKED;
83278325 if (is_vm_hugetlb_page(vma))
kernel/fork.c+84−11
@@ -471,6 +471,20 @@ void free_task(struct task_struct *tsk) · 470 unmodified lines
471471 }
472472 EXPORT_SYMBOL(free_task);
473473
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+
474488 #ifdef CONFIG_MMU
475489 static __latent_entropy int dup_mmap(struct mm_struct *mm,
476490 struct mm_struct *oldmm)
@@ -494,7 +508,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, · 17 unmodified lines
494508 mmap_write_lock_nested(mm, SINGLE_DEPTH_NESTING);
495509
496510 /* 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);
498512
499513 mm->total_vm = oldmm->total_vm;
500514 mm->data_vm = oldmm->data_vm;
@@ -557,12 +571,9 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, · 56 unmodified lines
557571 tmp->vm_flags &= ~(VM_LOCKED | VM_LOCKONFAULT);
558572 file = tmp->vm_file;
559573 if (file) {
560− struct inode *inode = file_inode(file);
561574 struct address_space *mapping = file->f_mapping;
562575
563576 get_file(file);
564− if (tmp->vm_flags & VM_DENYWRITE)
565− put_write_access(inode);
566577 i_mmap_lock_write(mapping);
567578 if (tmp->vm_flags & VM_SHARED)
568579 mapping_allow_writable(mapping);
@@ -640,7 +651,7 @@ static inline void mm_free_pgd(struct mm_struct *mm) · 71 unmodified lines
640651 static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
641652 {
642653 mmap_write_lock(oldmm);
643− RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm));
654+ dup_mm_exe_file(mm, oldmm);
644655 mmap_write_unlock(oldmm);
645656 return 0;
646657 }
@@ -1150,11 +1161,11 @@ void mmput_async(struct mm_struct *mm) · 503 unmodified lines
11501161 *
11511162 * Main users are mmput() and sys_execve(). Callers prevent concurrent
11521163 * 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.
11561167 */
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)
11581169 {
11591170 struct file *old_exe_file;
11601171
@@ -1165,11 +1176,73 @@ void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) · 4 unmodified lines
11651176 */
11661177 old_exe_file = rcu_dereference_raw(mm->exe_file);
11671178
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;
11691186 get_file(new_exe_file);
1187+ }
11701188 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);
11721191 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;
11731246 }
11741247
11751248 /**
kernel/sys.c+1−32
@@ -1847,7 +1847,6 @@ SYSCALL_DEFINE1(umask, int, mask) · 1846 unmodified lines
18471847 static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
18481848 {
18491849 struct fd exe;
1850− struct file *old_exe, *exe_file;
18511850 struct inode *inode;
18521851 int err;
18531852
@@ -1870,40 +1869,10 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) · 16 unmodified lines
18701869 if (err)
18711870 goto exit;
18721871
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);
19001873 exit:
19011874 fdput(exe);
19021875 return err;
1903−exit_err:
1904− mmap_read_unlock(mm);
1905− fput(exe_file);
1906− goto exit;
19071876 }
19081877
19091878 /*