upnphttp: improve robustness against malformed (possibly malicious) requests

This commit is contained in:
Catalin Patulea 2014-03-02 23:33:50 -05:00 committed by Justin Maggard
parent 01532b0490
commit 57c6510fe4

View File

@ -150,7 +150,7 @@ ParseHttpHeaders(struct upnphttp * h)
if(strncasecmp(line, "Content-Length", 14)==0)
{
p = colon;
while(*p < '0' || *p > '9')
while(*p && (*p < '0' || *p > '9'))
p++;
h->req_contentlen = atoi(p);
}
@ -161,13 +161,13 @@ ParseHttpHeaders(struct upnphttp * h)
while(*p == ':' || *p == ' ' || *p == '\t')
p++;
while(p[n] >= ' ')
{
n++;
}
if((p[0] == '"' && p[n-1] == '"')
|| (p[0] == '\'' && p[n-1] == '\''))
if(n >= 2 &&
((p[0] == '"' && p[n-1] == '"') ||
(p[0] == '\'' && p[n-1] == '\'')))
{
p++; n -= 2;
p++;
n -= 2;
}
h->req_soapAction = p;
h->req_soapActionLen = n;
@ -175,10 +175,10 @@ ParseHttpHeaders(struct upnphttp * h)
else if(strncasecmp(line, "Callback", 8)==0)
{
p = colon;
while(*p != '<' && *p != '\r' )
while(*p && *p != '<' && *p != '\r' )
p++;
n = 0;
while(p[n] != '>' && p[n] != '\r' )
while(p[n] && p[n] != '>' && p[n] != '\r' )
n++;
h->req_Callback = p + 1;
h->req_CallbackLen = MAX(0, n - 1);
@ -200,7 +200,7 @@ ParseHttpHeaders(struct upnphttp * h)
while(isspace(*p))
p++;
n = 0;
while(!isspace(p[n]))
while(p[n] && !isspace(p[n]))
n++;
h->req_SID = p;
h->req_SIDLen = n;
@ -212,7 +212,7 @@ ParseHttpHeaders(struct upnphttp * h)
while(isspace(*p))
p++;
n = 0;
while(!isspace(p[n]))
while(p[n] && !isspace(p[n]))
n++;
h->req_NT = p;
h->req_NTLen = n;
@ -396,8 +396,11 @@ ParseHttpHeaders(struct upnphttp * h)
}
}
next_header:
while(!(line[0] == '\r' && line[1] == '\n'))
line++;
line = strstr(line, "\r\n");
if (!line)
{
return;
}
line += 2;
}
if( h->reqflags & FLAG_CHUNKED )
@ -410,9 +413,10 @@ next_header:
(h->req_chunklen = strtol(line, &endptr, 16)) &&
(endptr != line) )
{
while(!(endptr[0] == '\r' && endptr[1] == '\n'))
endptr = strstr(endptr, "\r\n");
if (!endptr)
{
endptr++;
return;
}
line = endptr+h->req_chunklen+2;
}
@ -541,18 +545,6 @@ Send501(struct upnphttp * h)
CloseSocket_upnphttp(h);
}
static const char *
findendheaders(const char * s, int len)
{
while(len-- > 0)
{
if(s[0]=='\r' && s[1]=='\n' && s[2]=='\r' && s[3]=='\n')
return s;
s++;
}
return NULL;
}
/* Sends the description generated by the parameter */
static void
sendXMLdesc(struct upnphttp * h, char * (f)(int *))
@ -807,7 +799,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
p = h->req_buf;
if(!p)
return;
for(i = 0; i<15 && *p != ' ' && *p != '\r'; i++)
for(i = 0; i<15 && *p && *p != ' ' && *p != '\r'; i++)
HttpCommand[i] = *(p++);
HttpCommand[i] = '\0';
while(*p==' ')
@ -818,13 +810,13 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
while(*p!='/')
p++;
}
for(i = 0; i<511 && *p != ' ' && *p != '\r'; i++)
for(i = 0; i<511 && *p && *p != ' ' && *p != '\r'; i++)
HttpUrl[i] = *(p++);
HttpUrl[i] = '\0';
while(*p==' ')
p++;
HttpVer = h->HttpVer;
for(i = 0; i<15 && *p != '\r'; i++)
for(i = 0; i<15 && *p && *p != '\r'; i++)
HttpVer[i] = *(p++);
HttpVer[i] = '\0';
/*DPRINTF(E_INFO, L_HTTP, "HTTP REQUEST : %s %s (%s)\n",
@ -846,6 +838,11 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
/* see if we need to wait for remaining data */
if( (h->reqflags & FLAG_CHUNKED) )
{
if( h->req_chunklen == -1)
{
Send400(h);
return;
}
if( h->req_chunklen )
{
h->state = 2;
@ -856,9 +853,11 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
while( (h->req_chunklen = strtol(chunk, &endptr, 16)) && (endptr != chunk) )
{
while(!(endptr[0] == '\r' && endptr[1] == '\n'))
endptr = strstr(endptr, "\r\n");
if (!endptr)
{
endptr++;
Send400(h);
return;
}
endptr += 2;
@ -1071,7 +1070,7 @@ Process_upnphttp(struct upnphttp * h)
h->req_buflen += n;
h->req_buf[h->req_buflen] = '\0';
/* search for the string "\r\n\r\n" */
endheaders = findendheaders(h->req_buf, h->req_buflen);
endheaders = strstr(h->req_buf, "\r\n\r\n");
if(endheaders)
{
h->req_contentoff = endheaders - h->req_buf + 4;
@ -1143,56 +1142,43 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
time_t curtime = time(NULL);
char date[30];
int templen;
struct string_s res;
if(!h->res_buf)
{
templen = sizeof(httpresphead) + 256 + bodylen;
h->res_buf = (char *)malloc(templen);
h->res_buf_alloclen = templen;
}
h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
httpresphead, "HTTP/1.1",
res.data = h->res_buf;
res.size = h->res_buf_alloclen;
res.off = 0;
strcatf(&res, httpresphead, "HTTP/1.1",
respcode, respmsg,
(h->respflags&FLAG_HTML)?"text/html":"text/xml; charset=\"utf-8\"",
bodylen);
/* Additional headers */
if(h->respflags & FLAG_TIMEOUT) {
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
"Timeout: Second-");
strcatf(&res, "Timeout: Second-");
if(h->req_Timeout) {
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
"%d\r\n", h->req_Timeout);
strcatf(&res, "%d\r\n", h->req_Timeout);
} else {
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
"300\r\n");
strcatf(&res, "300\r\n");
}
}
if(h->respflags & FLAG_SID) {
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
"SID: %.*s\r\n", h->req_SIDLen, h->req_SID);
strcatf(&res, "SID: %.*s\r\n", h->req_SIDLen, h->req_SID);
}
if(h->reqflags & FLAG_LANGUAGE) {
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
"Content-Language: en\r\n");
strcatf(&res, "Content-Language: en\r\n");
}
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
"Date: %s\r\n", date);
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
"EXT:\r\n");
strcatf(&res, "Date: %s\r\n", date);
strcatf(&res, "EXT:\r\n");
#if 0 // DLNA
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
"contentFeatures.dlna.org: \r\n");
strcatf(&res, "contentFeatures.dlna.org: \r\n");
#endif
h->res_buf[h->res_buflen++] = '\r';
h->res_buf[h->res_buflen++] = '\n';
strcatf(&res, "\r\n");
h->res_buflen = res.off;
if(h->res_buf_alloclen < (h->res_buflen + bodylen))
{
h->res_buf = (char *)realloc(h->res_buf, (h->res_buflen + bodylen));
@ -1524,6 +1510,7 @@ SendResp_thumbnail(struct upnphttp * h, char * object)
if( access(path, F_OK) != 0 )
{
DPRINTF(E_ERROR, L_HTTP, "Error accessing %s\n", path);
Send404(h);
sqlite3_free(path);
return;
}