binfmt_elf_fdpic: support 64-bit systems
authorGreg Ungerer <gerg@kernel.org>
Tue, 11 Jul 2023 13:07:53 +0000 (23:07 +1000)
committerPalmer Dabbelt <palmer@rivosinc.com>
Wed, 23 Aug 2023 21:17:42 +0000 (14:17 -0700)
The binfmt_flat_fdpic code has a number of 32-bit specific data
structures associated with it. Extend it to be able to support and
be used on 64-bit systems as well.

The new code defines a number of key 64-bit variants of the core
elf-fdpic data structures - along side the existing 32-bit sized ones.
A common set of generic named structures are defined to be either
the 32-bit or 64-bit ones as required at compile time. This is a
similar technique to that used in the ELF binfmt loader.

For example:

  elf_fdpic_loadseg is either elf32_fdpic_loadseg or elf64_fdpic_loadseg
  elf_fdpic_loadmap is either elf32_fdpic_loadmap or elf64_fdpic_loadmap

the choice based on ELFCLASS32 or ELFCLASS64.

Signed-off-by: Greg Ungerer <gerg@kernel.org>
Acked-by: Kees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20230711130754.481209-2-gerg@kernel.org
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
fs/binfmt_elf_fdpic.c
include/linux/elf-fdpic.h
include/uapi/linux/elf-fdpic.h

