binfmt: remove in-tree usage of MAP_DENYWRITE
authorDavid Hildenbrand <david@redhat.com>
Fri, 23 Apr 2021 07:42:41 +0000 (09:42 +0200)
committerDavid Hildenbrand <david@redhat.com>
Fri, 3 Sep 2021 16:42:01 +0000 (18:42 +0200)
At exec time when we mmap the new executable via MAP_DENYWRITE we have it
opened via do_open_execat() and already deny_write_access()'ed the file
successfully. Once exec completes, we allow_write_acces(); however,
we set mm->exe_file in begin_new_exec() via set_mm_exe_file() and
also deny_write_access() as long as mm->exe_file remains set. We'll
effectively deny write access to our executable via mm->exe_file
until mm->exe_file is changed -- when the process is removed, on new
exec, or via sys_prctl(PR_SET_MM_MAP/EXE_FILE).

Let's remove all usage of MAP_DENYWRITE, it's no longer necessary for
mm->exe_file.

In case of an elf interpreter, we'll now only deny write access to the file
during exec. This is somewhat okay, because the interpreter behaves
(and sometime is) a shared library; all shared libraries, especially the
ones loaded directly in user space like via dlopen() won't ever be mapped
via MAP_DENYWRITE, because we ignore that from user space completely;
these shared libraries can always be modified while mapped and executed.
Let's only special-case the main executable, denying write access while
being executed by a process. This can be considered a minor user space
visible change.

While this is a cleanup, it also fixes part of a problem reported with
VM_DENYWRITE on overlayfs, as VM_DENYWRITE is effectively unused with
this patch and will be removed next:
  "Overlayfs did not honor positive i_writecount on realfile for
   VM_DENYWRITE mappings." [1]

[1] https://lore.kernel.org/r/YNHXzBgzRrZu1MrD@miu.piliscsaba.redhat.com/

Reported-by: Chengguang Xu <cgxu519@mykernel.net>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: Christian König <christian.koenig@amd.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
arch/x86/ia32/ia32_aout.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c

index 321d7b2..9bd1524 100644 (file)
@@ -202,8 +202,7 @@ static int load_aout_binary(struct linux_binprm *bprm)
 
                error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
                                PROT_READ | PROT_EXEC,
-                               MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
-                               MAP_32BIT,
+                               MAP_FIXED | MAP_PRIVATE | MAP_32BIT,
                                fd_offset);
 
                if (error != N_TXTADDR(ex))
@@ -211,8 +210,7 @@ static int load_aout_binary(struct linux_binprm *bprm)
 
                error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
                                PROT_READ | PROT_WRITE | PROT_EXEC,
-                               MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
-                               MAP_32BIT,
+                               MAP_FIXED | MAP_PRIVATE | MAP_32BIT,
                                fd_offset + ex.a_text);
                if (error != N_DATADDR(ex))
                        return error;
index d29de97..a47496d 100644 (file)
@@ -221,8 +221,7 @@ static int load_aout_binary(struct linux_binprm * bprm)
                }
 
                error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
-                       PROT_READ | PROT_EXEC,
-                       MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+                       PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE,
                        fd_offset);
 
                if (error != N_TXTADDR(ex))
@@ -230,7 +229,7 @@ static int load_aout_binary(struct linux_binprm * bprm)
 
                error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
                                PROT_READ | PROT_WRITE | PROT_EXEC,
-                               MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+                               MAP_FIXED | MAP_PRIVATE,
                                fd_offset + ex.a_text);
                if (error != N_DATADDR(ex))
                        return error;
index 6d2c795..69d900a 100644 (file)
@@ -622,7 +622,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
        eppnt = interp_elf_phdata;
        for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
                if (eppnt->p_type == PT_LOAD) {
-                       int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+                       int elf_type = MAP_PRIVATE;
                        int elf_prot = make_prot(eppnt->p_flags, arch_state,
                                                 true, true);
                        unsigned long vaddr = 0;
@@ -1070,7 +1070,7 @@ out_free_interp:
                elf_prot = make_prot(elf_ppnt->p_flags, &arch_state,
                                     !!interpreter, false);
 
-               elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
+               elf_flags = MAP_PRIVATE;
 
                vaddr = elf_ppnt->p_vaddr;
                /*
index cf40284..6d8fd60 100644 (file)
@@ -1041,7 +1041,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
                if (phdr->p_flags & PF_W) prot |= PROT_WRITE;
                if (phdr->p_flags & PF_X) prot |= PROT_EXEC;
 
-               flags = MAP_PRIVATE | MAP_DENYWRITE;
+               flags = MAP_PRIVATE;
                maddr = 0;
 
                switch (params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) {