mime: only allow 40 levels of calls
No binary (build failed)
—
(log yok)
| @@ -44,11 +44,14 @@ struct Curl_easy; | |
| #include "slist.h" | |
| #include "curlx/dynbuf.h" | |
| + | #define MAX_MIME_LEVELS 40 /* avoid deep nesting */ |
| + | |
| #define READ_ERROR ((size_t)-1) | |
| #define STOP_FILLING ((size_t)-2) | |
| static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, | |
| - | void *instream, bool *hasread); |
| + | void *instream, bool *hasread, |
| + | size_t call_depth); |
| static curl_off_t mime_size(curl_mimepart *part); | |
| /* Quoted-printable character class table. | |
| @@ -687,11 +690,16 @@ static size_t readback_bytes(struct mime_state *state, | |
| } | |
| /* Read a non-encoded part content. */ | |
| - | static size_t read_part_content(curl_mimepart *part, |
| - | char *buffer, size_t bufsize, bool *hasread) |
| + | |
| + | static size_t read_part_content(curl_mimepart *part, char *buffer, |
| + | size_t bufsize, bool *hasread, |
| + | size_t call_depth) |
| { | |
| size_t sz = 0; | |
| + | if(++call_depth > MAX_MIME_LEVELS) |
| + | return READ_ERROR; |
| + | |
| switch(part->lastreadstatus) { | |
| case 0: | |
| case CURL_READFUNC_ABORT: | |
| @@ -714,7 +722,8 @@ static size_t read_part_content(curl_mimepart *part, | |
| * Cannot be processed as other kinds since read function requires | |
| * an additional parameter and is highly recursive. | |
| */ | |
| - | sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread); |
| + | sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread, |
| + | call_depth); |
| break; | |
| case MIMEKIND_FILE: | |
| if(part->fp && feof(part->fp)) | |
| @@ -753,13 +762,17 @@ static size_t read_part_content(curl_mimepart *part, | |
| /* Read and encode part content. */ | |
| static size_t read_encoded_part_content(curl_mimepart *part, char *buffer, | |
| - | size_t bufsize, bool *hasread) |
| + | size_t bufsize, bool *hasread, |
| + | size_t call_depth) |
| { | |
| struct mime_encoder_state *st = &part->encstate; | |
| size_t cursize = 0; | |
| size_t sz; | |
| bool ateof = FALSE; | |
| + | if(++call_depth > MAX_MIME_LEVELS) |
| + | return READ_ERROR; |
| + | |
| for(;;) { | |
| if(st->bufbeg < st->bufend || ateof) { | |
| /* Encode buffered data. */ | |
| @@ -792,7 +805,7 @@ static size_t read_encoded_part_content(curl_mimepart *part, char *buffer, | |
| if(st->bufend >= sizeof(st->buf)) | |
| return cursize ? cursize : READ_ERROR; /* Buffer full. */ | |
| sz = read_part_content(part, st->buf + st->bufend, | |
| - | sizeof(st->buf) - st->bufend, hasread); |
| + | sizeof(st->buf) - st->bufend, hasread, call_depth); |
| switch(sz) { | |
| case 0: | |
| ateof = TRUE; | |
| @@ -813,12 +826,15 @@ static size_t read_encoded_part_content(curl_mimepart *part, char *buffer, | |
| /* Readback a mime part. */ | |
| static size_t readback_part(curl_mimepart *part, | |
| - | char *buffer, size_t bufsize, bool *hasread) |
| + | char *buffer, size_t bufsize, bool *hasread, |
| + | size_t call_depth) |
| { | |
| size_t cursize = 0; | |
| - | /* Readback from part. */ |
| + | if(++call_depth > MAX_MIME_LEVELS) |
| + | return READ_ERROR; |
| + | /* Readback from part. */ |
| while(bufsize) { | |
| size_t sz = 0; | |
| struct curl_slist *hdr = (struct curl_slist *)part->state.ptr; | |
| @@ -861,9 +877,10 @@ static size_t readback_part(curl_mimepart *part, | |
| break; | |
| case MIMESTATE_CONTENT: | |
| if(part->encoder) | |
| - | sz = read_encoded_part_content(part, buffer, bufsize, hasread); |
| + | sz = read_encoded_part_content(part, buffer, bufsize, hasread, |
| + | call_depth); |
| else | |
| - | sz = read_part_content(part, buffer, bufsize, hasread); |
| + | sz = read_part_content(part, buffer, bufsize, hasread, call_depth); |
| switch(sz) { | |
| case 0: | |
| mimesetstate(&part->state, MIMESTATE_END, NULL); | |
| @@ -897,12 +914,16 @@ static size_t readback_part(curl_mimepart *part, | |
| /* Readback from mime. Warning: not a read callback function. */ | |
| static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, | |
| - | void *instream, bool *hasread) |
| + | void *instream, bool *hasread, |
| + | size_t call_depth) |
| { | |
| curl_mime *mime = (curl_mime *)instream; | |
| size_t cursize = 0; | |
| (void)size; /* Always 1 */ | |
| + | if(++call_depth > MAX_MIME_LEVELS) |
| + | return READ_ERROR; |
| + | |
| while(nitems) { | |
| size_t sz = 0; | |
| curl_mimepart *part = mime->state.ptr; | |
| @@ -937,7 +958,7 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, | |
| mimesetstate(&mime->state, MIMESTATE_END, NULL); | |
| break; | |
| } | |
| - | sz = readback_part(part, buffer, nitems, hasread); |
| + | sz = readback_part(part, buffer, nitems, hasread, call_depth); |
| switch(sz) { | |
| case CURL_READFUNC_ABORT: | |
| case CURL_READFUNC_PAUSE: | |
| @@ -1506,7 +1527,7 @@ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) | |
| * adding any data and this loops infinitely. */ | |
| do { | |
| hasread = FALSE; | |
| - | ret = readback_part(part, buffer, nitems, &hasread); |
| + | ret = readback_part(part, buffer, nitems, &hasread, 0); |
| /* | |
| * If this is not possible to get some data without calling more than | |
| * one read callback (probably because a content encoder is not able to | |