mirror of
https://github.com/curl/curl.git
synced 2026-04-25 00:12:12 +03:00
mime: only allow 40 levels of calls
To avoid problems when doing insane things. Closes #21384
This commit is contained in:
parent
5448495cfd
commit
d087a7e4ec
1 changed files with 34 additions and 13 deletions
47
lib/mime.c
47
lib/mime.c
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue