]> git.proxmox.com Git - mirror_qemu.git/blobdiff - linux-user/flatload.c
Fix input-linux reading from device
[mirror_qemu.git] / linux-user / flatload.c
index db88e4b1c5a3ca113bc726a89b32312087aea926..a35a560904917d086e52b97c8294e1d3e2d52e55 100644 (file)
@@ -13,8 +13,7 @@
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  *      Copyright (C) 2006 CodeSourcery.
  *     Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
 
 /****************************************************************************/
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <unistd.h>
+#include "qemu/osdep.h"
 
 #include "qemu.h"
 #include "flat.h"
+#include "target_flat.h"
 
 //#define DEBUG
 
 #ifdef DEBUG
-#define        DBG_FLT(a...)   printf(a)
+#define        DBG_FLT(...)    printf(__VA_ARGS__)
 #else
-#define        DBG_FLT(a...)
-#endif
-
-#define flat_reloc_valid(reloc, size)             ((reloc) <= (size))
-#define flat_old_ram_flag(flag)                   (flag)
-#ifdef TARGET_WORDS_BIGENDIAN
-#define flat_get_relocate_addr(relval)            (relval)
-#else
-#define flat_get_relocate_addr(relval)            bswap32(relval)
+#define        DBG_FLT(...)
 #endif
 
 #define RELOC_FAILED 0xff00ff01                /* Relocation incorrect somewhere */
 #define UNLOADED_LIB 0x7ff000ff                /* Placeholder for unused library */
 
 struct lib_info {
-    target_ulong start_code;   /* Start of text segment */
-    target_ulong start_data;   /* Start of data segment */
-    target_ulong end_data;      /* Start of bss section */
-    target_ulong start_brk;    /* End of data segment */
-    target_ulong text_len;     /* Length of text segment */
-    target_ulong entry;                /* Start address for this module */
-    target_ulong build_date;   /* When this one was compiled */
+    abi_ulong start_code;       /* Start of text segment */
+    abi_ulong start_data;       /* Start of data segment */
+    abi_ulong end_data;         /* Start of bss section */
+    abi_ulong start_brk;        /* End of data segment */
+    abi_ulong text_len;                /* Length of text segment */
+    abi_ulong entry;           /* Start address for this module */
+    abi_ulong build_date;       /* When this one was compiled */
     short loaded;              /* Has this library been loaded? */
 };
 
@@ -79,8 +67,6 @@ static int load_flat_shared_library(int id, struct lib_info *p);
 
 struct linux_binprm;
 
-#define ntohl(x) be32_to_cpu(x)
-
 /****************************************************************************/
 /*
  * create_flat_tables() parses the env- and arg-strings in new user
@@ -89,7 +75,7 @@ struct linux_binprm;
  */
 
 /* Push a block of strings onto the guest stack.  */
-static target_ulong copy_strings(target_ulong p, int n, char **s)
+static abi_ulong copy_strings(abi_ulong p, int n, char **s)
 {
     int len;
 
@@ -102,14 +88,20 @@ static target_ulong copy_strings(target_ulong p, int n, char **s)
     return p;
 }
 
-int target_pread(int fd, target_ulong ptr, target_ulong len,
-                 target_ulong offset)
+static int target_pread(int fd, abi_ulong ptr, abi_ulong len,
+                        abi_ulong offset)
 {
     void *buf;
     int ret;
 
-    buf = lock_user(ptr, len, 0);
+    buf = lock_user(VERIFY_WRITE, ptr, len, 0);
+    if (!buf) {
+        return -EFAULT;
+    }
     ret = pread(fd, buf, len, offset);
+    if (ret < 0) {
+        ret = -errno;
+    }
     unlock_user(buf, ptr, len);
     return ret;
 }
@@ -262,15 +254,15 @@ out:
 
 /****************************************************************************/
 
