]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - fs/binfmt_flat.c
ocfs2: fix possible use-after-free with AIO
[linux-2.6.git] / fs / binfmt_flat.c
index 697f6b5f13139ac5ea95a3f7456687299f26775e..6b2daf99fab8bcd91d314f0abd951b8472a092d2 100644 (file)
@@ -15,7 +15,7 @@
  *     JAN/99 -- coded full program relocation (gerg@snapgear.com)
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -37,7 +37,6 @@
 #include <linux/syscalls.h>
 
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
 #endif
 
 /*
- * User data (stack, data section and bss) needs to be aligned
- * for the same reasons as SLAB memory is, and to the same amount.
- * Avoid duplicating architecture specific code by using the same
- * macro as with SLAB allocation:
+ * User data (data section and bss) needs to be aligned.
+ * We pick 0x20 here because it is the max value elf2flt has always
+ * used in producing FLAT files, and because it seems to be large
+ * enough to make all the gcc alignment related tests happy.
  */
-#ifdef ARCH_SLAB_MINALIGN
-#define FLAT_DATA_ALIGN        (ARCH_SLAB_MINALIGN)
-#else
-#define FLAT_DATA_ALIGN        (sizeof(void *))
-#endif
+#define FLAT_DATA_ALIGN        (0x20)
+
+/*
+ * User data (stack) also needs to be aligned.
+ * Here we can be a bit looser than the data sections since this
+ * needs to only meet arch ABI requirements.
+ */
+#define FLAT_STACK_ALIGN       max_t(unsigned long, sizeof(void *), ARCH_SLAB_MINALIGN)
 
 #define RELOC_FAILED 0xff00ff01                /* Relocation incorrect somewhere */
 #define UNLOADED_LIB 0x7ff000ff                /* Placeholder for unused library */
@@ -87,7 +89,7 @@ static int load_flat_shared_library(int id, struct lib_info *p);
 #endif
 
 static int load_flat_binary(struct linux_binprm *, struct pt_regs * regs);
-static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
+static int flat_core_dump(struct coredump_params *cprm);
 
 static struct linux_binfmt flat_format = {
        .module         = THIS_MODULE,
@@ -102,10 +104,10 @@ static struct linux_binfmt flat_format = {
  * Currently only a stub-function.
  */
 
-static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
+static int flat_core_dump(struct coredump_params *cprm)
 {
        printk("Process %s:%d received signr %d and should have core dumped\n",
-                       current->comm, current->pid, (int) signr);
+                       current->comm, current->pid, (int) cprm->signr);
        return(1);
 }
 
@@ -129,7 +131,7 @@ static unsigned long create_flat_tables(
 
        sp = (unsigned long *)p;
        sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
-       sp = (unsigned long *) ((unsigned long)sp & -FLAT_DATA_ALIGN);
+       sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN);
        argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
        envp = argv + (argc + 1);
 
@@ -278,8 +280,6 @@ static int decompress_exec(
                ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
                if (ret <= 0)
                        break;
-               if (ret >= (unsigned long) -4096)
-                       break;
                len -= ret;
 
                strm.next_in = buf;
@@ -335,7 +335,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
                                        "(%d != %d)", (unsigned) r, curid, id);
                        goto failed;
                } else if ( ! p->lib_list[id].loaded &&
-                               load_flat_shared_library(id, p) > (unsigned long) -4096) {
+                               IS_ERR_VALUE(load_flat_shared_library(id, p))) {
                        printk("BINFMT_FLAT: failed to load library %d", id);
                        goto failed;
                }
@@ -357,7 +357,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
 
        if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
                printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x/0x%x)",
-                      (int) r,(int)(start_brk-start_code),(int)text_len);
+                      (int) r,(int)(start_brk-start_data+text_len),(int)text_len);
                goto failed;
        }
 
