mirror of
https://github.com/nodejs/http-parser.git
synced 2025-10-21 23:52:13 +08:00
src: fix out-of-bounds read through strtoul
`strtoul` will attempt to lookup the next digit up until it will stumble upon an invalid one. However, for an unterminated string as an input value, this results in out-of-bounds read. Remove `strtoul` call, and replace it with simple loop. Fix: #408 PR-URL: https://github.com/nodejs/http-parser/pull/409 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
@@ -22,7 +22,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
@@ -2367,12 +2366,27 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (u->field_set & (1 << UF_PORT)) {
|
if (u->field_set & (1 << UF_PORT)) {
|
||||||
/* Don't bother with endp; we've already validated the string */
|
uint16_t off;
|
||||||
unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
|
uint16_t len;
|
||||||
|
const char* p;
|
||||||
|
const char* end;
|
||||||
|
unsigned long v;
|
||||||
|
|
||||||
/* Ports have a max value of 2^16 */
|
off = u->field_data[UF_PORT].off;
|
||||||
if (v > 0xffff) {
|
len = u->field_data[UF_PORT].len;
|
||||||
return 1;
|
end = buf + off + len;
|
||||||
|
|
||||||
|
/* NOTE: The characters are already validated and are in the [0-9] range */
|
||||||
|
assert(off + len <= buflen && "Port number overflow");
|
||||||
|
v = 0;
|
||||||
|
for (p = buf + off; p < end; p++) {
|
||||||
|
v *= 10;
|
||||||
|
v += *p - '0';
|
||||||
|
|
||||||
|
/* Ports have a max value of 2^16 */
|
||||||
|
if (v > 0xffff) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u->port = (uint16_t) v;
|
u->port = (uint16_t) v;
|
||||||
|
25
test.c
25
test.c
@@ -3664,6 +3664,30 @@ test_header_cr_no_lf_error (int req)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_no_overflow_parse_url (void)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
struct http_parser_url u;
|
||||||
|
|
||||||
|
http_parser_url_init(&u);
|
||||||
|
rv = http_parser_parse_url("http://example.com:8001", 22, 0, &u);
|
||||||
|
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"\n*** test_no_overflow_parse_url invalid return value=%d\n",
|
||||||
|
rv);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u.port != 800) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"\n*** test_no_overflow_parse_url invalid port number=%d\n",
|
||||||
|
u.port);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
test_header_overflow_error (int req)
|
test_header_overflow_error (int req)
|
||||||
{
|
{
|
||||||
@@ -4099,6 +4123,7 @@ main (void)
|
|||||||
test_header_nread_value();
|
test_header_nread_value();
|
||||||
|
|
||||||
//// OVERFLOW CONDITIONS
|
//// OVERFLOW CONDITIONS
|
||||||
|
test_no_overflow_parse_url();
|
||||||
|
|
||||||
test_header_overflow_error(HTTP_REQUEST);
|
test_header_overflow_error(HTTP_REQUEST);
|
||||||
test_no_overflow_long_body(HTTP_REQUEST, 1000);
|
test_no_overflow_long_body(HTTP_REQUEST, 1000);
|
||||||
|
Reference in New Issue
Block a user