Author: markj
Date: Sun Oct 13 16:21:48 2019
New Revision: 353478
URL: https://svnweb.freebsd.org/changeset/base/353478

Log:
  MFC r352829:
  Fix some problems with the SPARSE_MAPPING option in the kernel linker.

Modified:
  stable/12/sys/kern/link_elf.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/kern/link_elf.c
==============================================================================
--- stable/12/sys/kern/link_elf.c       Sun Oct 13 16:14:04 2019        
(r353477)
+++ stable/12/sys/kern/link_elf.c       Sun Oct 13 16:21:48 2019        
(r353478)
@@ -40,6 +40,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
+#ifdef SPARSE_MAPPING
+#include <sys/mman.h>
+#endif
 #include <sys/mutex.h>
 #include <sys/mount.h>
 #include <sys/pcpu.h>
@@ -423,7 +426,7 @@ link_elf_init(void* arg)
        ef->address = 0;
 #endif
 #ifdef SPARSE_MAPPING
-       ef->object = 0;
+       ef->object = NULL;
 #endif
        ef->dynamic = dp;
 
@@ -728,7 +731,7 @@ link_elf_link_preload(linker_class_t cls,
        ef->modptr = modptr;
        ef->address = *(caddr_t *)baseptr;
 #ifdef SPARSE_MAPPING
-       ef->object = 0;
+       ef->object = NULL;
 #endif
        dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr;
        ef->dynamic = (Elf_Dyn *)dp;
@@ -782,7 +785,7 @@ link_elf_load_file(linker_class_t cls, const char* fil
        struct nameidata nd;
        struct thread* td = curthread;  /* XXX */
        Elf_Ehdr *hdr;
-       caddr_t firstpage;
+       caddr_t firstpage, segbase;
        int nbytes, i;
        Elf_Phdr *phdr;
        Elf_Phdr *phlimit;
@@ -949,47 +952,61 @@ link_elf_load_file(linker_class_t cls, const char* fil
                error = ENOMEM;
                goto out;
        }
-       ef->address = (caddr_t) vm_map_min(kernel_map);
+#ifdef __amd64__
+       mapbase = (caddr_t)KERNBASE;
+#else
+       mapbase = (caddr_t)vm_map_min(kernel_map);
+#endif
+       /*
+        * Mapping protections are downgraded after relocation processing.
+        */
        error = vm_map_find(kernel_map, ef->object, 0,
-           (vm_offset_t *) &ef->address, mapsize, 0, VMFS_OPTIMAL_SPACE,
+           (vm_offset_t *)&mapbase, mapsize, 0, VMFS_OPTIMAL_SPACE,
            VM_PROT_ALL, VM_PROT_ALL, 0);
        if (error != 0) {
                vm_object_deallocate(ef->object);
-               ef->object = 0;
+               ef->object = NULL;
                goto out;
        }
 #else
-       ef->address = malloc(mapsize, M_LINKER, M_EXEC | M_WAITOK);
+       mapbase = malloc(mapsize, M_LINKER, M_EXEC | M_WAITOK);
 #endif
-       mapbase = ef->address;
+       ef->address = mapbase;
 
        /*
         * Read the text and data sections and zero the bss.
         */
        for (i = 0; i < nsegs; i++) {
-               caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr;
-               error = vn_rdwr(UIO_READ, nd.ni_vp,
-                   segbase, segs[i]->p_filesz, segs[i]->p_offset,
-                   UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
-                   &resid, td);
-               if (error != 0)
-                       goto out;
-               bzero(segbase + segs[i]->p_filesz,
-                   segs[i]->p_memsz - segs[i]->p_filesz);
+               segbase = mapbase + segs[i]->p_vaddr - base_vaddr;
 
 #ifdef SPARSE_MAPPING
                /*
-                * Wire down the pages
+                * Consecutive segments may have different mapping permissions,
+                * so be strict and verify that their mappings do not overlap.
                 */
+               if (((vm_offset_t)segbase & PAGE_MASK) != 0) {
+                       error = EINVAL;
+                       goto out;
+               }
+
                error = vm_map_wire(kernel_map,
-                   (vm_offset_t) segbase,
-                   (vm_offset_t) segbase + segs[i]->p_memsz,
-                   VM_MAP_WIRE_SYSTEM|VM_MAP_WIRE_NOHOLES);
+                   (vm_offset_t)segbase,
+                   (vm_offset_t)segbase + round_page(segs[i]->p_memsz),
+                   VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
                if (error != KERN_SUCCESS) {
                        error = ENOMEM;
                        goto out;
                }
 #endif
+
+               error = vn_rdwr(UIO_READ, nd.ni_vp,
+                   segbase, segs[i]->p_filesz, segs[i]->p_offset,
+                   UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
+                   &resid, td);
+               if (error != 0)
+                       goto out;
+               bzero(segbase + segs[i]->p_filesz,
+                   segs[i]->p_memsz - segs[i]->p_filesz);
        }
 
 #ifdef GPROF
@@ -1026,6 +1043,34 @@ link_elf_load_file(linker_class_t cls, const char* fil
        error = relocate_file(ef);
        if (error != 0)
                goto out;
+
+#ifdef SPARSE_MAPPING
+       /*
+        * Downgrade permissions on text segment mappings now that relocation
+        * processing is complete.  Restrict permissions on read-only segments.
+        */
+       for (i = 0; i < nsegs; i++) {
+               vm_prot_t prot;
+
+               if (segs[i]->p_type != PT_LOAD)
+                       continue;
+
+               prot = VM_PROT_READ;
+               if ((segs[i]->p_flags & PF_W) != 0)
+                       prot |= VM_PROT_WRITE;
+               if ((segs[i]->p_flags & PF_X) != 0)
+                       prot |= VM_PROT_EXECUTE;
+               segbase = mapbase + segs[i]->p_vaddr - base_vaddr;
+               error = vm_map_protect(kernel_map,
+                   (vm_offset_t)segbase,
+                   (vm_offset_t)segbase + round_page(segs[i]->p_memsz),
+                   prot, FALSE);
+               if (error != KERN_SUCCESS) {
+                       error = ENOMEM;
+                       goto out;
+               }
+       }
+#endif
 
        /*
         * Try and load the symbol table if it's present.  (you can
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to