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