Make sure access to dtstruct does not overflow.

*** This is a fairly large patch, and I am not 100% that it
*** (or what it replaces) is correct

Signed-off-by: Simon Horman <[EMAIL PROTECTED]>

Index: kexec-tools-testing/kexec/arch/ppc64/fs2dt.c
===================================================================
--- kexec-tools-testing.orig/kexec/arch/ppc64/fs2dt.c   2006-12-11 
14:48:59.000000000 +0900
+++ kexec-tools-testing/kexec/arch/ppc64/fs2dt.c        2006-12-11 
14:49:48.000000000 +0900
@@ -39,7 +39,8 @@
 
 static char pathname[MAXPATH], *pathstart;
 static char propnames[NAMESPACE] = { 0 };
-static unsigned dtstruct[TREEWORDS], *dt;
+static unsigned dtstruct[TREEWORDS];
+static int dtstruct_offset = 0;
 static unsigned long long mem_rsrv[2*MEMRESERVE] = { 0, 0 };
 
 static int initrd_found = 0;
@@ -111,6 +112,79 @@
        return offset;
 }
 
+static unsigned *dtstruct_get_ptr(void)
+{
+       return dtstruct + dtstruct_offset;
+}
+
+static size_t dtstruct_get_offset(void)
+{
+       return dtstruct_offset;
+}
+
+static void dtstruct_assign(unsigned val)
+{
+       dtstruct[dtstruct_offset++] = val;
+       if (dtstruct_offset == TREEWORDS)
+               die("unrecoverable error: dtstruct overflow\n");
+}
+
+static void dtstruct_align8(void)
+{
+       while (dtstruct_offset & 2)
+               dtstruct_assign(0);
+}
+
+static void dtstruct_assign_buf(const void *data, size_t bytes)
+{
+       unsigned tail;
+
+       tail = bytes % sizeof(unsigned);
+       if (tail)
+               tail = sizeof(unsigned) - tail;
+       if (TREEWORDS - dtstruct_offset < (bytes + tail) / sizeof(unsigned))
+               die("unrecoverable error: dtstruct overflow\n");
+       if (tail)
+               memset(dtstruct + dtstruct_offset, 0, bytes + tail);
+       memcpy(dtstruct + dtstruct_offset, data, bytes);
+       dtstruct_offset += (bytes + tail) / sizeof(unsigned);
+}
+
+static void dtstruct_assign_str(const char *str)
+{
+       dtstruct_assign_buf(str, strlen(str) + 1);
+}
+
+static ssize_t dtstruct_read(int fd, size_t bytes)
+{
+       size_t tail;
+
+       tail = bytes % sizeof(unsigned);
+       if (tail)
+               tail = sizeof(unsigned) - tail;
+       if (TREEWORDS - dtstruct_offset < (bytes + tail) / sizeof(unsigned))
+               die("unrecoverable error: dtstruct overflow\n");
+       if (tail)
+               memset(dtstruct + dtstruct_offset, 0, bytes + tail);
+       if (read(fd, dtstruct + dtstruct_offset, bytes) != bytes)
+               return -1;
+       dtstruct_offset += (bytes + tail) / sizeof(unsigned);
+
+       return (bytes + tail) / sizeof(unsigned);
+}
+
+static size_t dtstruct_seek(ssize_t offset)
+{
+       if (offset > 0 && TREEWORDS - dtstruct_offset < offset)
+               die("unrecoverable error: dtstruct overflow\n");
+       else if (offset < 0 && offset > dtstruct_offset)
+               die("unrecoverable error: dtstruct overflow\n");
+
+       dtstruct_offset += offset;
+
+       return dtstruct_offset;
+}
+
 static void add_usable_mem_property(int fd, int len)
 {
        char fname[MAXPATH], *bname;
@@ -172,13 +246,12 @@
        /*
         * No add linux,usable-memory property.
         */
-       *dt++ = 3;
-       *dt++ = rlen;
-       *dt++ = propnum("linux,usable-memory");
-       if ((rlen >= 8) && ((unsigned long)dt & 0x4))
-               dt++;
-       memcpy(dt,&ranges,rlen);
-       dt += (rlen + 3)/4;
+       dtstruct_assign(3);
+       dtstruct_assign(rlen);
+       dtstruct_assign(propnum("linux,usable-memory"));
+       if (rlen >= 8)
+               dtstruct_align8();
+       dtstruct_assign_buf(&ranges, rlen);
 }
 
 /* put all properties (files) in the property structure */