-static target_ulong
-calc_reloc(target_ulong r, struct lib_info *p, int curid, int internalp)
+static abi_ulong
+calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp)
 {
-    target_ulong addr;
+    abi_ulong addr;
     int id;
-    target_ulong start_brk;
-    target_ulong start_data;
-    target_ulong text_len;
-    target_ulong start_code;
+    abi_ulong start_brk;
+    abi_ulong start_data;
+    abi_ulong text_len;
+    abi_ulong start_code;
 
 #ifdef CONFIG_BINFMT_SHARED_FLAT
 #error needs checking
@@ -336,10 +328,10 @@ failed:
 /****************************************************************************/
 
 /* ??? This does not handle endianness correctly.  */
-void old_reloc(struct lib_info *libinfo, uint32_t rl)
+static void old_reloc(struct lib_info *libinfo, uint32_t rl)
 {
 #ifdef DEBUG
-       char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
+       const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
 #endif
        uint32_t *ptr;
         uint32_t offset;
@@ -349,9 +341,9 @@ void old_reloc(struct lib_info *libinfo, uint32_t rl)
         reloc_type = rl >> 30;
         /* ??? How to handle this?  */
 #if defined(CONFIG_COLDFIRE)
-       ptr = (uint32_t *) (libinfo->start_code + offset);
+       ptr = (uint32_t *) ((unsigned long) libinfo->start_code + offset);
 #else
-       ptr = (uint32_t *) (libinfo->start_data + offset);
+       ptr = (uint32_t *) ((unsigned long) libinfo->start_data + offset);
 #endif
 
 #ifdef DEBUG
@@ -381,19 +373,19 @@ void old_reloc(struct lib_info *libinfo, uint32_t rl)
 /****************************************************************************/
 
 static int load_flat_file(struct linux_binprm * bprm,
-               struct lib_info *libinfo, int id, target_ulong *extra_stack)
+               struct lib_info *libinfo, int id, abi_ulong *extra_stack)
 {
     struct flat_hdr * hdr;
-    target_ulong textpos = 0, datapos = 0, result;
-    target_ulong realdatastart = 0;
-    target_ulong text_len, data_len, bss_len, stack_len, flags;
-    target_ulong memp = 0; /* for finding the brk area */
-    target_ulong extra;
-    target_ulong reloc = 0, rp;
+    abi_ulong textpos = 0, datapos = 0;
+    abi_long result;
+    abi_ulong realdatastart = 0;
+    abi_ulong text_len, data_len, bss_len, stack_len, flags;
+    abi_ulong extra;
+    abi_ulong reloc = 0, rp;
     int i, rev, relocs = 0;
-    target_ulong fpos;
-    target_ulong start_code, end_code;
-    target_ulong indx_len;
+    abi_ulong fpos;
+    abi_ulong start_code;
+    abi_ulong indx_len;
 
     hdr = ((struct flat_hdr *) bprm->buf);             /* exec-header */
 
@@ -440,14 +432,14 @@ static int load_flat_file(struct linux_binprm * bprm,
     /*
      * calculate the extra space we need to map in
      */
-    extra = relocs * sizeof(target_ulong);
+    extra = relocs * sizeof(abi_ulong);
     if (extra < bss_len + stack_len)
         extra = bss_len + stack_len;
 
     /* Add space for library base pointers.  Make sure this does not
        misalign the  doesn't misalign the data segment.  */
-    indx_len = MAX_SHARED_LIBS * sizeof(target_ulong);
-    indx_len = (indx_len + 15) & ~(target_ulong)15;
+    indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong);
+    indx_len = (indx_len + 15) & ~(abi_ulong)15;
 
     /*
      * there are a couple of cases here,  the separate code/data
@@ -485,12 +477,12 @@ static int load_flat_file(struct linux_binprm * bprm,
 #ifdef CONFIG_BINFMT_ZFLAT
         if (flags & FLAT_FLAG_GZDATA) {
             result = decompress_exec(bprm, fpos, (char *) datapos,
-                                     data_len + (relocs * sizeof(target_ulong)))
+                                     data_len + (relocs * sizeof(abi_ulong)))
         } else
 #endif
         {
             result = target_pread(bprm->fd, datapos,
-                                  data_len + (relocs * sizeof(target_ulong)),
+                                  data_len + (relocs * sizeof(abi_ulong)),
                                   fpos);
         }
         if (result < 0) {
@@ -499,7 +491,6 @@ static int load_flat_file(struct linux_binprm * bprm,
         }
 
         reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
-        memp = realdatastart;
 
     } else {
 
@@ -514,7 +505,6 @@ static int load_flat_file(struct linux_binprm * bprm,
         realdatastart = textpos + ntohl(hdr->data_start);
         datapos = realdatastart + indx_len;
         reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
-        memp = textpos;
 
 #ifdef CONFIG_BINFMT_ZFLAT
 #error code needs checking
@@ -544,7 +534,7 @@ static int load_flat_file(struct linux_binprm * bprm,
                                   text_len, 0);
             if (result >= 0) {
                 result = target_pread(bprm->fd, datapos,
-                    data_len + (relocs * sizeof(target_ulong)),
+                    data_len + (relocs * sizeof(abi_ulong)),
                     ntohl(hdr->data_start));
             }
         }
@@ -560,11 +550,10 @@ static int load_flat_file(struct linux_binprm * bprm,
 
     /* The main program needs a little extra setup in the task structure */
     start_code = textpos + sizeof (struct flat_hdr);
-    end_code = textpos + text_len;
 
     DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
             id ? "Lib" : "Load", bprm->filename,
-            (int) start_code, (int) end_code,
+            (int) start_code, (int) (textpos + text_len),
             (int) datapos,
             (int) (datapos + data_len),
             (int) (datapos + data_len),
@@ -587,7 +576,7 @@ static int load_flat_file(struct linux_binprm * bprm,
      * help simplify all this mumbo jumbo
      *
      * We've got two different sections of relocation entries.
-     * The first is the GOT which resides at the begining of the data segment
+     * The first is the GOT which resides at the beginning of the data segment
      * and is terminated with a -1.  This one can be relocated in place.
      * The second is the extra relocation entries tacked after the image's
      * data segment. These require a little more processing as the entry is
@@ -597,17 +586,19 @@ static int load_flat_file(struct linux_binprm * bprm,
     if (flags & FLAT_FLAG_GOTPIC) {
         rp = datapos;
         while (1) {
-            target_ulong addr;
-            addr = tgetl(rp);
+            abi_ulong addr;
+            if (get_user_ual(addr, rp))
+                return -EFAULT;
             if (addr == -1)
                 break;
             if (addr) {
                 addr = calc_reloc(addr, libinfo, id, 0);
                 if (addr == RELOC_FAILED)
                     return -ENOEXEC;
-                tputl(rp, addr);
+                if (put_user_ual(addr, rp))
+                    return -EFAULT;
             }
-            rp += sizeof(target_ulong);
+            rp += sizeof(abi_ulong);
         }
     }
 
@@ -623,48 +614,54 @@ static int load_flat_file(struct linux_binprm * bprm,
      * __start to address 4 so that is okay).
      */
     if (rev > OLD_FLAT_VERSION) {
+        abi_ulong persistent = 0;
         for (i = 0; i < relocs; i++) {
-            target_ulong addr, relval;
+            abi_ulong addr, relval;
 
             /* Get the address of the pointer to be
                relocated (of course, the address has to be
                relocated first).  */
-            relval = tgetl(reloc + i * sizeof (target_ulong));
+            if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
+                return -EFAULT;
+            relval = ntohl(relval);
+            if (flat_set_persistent(relval, &persistent))
+                continue;
             addr = flat_get_relocate_addr(relval);
             rp = calc_reloc(addr, libinfo, id, 1);
             if (rp == RELOC_FAILED)
                 return -ENOEXEC;
 
             /* Get the pointer's value.  */
-            addr = tgetl(rp);
+            if (get_user_ual(addr, rp))
+                return -EFAULT;
+            addr = flat_get_addr_from_rp(addr, relval, flags, &persistent);
             if (addr != 0) {
                 /*
                  * Do the relocation.  PIC relocs in the data section are
                  * already in target order
                  */
-
-#ifndef TARGET_WORDS_BIGENDIAN
                 if ((flags & FLAT_FLAG_GOTPIC) == 0)
-                    addr = bswap32(addr);
-#endif
+                    addr = ntohl(addr);
                 addr = calc_reloc(addr, libinfo, id, 0);
                 if (addr == RELOC_FAILED)
                     return -ENOEXEC;
 
                 /* Write back the relocated pointer.  */
-                tputl(rp, addr);
+                if (flat_put_addr_at_rp(rp, addr, relval))
+                    return -EFAULT;
             }
         }
     } else {
         for (i = 0; i < relocs; i++) {
-            target_ulong relval;
-            relval = tgetl(reloc + i * sizeof (target_ulong));
+            abi_ulong relval;
+            if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
+                return -EFAULT;
             old_reloc(&libinfo[0], relval);
         }
     }
 
     /* zero the BSS.  */
-    memset((void*)(datapos + data_len), 0, bss_len);
+    memset(g2h(datapos + data_len), 0, bss_len);
 
     return 0;
 }
@@ -708,14 +705,13 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
 
 #endif /* CONFIG_BINFMT_SHARED_FLAT */
 
-int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info)
+int load_flt_binary(struct linux_binprm *bprm, struct image_info *info)
 {
     struct lib_info libinfo[MAX_SHARED_LIBS];
-    target_ulong p = bprm->p;
-    target_ulong stack_len;
-    target_ulong start_addr;
-    target_ulong sp;
+    abi_ulong p;
+    abi_ulong stack_len;
+    abi_ulong start_addr;
+    abi_ulong sp;
     int res;
     int i, j;
 
@@ -727,8 +723,15 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
      * pedantic and include space for the argv/envp array as it may have
      * a lot of entries.
      */
-#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
-    stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
+    stack_len = 0;
+    for (i = 0; i < bprm->argc; ++i) {
+        /* the argv strings */
+        stack_len += strlen(bprm->argv[i]);
+    }
+    for (i = 0; i < bprm->envc; ++i) {
+        /* the envp strings */
+        stack_len += strlen(bprm->envp[i]);
+    }
     stack_len += (bprm->argc + 1) * 4; /* the argv array */
     stack_len += (bprm->envc + 1) * 4; /* the envp array */
 
@@ -740,13 +743,16 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     /* Update data segment pointers for all libraries */
     for (i=0; i<MAX_SHARED_LIBS; i++) {
         if (libinfo[i].loaded) {
-            target_ulong p;
+            abi_ulong p;
             p = libinfo[i].start_data;
             for (j=0; j<MAX_SHARED_LIBS; j++) {
                 p -= 4;
-                tput32(p, libinfo[j].loaded
-                          ? libinfo[j].start_data
-                          : UNLOADED_LIB);
+                /* FIXME - handle put_user() failures */
+                if (put_user_ual(libinfo[j].loaded
+                                 ? libinfo[j].start_data
+                                 : UNLOADED_LIB,
+                                 p))
+                    return -EFAULT;
             }
         }
     }
@@ -758,15 +764,16 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     p = copy_strings(p, bprm->envc, bprm->envp);
     p = copy_strings(p, bprm->argc, bprm->argv);
     /* Align stack.  */
-    sp = p & ~(target_ulong)(sizeof(target_ulong) - 1);
+    sp = p & ~(abi_ulong)(sizeof(abi_ulong) - 1);
     /* Enforce final stack alignment of 16 bytes.  This is sufficient
        for all current targets, and excess alignment is harmless.  */
     stack_len = bprm->envc + bprm->argc + 2;
     stack_len += 3;    /* argc, arvg, argp */
-    stack_len *= sizeof(target_ulong);
+    stack_len *= sizeof(abi_ulong);
     if ((sp + stack_len) & 15)
         sp -= 16 - ((sp + stack_len) & 15);
-    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
+    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p,
+                             flat_argvp_envp_on_stack());
 
     /* Fake some return addresses to ensure the call chain will
      * initialise library in order for us.  We are required to call
@@ -779,7 +786,9 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     for (i = MAX_SHARED_LIBS-1; i>0; i--) {
             if (libinfo[i].loaded) {
                     /* Push previos first to call address */
-                    --sp;      put_user(start_addr, sp);
+                    --sp;
+                    if (put_user_ual(start_addr, sp))
+                        return -EFAULT;
                     start_addr = libinfo[i].entry;
             }
     }
@@ -792,6 +801,7 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     info->end_data = libinfo[0].end_data;
     info->start_brk = libinfo[0].start_brk;
     info->start_stack = sp;
+    info->stack_limit = libinfo[0].start_brk;
     info->entry = start_addr;
     info->code_offset = info->start_code;
     info->data_offset = info->start_data - libinfo[0].text_len;