summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2015-08-20 14:33:30 +0000
committerjhb <jhb@FreeBSD.org>2015-08-20 14:33:30 +0000
commitedef59ae5270c40a1bc788aecacfae56ae788cd2 (patch)
tree5577fe5b1d9e5a6495688b8baaf8afe3a31d66fc
parentca3ff2693cd42d868756745a08d82eea4a66c79f (diff)
downloadFreeBSD-src-edef59ae5270c40a1bc788aecacfae56ae788cd2.zip
FreeBSD-src-edef59ae5270c40a1bc788aecacfae56ae788cd2.tar.gz
Rework the argv and env string fetching for execve to be more robust.
Before truss would fetch 100 string pointers and happily walk off the end of the array if it never found a NULL. This also means for a short argv list it could fail entirely if the 100 string pointers spanned into an unmapped page. Instead, fetch page-aligned blocks of string pointers in a loop fetching each string until a NULL is found. While here, make use of the open memstream file descriptor instead of allocating a temporary array. This allows us to fetch each string once instead of twice.
-rw-r--r--usr.bin/truss/syscalls.c70
1 files changed, 44 insertions, 26 deletions
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c
index 0df8d9a..91769fb 100644
--- a/usr.bin/truss/syscalls.c
+++ b/usr.bin/truss/syscalls.c
@@ -913,36 +913,54 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval,
break;
}
case StringArray: {
- int num, size, i;
- char *tmp2;
+ uintptr_t addr;
+ union {
+ char *strarray[0];
+ char buf[PAGE_SIZE];
+ } u;
char *string;
- char *strarray[100]; /* XXX This is ugly. */
-
- if (get_struct(pid, (void *)args[sc->offset],
- (void *)&strarray, sizeof(strarray)) == -1)
- err(1, "get_struct %p", (void *)args[sc->offset]);
- num = 0;
- size = 0;
-
- /* Find out how large of a buffer we'll need. */
- while (strarray[num] != NULL) {
- string = get_string(pid, (void*)strarray[num], 0);
- size += strlen(string);
- free(string);
- num++;
+ size_t len;
+ int first, i;
+
+ /*
+ * Read a page of pointers at a time. Punt if the top-level
+ * pointer is not aligned. Note that the first read is of
+ * a partial page.
+ */
+ addr = args[sc->offset];
+ if (addr % sizeof(char *) != 0) {
+ fprintf(fp, "0x%lx", args[sc->offset]);
+ break;
+ }
+
+ len = PAGE_SIZE - (addr & PAGE_MASK);
+ if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
+ fprintf(fp, "0x%lx", args[sc->offset]);
+ break;
}
- size += 4 + (num * 4);
- tmp = (char *)malloc(size);
- tmp2 = tmp;
-
- tmp2 += sprintf(tmp2, " [");
- for (i = 0; i < num; i++) {
- string = get_string(pid, (void*)strarray[i], 0);
- tmp2 += sprintf(tmp2, " \"%s\"%c", string,
- (i + 1 == num) ? ' ' : ',');
+
+ fputc('[', fp);
+ first = 1;
+ i = 0;
+ while (u.strarray[i] != NULL) {
+ string = get_string(pid, u.strarray[i], 0);
+ fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
free(string);
+ first = 0;
+
+ i++;
+ if (i == len / sizeof(char *)) {
+ addr += len;
+ len = PAGE_SIZE;
+ if (get_struct(pid, (void *)addr, u.buf, len) ==
+ -1) {
+ fprintf(fp, ", <inval>");
+ break;
+ }
+ i = 0;
+ }
}
- tmp2 += sprintf(tmp2, "]");
+ fputs(" ]", fp);
break;
}
#ifdef __LP64__
OpenPOWER on IntegriCloud