Add error and range checks to parse_range
Only trusted input is passed to parse_range, but check for invalid
input to catch possible problems in transfer lists.
Bug: 21033983
Bug: 21034030
Bug: 21034172
Bug: 21034406
Change-Id: Ia17537a2d23d5f701522fbc42ed38924e1ee3366
diff --git a/updater/blockimg.c b/updater/blockimg.c
index 532e7b8..a98cdcc 100644
--- a/updater/blockimg.c
+++ b/updater/blockimg.c
@@ -60,30 +60,91 @@
int pos[0];
} RangeSet;
+#define RANGESET_MAX_POINTS \
+ ((int)((INT_MAX / sizeof(int)) - sizeof(RangeSet)))
+
static RangeSet* parse_range(char* text) {
char* save;
- int num;
- num = strtol(strtok_r(text, ",", &save), NULL, 0);
+ char* token;
+ int i, num;
+ long int val;
+ RangeSet* out = NULL;
+ size_t bufsize;
- RangeSet* out = malloc(sizeof(RangeSet) + num * sizeof(int));
- if (out == NULL) {
- fprintf(stderr, "failed to allocate range of %zu bytes\n",
- sizeof(RangeSet) + num * sizeof(int));
- exit(1);
+ if (!text) {
+ goto err;
}
+
+ token = strtok_r(text, ",", &save);
+
+ if (!token) {
+ goto err;
+ }
+
+ val = strtol(token, NULL, 0);
+
+ if (val < 2 || val > RANGESET_MAX_POINTS) {
+ goto err;
+ } else if (val % 2) {
+ goto err; // must be even
+ }
+
+ num = (int) val;
+ bufsize = sizeof(RangeSet) + num * sizeof(int);
+
+ out = malloc(bufsize);
+
+ if (!out) {
+ fprintf(stderr, "failed to allocate range of %zu bytes\n", bufsize);
+ goto err;
+ }
+
out->count = num / 2;
out->size = 0;
- int i;
+
for (i = 0; i < num; ++i) {
- out->pos[i] = strtol(strtok_r(NULL, ",", &save), NULL, 0);
- if (i%2) {
+ token = strtok_r(NULL, ",", &save);
+
+ if (!token) {
+ goto err;
+ }
+
+ val = strtol(token, NULL, 0);
+
+ if (val < 0 || val > INT_MAX) {
+ goto err;
+ }
+
+ out->pos[i] = (int) val;
+
+ if (i % 2) {
+ if (out->pos[i - 1] >= out->pos[i]) {
+ goto err; // empty or negative range
+ }
+
+ if (out->size > INT_MAX - out->pos[i]) {
+ goto err; // overflow
+ }
+
out->size += out->pos[i];
} else {
+ if (out->size < 0) {
+ goto err;
+ }
+
out->size -= out->pos[i];
}
}
+ if (out->size <= 0) {
+ goto err;
+ }
+
return out;
+
+err:
+ fprintf(stderr, "failed to parse range '%s'\n", text ? text : "NULL");
+ exit(1);
}
static int range_overlaps(RangeSet* r1, RangeSet* r2) {