linux/arch/x86/ia32/ia32_aout.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  a.out loader for x86-64
   4 *
   5 *  Copyright (C) 1991, 1992, 1996  Linus Torvalds
   6 *  Hacked together by Andi Kleen
   7 */
   8
   9#include <linux/module.h>
  10
  11#include <linux/time.h>
  12#include <linux/kernel.h>
  13#include <linux/mm.h>
  14#include <linux/mman.h>
  15#include <linux/a.out.h>
  16#include <linux/errno.h>
  17#include <linux/signal.h>
  18#include <linux/string.h>
  19#include <linux/fs.h>
  20#include <linux/file.h>
  21#include <linux/stat.h>
  22#include <linux/fcntl.h>
  23#include <linux/ptrace.h>
  24#include <linux/user.h>
  25#include <linux/binfmts.h>
  26#include <linux/personality.h>
  27#include <linux/init.h>
  28#include <linux/jiffies.h>
  29#include <linux/perf_event.h>
  30#include <linux/sched/task_stack.h>
  31
  32#include <linux/uaccess.h>
  33#include <asm/pgalloc.h>
  34#include <asm/cacheflush.h>
  35#include <asm/user32.h>
  36#include <asm/ia32.h>
  37
  38#undef WARN_OLD
  39
  40static int load_aout_binary(struct linux_binprm *);
  41static int load_aout_library(struct file *);
  42
  43static struct linux_binfmt aout_format = {
  44        .module         = THIS_MODULE,
  45        .load_binary    = load_aout_binary,
  46        .load_shlib     = load_aout_library,
  47};
  48
  49static int set_brk(unsigned long start, unsigned long end)
  50{
  51        start = PAGE_ALIGN(start);
  52        end = PAGE_ALIGN(end);
  53        if (end <= start)
  54                return 0;
  55        return vm_brk(start, end - start);
  56}
  57
  58
  59/*
  60 * create_aout_tables() parses the env- and arg-strings in new user
  61 * memory and creates the pointer tables from them, and puts their
  62 * addresses on the "stack", returning the new stack pointer value.
  63 */
  64static u32 __user *create_aout_tables(char __user *p, struct linux_binprm *bprm)
  65{
  66        u32 __user *argv, *envp, *sp;
  67        int argc = bprm->argc, envc = bprm->envc;
  68
  69        sp = (u32 __user *) ((-(unsigned long)sizeof(u32)) & (unsigned long) p);
  70        sp -= envc+1;
  71        envp = sp;
  72        sp -= argc+1;
  73        argv = sp;
  74        put_user((unsigned long) envp, --sp);
  75        put_user((unsigned long) argv, --sp);
  76        put_user(argc, --sp);
  77        current->mm->arg_start = (unsigned long) p;
  78        while (argc-- > 0) {
  79                char c;
  80
  81                put_user((u32)(unsigned long)p, argv++);
  82                do {
  83                        get_user(c, p++);
  84                } while (c);
  85        }
  86        put_user(0, argv);
  87        current->mm->arg_end = current->mm->env_start = (unsigned long) p;
  88        while (envc-- > 0) {
  89                char c;
  90
  91                put_user((u32)(unsigned long)p, envp++);
  92                do {
  93                        get_user(c, p++);
  94                } while (c);
  95        }
  96        put_user(0, envp);
  97        current->mm->env_end = (unsigned long) p;
  98        return sp;
  99}
 100
 101/*
 102 * These are the functions used to load a.out style executables and shared
 103 * libraries.  There is no binary dependent code anywhere else.
 104 */
 105static int load_aout_binary(struct linux_binprm *bprm)
 106{
 107        unsigned long error, fd_offset, rlim;
 108        struct pt_regs *regs = current_pt_regs();
 109        struct exec ex;
 110        int retval;
 111
 112        ex = *((struct exec *) bprm->buf);              /* exec-header */
 113        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
 114             N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
 115            N_TRSIZE(ex) || N_DRSIZE(ex) ||
 116            i_size_read(file_inode(bprm->file)) <
 117            ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 118                return -ENOEXEC;
 119        }
 120
 121        fd_offset = N_TXTOFF(ex);
 122
 123        /* Check initial limits. This avoids letting people circumvent
 124         * size limits imposed on them by creating programs with large
 125         * arrays in the data or bss.
 126         */
 127        rlim = rlimit(RLIMIT_DATA);
 128        if (rlim >= RLIM_INFINITY)
 129                rlim = ~0;
 130        if (ex.a_data + ex.a_bss > rlim)
 131                return -ENOMEM;
 132
 133        /* Flush all traces of the currently running executable */
 134        retval = flush_old_exec(bprm);
 135        if (retval)
 136                return retval;
 137
 138        /* OK, This is the point of no return */
 139        set_personality(PER_LINUX);
 140        set_personality_ia32(false);
 141
 142        setup_new_exec(bprm);
 143
 144        regs->cs = __USER32_CS;
 145        regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 =
 146                regs->r13 = regs->r14 = regs->r15 = 0;
 147
 148        current->mm->end_code = ex.a_text +
 149                (current->mm->start_code = N_TXTADDR(ex));
 150        current->mm->end_data = ex.a_data +
 151                (current->mm->start_data = N_DATADDR(ex));
 152        current->mm->brk = ex.a_bss +
 153                (current->mm->start_brk = N_BSSADDR(ex));
 154
 155        retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
 156        if (retval < 0)
 157                return retval;
 158
 159        install_exec_creds(bprm);
 160
 161        if (N_MAGIC(ex) == OMAGIC) {
 162                unsigned long text_addr, map_size;
 163
 164                text_addr = N_TXTADDR(ex);
 165                map_size = ex.a_text+ex.a_data;
 166
 167                error = vm_brk(text_addr & PAGE_MASK, map_size);
 168
 169                if (error)
 170                        return error;
 171
 172                error = read_code(bprm->file, text_addr, 32,
 173                                  ex.a_text + ex.a_data);
 174                if ((signed long)error < 0)
 175                        return error;
 176        } else {
 177#ifdef WARN_OLD
 178                static unsigned long error_time, error_time2;
 179                if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
 180                    (N_MAGIC(ex) != NMAGIC) &&
 181                                time_after(jiffies, error_time2 + 5*HZ)) {
 182                        printk(KERN_NOTICE "executable not page aligned\n");
 183                        error_time2 = jiffies;
 184                }
 185
 186                if ((fd_offset & ~PAGE_MASK) != 0 &&
 187                            time_after(jiffies, error_time + 5*HZ)) {
 188                        printk(KERN_WARNING
 189                               "fd_offset is not page aligned. Please convert "
 190                               "program: %pD\n",
 191                               bprm->file);
 192                        error_time = jiffies;
 193                }
 194#endif
 195
 196                if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) {
 197                        error = vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
 198                        if (error)
 199                                return error;
 200
 201                        read_code(bprm->file, N_TXTADDR(ex), fd_offset,
 202                                        ex.a_text+ex.a_data);
 203                        goto beyond_if;
 204                }
 205
 206                error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
 207                                PROT_READ | PROT_EXEC,
 208                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
 209                                MAP_EXECUTABLE | MAP_32BIT,
 210                                fd_offset);
 211
 212                if (error != N_TXTADDR(ex))
 213                        return error;
 214
 215                error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
 216                                PROT_READ | PROT_WRITE | PROT_EXEC,
 217                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
 218                                MAP_EXECUTABLE | MAP_32BIT,
 219                                fd_offset + ex.a_text);
 220                if (error != N_DATADDR(ex))
 221                        return error;
 222        }
 223
 224beyond_if:
 225        error = set_brk(current->mm->start_brk, current->mm->brk);
 226        if (error)
 227                return error;
 228
 229        set_binfmt(&aout_format);
 230
 231        current->mm->start_stack =
 232                (unsigned long)create_aout_tables((char __user *)bprm->p, bprm);
 233        /* start thread */
 234        loadsegment(fs, 0);
 235        loadsegment(ds, __USER32_DS);
 236        loadsegment(es, __USER32_DS);
 237        load_gs_index(0);
 238        (regs)->ip = ex.a_entry;
 239        (regs)->sp = current->mm->start_stack;
 240        (regs)->flags = 0x200;
 241        (regs)->cs = __USER32_CS;
 242        (regs)->ss = __USER32_DS;
 243        regs->r8 = regs->r9 = regs->r10 = regs->r11 =
 244        regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0;
 245        set_fs(USER_DS);
 246        return 0;
 247}
 248
 249static int load_aout_library(struct file *file)
 250{
 251        unsigned long bss, start_addr, len, error;
 252        int retval;
 253        struct exec ex;
 254        loff_t pos = 0;
 255
 256        retval = -ENOEXEC;
 257        error = kernel_read(file, &ex, sizeof(ex), &pos);
 258        if (error != sizeof(ex))
 259                goto out;
 260
 261        /* We come in here for the regular a.out style of shared libraries */
 262        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
 263            N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
 264            i_size_read(file_inode(file)) <
 265            ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 266                goto out;
 267        }
 268
 269        if (N_FLAGS(ex))
 270                goto out;
 271
 272        /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
 273           this off to get the starting address for the page */
 274
 275        start_addr =  ex.a_entry & 0xfffff000;
 276
 277        if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
 278#ifdef WARN_OLD
 279                static unsigned long error_time;
 280                if (time_after(jiffies, error_time + 5*HZ)) {
 281                        printk(KERN_WARNING
 282                               "N_TXTOFF is not page aligned. Please convert "
 283                               "library: %pD\n",
 284                               file);
 285                        error_time = jiffies;
 286                }
 287#endif
 288                retval = vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
 289                if (retval)
 290                        goto out;
 291
 292                read_code(file, start_addr, N_TXTOFF(ex),
 293                          ex.a_text + ex.a_data);
 294                retval = 0;
 295                goto out;
 296        }
 297        /* Now use mmap to map the library into memory. */
 298        error = vm_mmap(file, start_addr, ex.a_text + ex.a_data,
 299                        PROT_READ | PROT_WRITE | PROT_EXEC,
 300                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_32BIT,
 301                        N_TXTOFF(ex));
 302        retval = error;
 303        if (error != start_addr)
 304                goto out;
 305
 306        len = PAGE_ALIGN(ex.a_text + ex.a_data);
 307        bss = ex.a_text + ex.a_data + ex.a_bss;
 308        if (bss > len) {
 309                retval = vm_brk(start_addr + len, bss - len);
 310                if (retval)
 311                        goto out;
 312        }
 313        retval = 0;
 314out:
 315        return retval;
 316}
 317
 318static int __init init_aout_binfmt(void)
 319{
 320        register_binfmt(&aout_format);
 321        return 0;
 322}
 323
 324static void __exit exit_aout_binfmt(void)
 325{
 326        unregister_binfmt(&aout_format);
 327}
 328
 329module_init(init_aout_binfmt);
 330module_exit(exit_aout_binfmt);
 331MODULE_LICENSE("GPL");
 332