index 1c6c583..43b2a28 100644 (file)
@@ -138,7 +138,7 @@ static int is_constdisp(struct elfhdr *hdr)
 static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *params,
                                 struct file *file)
 {
-       struct elf32_phdr *phdr;
+       struct elf_phdr *phdr;
        unsigned long size;
        int retval, loop;
        loff_t pos = params->hdr.e_phoff;
@@ -560,8 +560,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
        sp &= ~7UL;
 
        /* stack the load map(s) */
-       len = sizeof(struct elf32_fdpic_loadmap);
-       len += sizeof(struct elf32_fdpic_loadseg) * exec_params->loadmap->nsegs;
+       len = sizeof(struct elf_fdpic_loadmap);
+       len += sizeof(struct elf_fdpic_loadseg) * exec_params->loadmap->nsegs;
        sp = (sp - len) & ~7UL;
        exec_params->map_addr = sp;
 
@@ -571,8 +571,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
        current->mm->context.exec_fdpic_loadmap = (unsigned long) sp;
 
        if (interp_params->loadmap) {
-               len = sizeof(struct elf32_fdpic_loadmap);
-               len += sizeof(struct elf32_fdpic_loadseg) *
+               len = sizeof(struct elf_fdpic_loadmap);
+               len += sizeof(struct elf_fdpic_loadseg) *
                        interp_params->loadmap->nsegs;
                sp = (sp - len) & ~7UL;
                interp_params->map_addr = sp;
@@ -740,13 +740,13 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
                              struct mm_struct *mm,
                              const char *what)
 {
-       struct elf32_fdpic_loadmap *loadmap;
+       struct elf_fdpic_loadmap *loadmap;
 #ifdef CONFIG_MMU
-       struct elf32_fdpic_loadseg *mseg;
+       struct elf_fdpic_loadseg *mseg;
        unsigned long load_addr;
 #endif
-       struct elf32_fdpic_loadseg *seg;
-       struct elf32_phdr *phdr;
+       struct elf_fdpic_loadseg *seg;
+       struct elf_phdr *phdr;
        unsigned nloads, tmp;
        unsigned long stop;
        int loop, ret;
@@ -766,7 +766,7 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
 
        params->loadmap = loadmap;
 
-       loadmap->version = ELF32_FDPIC_LOADMAP_VERSION;
+       loadmap->version = ELF_FDPIC_LOADMAP_VERSION;
        loadmap->nsegs = nloads;
 
        /* map the requested LOADs into the memory space */
@@ -839,8 +839,8 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
                        if (phdr->p_vaddr >= seg->p_vaddr &&
                            phdr->p_vaddr + phdr->p_memsz <=
                            seg->p_vaddr + seg->p_memsz) {
-                               Elf32_Dyn __user *dyn;
-                               Elf32_Sword d_tag;
+                               Elf_Dyn __user *dyn;
+                               Elf_Sword d_tag;
 
                                params->dynamic_addr =
                                        (phdr->p_vaddr - seg->p_vaddr) +
@@ -850,11 +850,11 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
                                 * one item, and that the last item is a NULL
                                 * entry */
                                if (phdr->p_memsz == 0 ||
-                                   phdr->p_memsz % sizeof(Elf32_Dyn) != 0)
+                                   phdr->p_memsz % sizeof(Elf_Dyn) != 0)
                                        goto dynamic_error;
 
-                               tmp = phdr->p_memsz / sizeof(Elf32_Dyn);
-                               dyn = (Elf32_Dyn __user *)params->dynamic_addr;
+                               tmp = phdr->p_memsz / sizeof(Elf_Dyn);
+                               dyn = (Elf_Dyn __user *)params->dynamic_addr;
                                if (get_user(d_tag, &dyn[tmp - 1].d_tag) ||
                                    d_tag != 0)
                                        goto dynamic_error;
@@ -923,8 +923,8 @@ static int elf_fdpic_map_file_constdisp_on_uclinux(
        struct file *file,
        struct mm_struct *mm)
 {
-       struct elf32_fdpic_loadseg *seg;
-       struct elf32_phdr *phdr;
+       struct elf_fdpic_loadseg *seg;
+       struct elf_phdr *phdr;
        unsigned long load_addr, base = ULONG_MAX, top = 0, maddr = 0;
        int loop, ret;
 
@@ -1007,8 +1007,8 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
                                             struct file *file,
                                             struct mm_struct *mm)
 {
-       struct elf32_fdpic_loadseg *seg;
-       struct elf32_phdr *phdr;
+       struct elf_fdpic_loadseg *seg;
+       struct elf_phdr *phdr;
        unsigned long load_addr, delta_vaddr;
        int loop, dvset;
 
index 3bea95a..e533f45 100644 (file)
 
 #include <uapi/linux/elf-fdpic.h>
 
+#if ELF_CLASS == ELFCLASS32
+#define Elf_Sword                      Elf32_Sword
+#define elf_fdpic_loadseg              elf32_fdpic_loadseg
+#define elf_fdpic_loadmap              elf32_fdpic_loadmap
+#define ELF_FDPIC_LOADMAP_VERSION      ELF32_FDPIC_LOADMAP_VERSION
+#else
+#define Elf_Sword                      Elf64_Sxword
+#define elf_fdpic_loadmap              elf64_fdpic_loadmap
+#define elf_fdpic_loadseg              elf64_fdpic_loadseg
+#define ELF_FDPIC_LOADMAP_VERSION      ELF64_FDPIC_LOADMAP_VERSION
+#endif
+
 /*
  * binfmt binary parameters structure
  */
 struct elf_fdpic_params {
        struct elfhdr                   hdr;            /* ref copy of ELF header */
        struct elf_phdr                 *phdrs;         /* ref copy of PT_PHDR table */
-       struct elf32_fdpic_loadmap      *loadmap;       /* loadmap to be passed to userspace */
+       struct elf_fdpic_loadmap        *loadmap;       /* loadmap to be passed to userspace */
        unsigned long                   elfhdr_addr;    /* mapped ELF header user address */
        unsigned long                   ph_addr;        /* mapped PT_PHDR user address */
        unsigned long                   map_addr;       /* mapped loadmap user address */
index 4fcc6cf..ec23f08 100644 (file)
@@ -32,4 +32,19 @@ struct elf32_fdpic_loadmap {
 
 #define ELF32_FDPIC_LOADMAP_VERSION    0x0000
 
+/* segment mappings for ELF FDPIC libraries/executables/interpreters */
+struct elf64_fdpic_loadseg {
+       Elf64_Addr      addr;           /* core address to which mapped */
+       Elf64_Addr      p_vaddr;        /* VMA recorded in file */
+       Elf64_Word      p_memsz;        /* allocation size recorded in file */
+};
+
+struct elf64_fdpic_loadmap {
+       Elf64_Half      version;        /* version of these structures, just in case... */
+       Elf64_Half      nsegs;          /* number of segments */
+       struct elf64_fdpic_loadseg segs[];
+};
+
+#define ELF64_FDPIC_LOADMAP_VERSION    0x0000
+
 #endif /* _UAPI_LINUX_ELF_FDPIC_H */