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
[email protected]
https://lists.osdl.org/mailman/listinfo/fastboot