summaryrefslogtreecommitdiffstats
path: root/updater
diff options
context:
space:
mode:
authorSami Tolvanen <samitolvanen@google.com>2015-05-12 12:48:46 +0100
committerSteve Kondik <steve@cyngn.com>2015-11-07 19:02:26 -0800
commit84e7357a07c9dbecc83a5f3efa98cfc0f8289178 (patch)
tree02b4dfdb725b3e55fc0e59affbfa4fbf79aa3a65 /updater
parentacbc99951465efa22e9cd97613ebf57029cdacb4 (diff)
downloadbootable_recovery-84e7357a07c9dbecc83a5f3efa98cfc0f8289178.zip
bootable_recovery-84e7357a07c9dbecc83a5f3efa98cfc0f8289178.tar.gz
bootable_recovery-84e7357a07c9dbecc83a5f3efa98cfc0f8289178.tar.bz2
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
Diffstat (limited to 'updater')
-rw-r--r--updater/blockimg.c81
1 files changed, 71 insertions, 10 deletions
diff --git a/updater/blockimg.c b/updater/blockimg.c
index b006d10..e0be039 100644
--- a/updater/blockimg.c
+++ b/updater/blockimg.c
@@ -61,30 +61,91 @@ typedef struct {
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) {