@@ -186,7 +259,9 @@
 {
        struct dirent *dp;
        int i = 0, fd, len;
+       ssize_t read_len;
        struct stat statbuf;
+       unsigned *new_data;
 
        for (i = 0; i < numlist; i++) {
                dp = nlist[i];
@@ -227,24 +302,26 @@
 
                len = statbuf.st_size;
 
-               *dt++ = 3;
-               dt_len = dt;
-               *dt++ = len;
-               *dt++ = propnum(fn);
-
-               if ((len >= 8) && ((unsigned long)dt & 0x4))
-                       dt++;
+               dtstruct_assign(3);
+               dt_len = dtstruct_get_ptr();
+               dtstruct_assign(len);
+               dtstruct_assign(propnum(fn));
+               if (len >= 8)
+                       dtstruct_align8();
 
                fd = open(pathname, O_RDONLY);
                if (fd == -1)
                        die("unrecoverable error: could not open \"%s\": %s\n",
                            pathname, strerror(errno));
 
-               if (read(fd, dt, len) != len)
+               if ( (read_len = dtstruct_read(fd, len)) < 0 )
                        die("unrecoverable error: could not read \"%s\": %s\n",
                            pathname, strerror(errno));
 
-               checkprop(fn, dt);
+               dtstruct_seek(-read_len);
+               new_data = dtstruct_get_ptr();
+
+               checkprop(fn, new_data);
 
                /* Get the cmdline from the device-tree and modify it */
                if (!strcmp(dp->d_name, "bootargs")) {
@@ -260,7 +337,7 @@
                        }
                        if (!param) {
                                char *old_param;
-                               memcpy(temp_cmdline, dt, len);
+                               memcpy(temp_cmdline, new_data, len);
                                param = strstr(temp_cmdline, "root=");
                                if (param) {
                                        old_param = strtok(param, " ");
@@ -272,13 +349,14 @@
                        strcat(local_cmdline, " ");
                        cmd_len = strlen(local_cmdline);
                        cmd_len = cmd_len + 1;
-                       memcpy(dt, local_cmdline,cmd_len);
+                       dtstruct_assign_buf(local_cmdline, cmd_len);
                        len = cmd_len;
                        *dt_len = cmd_len;
                        fprintf(stderr, "Modified cmdline:%s\n", local_cmdline);
                }
+               else
+                       dtstruct_seek(read_len);
 
-               dt += (len + 3)/4;
                if (!strcmp(dp->d_name, "reg") && usablemem_rgns.size)
                        add_usable_mem_property(fd, len);
                close(fd);
@@ -323,12 +401,8 @@
        int numlist, i;
        struct stat statbuf;
 
-       *dt++ = 1;
-       strcpy((void *)dt, *pathstart ? pathstart : "/");
-       while(*dt)
-               dt++;
-       if (dt[-1] & 0xff)
-               dt++;
+       dtstruct_assign(1);
+       dtstruct_assign_str(*pathstart ? pathstart : "/");
 
        numlist = scandir(pathname, &namelist, 0, comparefunc);
        if (numlist < 0)
@@ -350,28 +424,21 @@
         */
        if (initrd_base && !initrd_found && !strcmp(basename,"/chosen/")) {
                int len = 8;
-               unsigned long long initrd_end;
-               *dt++ = 3;
-               *dt++ = len;
-               *dt++ = propnum("linux,initrd-start");
-
-               if ((len >= 8) && ((unsigned long)dt & 0x4))
-                       dt++;
-
-               memcpy(dt,&initrd_base,len);
-               dt += (len + 3)/4;
-
-               len = 8;
-               *dt++ = 3;
-               *dt++ = len;
-               *dt++ = propnum("linux,initrd-end");
-
-               initrd_end = initrd_base + initrd_size;
-               if ((len >= 8) && ((unsigned long)dt & 0x4))
-                       dt++;
+               unsigned long initrd_end;
 
-               memcpy(dt,&initrd_end,len);
-               dt += (len + 3)/4;
+               dtstruct_assign(3);
+               dtstruct_assign(len);
+               dtstruct_assign(propnum("linux,initrd-start"));
+               dtstruct_align8();
+               dtstruct_assign_buf(&initrd_base, len);
+
+               dtstruct_assign(3);
+               dtstruct_assign(len);
+               dtstruct_assign(propnum("linux,initrd-end"));
+
+               dtstruct_align8();
+               initrd_end =initrd_base + initrd_size;
+               dtstruct_assign_buf(&initrd_end, len);
 
                reserve(initrd_base, initrd_size);
        }
@@ -392,7 +459,7 @@
                        putnode();
        }
 
-       *dt++ = 2;
+       dtstruct_assign(2);
        dn[-1] = '\0';
        free(namelist);
 }
@@ -410,13 +477,12 @@
        strcpy(pathname, "/proc/device-tree/");
 
        pathstart = pathname + strlen(pathname);
-       dt = dtstruct;
 
        if (cmdline)
                strcpy(local_cmdline, cmdline);
 
        putnode();
-       *dt++ = 9;
+       dtstruct_assign(9);
 
        len = sizeof(bb[0]);
        len += 7; len &= ~7;
@@ -430,8 +496,7 @@
 
        bb->off_dt_struct = bb->off_mem_rsvmap + len;
 
-       len = dt - dtstruct;
-       len *= sizeof(unsigned);
+       len = dtstruct_get_offset() * sizeof(unsigned);
        bb->off_dt_strings = bb->off_dt_struct + len;
 
        len = propnum("");
@@ -445,6 +510,9 @@
        reserve(me, bb->totalsize); /* patched later in kexec_load */
 
        buf = (unsigned char *) malloc(bb->totalsize);
+       if (!buf)
+               die("unrecoverable error: could not allocate memory: %s\n",
+                   strerror(errno));
        *bufp = buf;
        memcpy(buf, bb, bb->off_mem_rsvmap);
        tlen = bb->off_mem_rsvmap;

--

-- 
Horms
  H: http://www.vergenet.net/~horms/
  W: http://www.valinux.co.jp/en/

_______________________________________________
fastboot mailing list
fastboot@lists.osdl.org
https://lists.osdl.org/mailman/listinfo/fastboot

Reply via email to