@@ -503,7 +503,7 @@ static int load_flat_file(struct linux_binprm * bprm,
         * size limits imposed on them by creating programs with large
         * arrays in the data or bss.
         */
-       rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
+       rlim = rlimit(RLIMIT_DATA);
        if (rlim >= RLIM_INFINITY)
                rlim = ~0;
        if (data_len + bss_len > rlim) {
@@ -521,6 +521,7 @@ static int load_flat_file(struct linux_binprm * bprm,
 
                /* OK, This is the point of no return */
                set_personality(PER_LINUX_32BIT);
+               setup_new_exec(bprm);
        }
 
        /*
@@ -541,11 +542,9 @@ static int load_flat_file(struct linux_binprm * bprm,
                 */
                DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
 
-               down_write(&current->mm->mmap_sem);
-               textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
+               textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
                                  MAP_PRIVATE|MAP_EXECUTABLE, 0);
-               up_write(&current->mm->mmap_sem);
-               if (!textpos  || textpos >= (unsigned long) -4096) {
+               if (!textpos || IS_ERR_VALUE(textpos)) {
                        if (!textpos)
                                textpos = (unsigned long) -ENOMEM;
                        printk("Unable to mmap process text, errno %d\n", (int)-textpos);
@@ -555,12 +554,10 @@ static int load_flat_file(struct linux_binprm * bprm,
 
                len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
                len = PAGE_ALIGN(len);
-               down_write(&current->mm->mmap_sem);
-               realdatastart = do_mmap(0, 0, len,
+               realdatastart = vm_mmap(0, 0, len,
                        PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
-               up_write(&current->mm->mmap_sem);
 
-               if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) {
+               if (realdatastart == 0 || IS_ERR_VALUE(realdatastart)) {
                        if (!realdatastart)
                                realdatastart = (unsigned long) -ENOMEM;
                        printk("Unable to allocate RAM for process data, errno %d\n",
@@ -587,10 +584,10 @@ static int load_flat_file(struct linux_binprm * bprm,
                        result = bprm->file->f_op->read(bprm->file, (char *) datapos,
                                        data_len + (relocs * sizeof(unsigned long)), &fpos);
                }
-               if (result >= (unsigned long)-4096) {
+               if (IS_ERR_VALUE(result)) {
                        printk("Unable to read data+bss, errno %d\n", (int)-result);
                        do_munmap(current->mm, textpos, text_len);
-                       do_munmap(current->mm, realdatastart, data_len + extra);
+                       do_munmap(current->mm, realdatastart, len);
                        ret = result;
                        goto err;
                }
@@ -602,12 +599,10 @@ static int load_flat_file(struct linux_binprm * bprm,
 
                len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
                len = PAGE_ALIGN(len);
-               down_write(&current->mm->mmap_sem);
-               textpos = do_mmap(0, 0, len,
+               textpos = vm_mmap(0, 0, len,
                        PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
-               up_write(&current->mm->mmap_sem);
 
-               if (!textpos  || textpos >= (unsigned long) -4096) {
+               if (!textpos || IS_ERR_VALUE(textpos)) {
                        if (!textpos)
                                textpos = (unsigned long) -ENOMEM;
                        printk("Unable to allocate RAM for process text/data, errno %d\n",
@@ -641,7 +636,7 @@ static int load_flat_file(struct linux_binprm * bprm,
                        fpos = 0;
                        result = bprm->file->f_op->read(bprm->file,
                                        (char *) textpos, text_len, &fpos);
-                       if (result < (unsigned long) -4096)
+                       if (!IS_ERR_VALUE(result))
                                result = decompress_exec(bprm, text_len, (char *) datapos,
                                                 data_len + (relocs * sizeof(unsigned long)), 0);
                }
@@ -651,13 +646,13 @@ static int load_flat_file(struct linux_binprm * bprm,
                        fpos = 0;
                        result = bprm->file->f_op->read(bprm->file,
                                        (char *) textpos, text_len, &fpos);
-                       if (result < (unsigned long) -4096) {
+                       if (!IS_ERR_VALUE(result)) {
                                fpos = ntohl(hdr->data_start);
                                result = bprm->file->f_op->read(bprm->file, (char *) datapos,
                                        data_len + (relocs * sizeof(unsigned long)), &fpos);
                        }
                }
-               if (result >= (unsigned long)-4096) {
+               if (IS_ERR_VALUE(result)) {
                        printk("Unable to read code+data+bss, errno %d\n",(int)-result);
                        do_munmap(current->mm, textpos, text_len + data_len + extra +
                                MAX_SHARED_LIBS * sizeof(unsigned long));
@@ -715,7 +710,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
@@ -818,6 +813,8 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
        int res;
        char buf[16];
 
+       memset(&bprm, 0, sizeof(bprm));
+
        /* Create the file name */
        sprintf(buf, "/lib/lib%d.so", id);
 
@@ -828,15 +825,28 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
        if (IS_ERR(bprm.file))
                return res;
 
+       bprm.cred = prepare_exec_creds();
+       res = -ENOMEM;
+       if (!bprm.cred)
+               goto out;
+
+       /* We don't really care about recalculating credentials at this point
+        * as we're past the point of no return and are dealing with shared
+        * libraries.
+        */
+       bprm.cred_prepared = 1;
+
        res = prepare_binprm(&bprm);
 
-       if (res <= (unsigned long)-4096)
+       if (!IS_ERR_VALUE(res))
                res = load_flat_file(&bprm, libs, id, NULL);
-       if (bprm.file) {
-               allow_write_access(bprm.file);
-               fput(bprm.file);
-               bprm.file = NULL;
-       }
+
+       abort_creds(bprm.cred);
+
+out:
+       allow_write_access(bprm.file);
+       fput(bprm.file);
+
        return(res);
 }
 
@@ -870,10 +880,10 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
        stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
        stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
-       stack_len += FLAT_DATA_ALIGN - 1;  /* reserve for upcoming alignment */
+       stack_len += FLAT_STACK_ALIGN - 1;  /* reserve for upcoming alignment */
        
        res = load_flat_file(bprm, &libinfo, 0, &stack_len);
-       if (res > (unsigned long)-4096)
+       if (IS_ERR_VALUE(res))
                return res;
        
        /* Update data segment pointers for all libraries */
@@ -885,7 +895,6 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                                                libinfo.lib_list[j].start_data:UNLOADED_LIB;
 
        install_exec_creds(bprm);
-       current->flags &= ~PF_FORKNOEXEC;
 
        set_binfmt(&flat_format);
 
@@ -933,7 +942,8 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 
 static int __init init_flat_binfmt(void)
 {
-       return register_binfmt(&flat_format);
+       register_binfmt(&flat_format);
+       return 0;
 }
 
 /****************************************************************************/