Skip to content

Commit

Permalink
Fix #2322 - stricter Content-Length check, allow 1*DIGIT only
Browse files Browse the repository at this point in the history
  • Loading branch information
cpq committed Aug 17, 2023
1 parent 88e3017 commit dce4e0c
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 36 deletions.
34 changes: 17 additions & 17 deletions mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -1245,16 +1245,20 @@ struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read,

bool mg_to_size_t(struct mg_str str, size_t *val);
bool mg_to_size_t(struct mg_str str, size_t *val) {
uint64_t result = 0, max = 1844674407370955160 /* (UINT64_MAX-9)/10 */;
size_t i = 0;
size_t i = 0, max = (size_t) -1, max2 = max / 10, result = 0, ndigits = 0;
while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
if (i < str.len && str.ptr[i] == '-') return false;
while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') {
if (result > max) return false;
size_t digit = (size_t) (str.ptr[i] - '0');
if (result > max2) return false; // Overflow
result *= 10;
result += (unsigned) (str.ptr[i] - '0');
i++;
if (result > max - digit) return false; // Overflow
result += digit;
i++, ndigits++;
}
while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
if (ndigits == 0) return false; // #2322: Content-Length = 1 * DIGIT
if (i != str.len) return false; // Ditto
*val = (size_t) result;
return true;
}
Expand Down Expand Up @@ -1746,20 +1750,16 @@ static struct mg_str guess_content_type(struct mg_str path, const char *extra) {

static int getrange(struct mg_str *s, size_t *a, size_t *b) {
size_t i, numparsed = 0;
// MG_INFO(("%.*s", (int) s->len, s->ptr));
for (i = 0; i + 6 < s->len; i++) {
if (memcmp(&s->ptr[i], "bytes=", 6) == 0) {
struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6);
if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
if (!mg_to_size_t(p, a)) return 0;
// MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
while (p.len && p.ptr[0] >= '0' && p.ptr[0] <= '9') p.ptr++, p.len--;
if (p.len && p.ptr[0] == '-') p.ptr++, p.len--;
if (!mg_to_size_t(p, b)) return 0;
if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
// MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
break;
struct mg_str k, v = mg_str_n(s->ptr + i + 6, s->len - i - 6);
if (memcmp(&s->ptr[i], "bytes=", 6) != 0) continue;
if (mg_split(&v, &k, NULL, '-')) {
if (mg_to_size_t(k, a)) numparsed++;
if (v.len > 0 && mg_to_size_t(v, b)) numparsed++;
} else {
if (mg_to_size_t(v, a)) numparsed++;
}
break;
}
return (int) numparsed;
}
Expand Down
34 changes: 17 additions & 17 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@

bool mg_to_size_t(struct mg_str str, size_t *val);
bool mg_to_size_t(struct mg_str str, size_t *val) {
uint64_t result = 0, max = 1844674407370955160 /* (UINT64_MAX-9)/10 */;
size_t i = 0;
size_t i = 0, max = (size_t) -1, max2 = max / 10, result = 0, ndigits = 0;
while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
if (i < str.len && str.ptr[i] == '-') return false;
while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') {
if (result > max) return false;
size_t digit = (size_t) (str.ptr[i] - '0');
if (result > max2) return false; // Overflow
result *= 10;
result += (unsigned) (str.ptr[i] - '0');
i++;
if (result > max - digit) return false; // Overflow
result += digit;
i++, ndigits++;
}
while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
if (ndigits == 0) return false; // #2322: Content-Length = 1 * DIGIT
if (i != str.len) return false; // Ditto
*val = (size_t) result;
return true;
}
Expand Down Expand Up @@ -514,20 +518,16 @@ static struct mg_str guess_content_type(struct mg_str path, const char *extra) {

static int getrange(struct mg_str *s, size_t *a, size_t *b) {
size_t i, numparsed = 0;
// MG_INFO(("%.*s", (int) s->len, s->ptr));
for (i = 0; i + 6 < s->len; i++) {
if (memcmp(&s->ptr[i], "bytes=", 6) == 0) {
struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6);
if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
if (!mg_to_size_t(p, a)) return 0;
// MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
while (p.len && p.ptr[0] >= '0' && p.ptr[0] <= '9') p.ptr++, p.len--;
if (p.len && p.ptr[0] == '-') p.ptr++, p.len--;
if (!mg_to_size_t(p, b)) return 0;
if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
// MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
break;
struct mg_str k, v = mg_str_n(s->ptr + i + 6, s->len - i - 6);
if (memcmp(&s->ptr[i], "bytes=", 6) != 0) continue;
if (mg_split(&v, &k, NULL, '-')) {
if (mg_to_size_t(k, a)) numparsed++;
if (v.len > 0 && mg_to_size_t(v, b)) numparsed++;
} else {
if (mg_to_size_t(v, a)) numparsed++;
}
break;
}
return (int) numparsed;
}
Expand Down
11 changes: 9 additions & 2 deletions test/unit_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,7 @@ static void test_http_range(void) {

fetch(&mgr, buf, url, "%s", "GET /range.txt HTTP/1.0\nRange: bytes=5-10\n\n");
ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
printf("%s", buf);
ASSERT(mg_strcmp(hm.uri, mg_str("206")) == 0);
ASSERT(mg_strcmp(hm.proto, mg_str("Partial Content")) == 0);
ASSERT(mg_strcmp(hm.body, mg_str(" of co")) == 0);
Expand Down Expand Up @@ -2184,16 +2185,22 @@ static void test_util(void) {

{
extern bool mg_to_size_t(struct mg_str, size_t *);
size_t val = 1;
size_t val, max = (size_t) -1;
ASSERT(mg_to_size_t(mg_str("0"), &val) && val == 0);
ASSERT(mg_to_size_t(mg_str("123"), &val) && val == 123);
ASSERT(mg_to_size_t(mg_str(""), &val) && val == 0);
ASSERT(mg_to_size_t(mg_str(" 123 \t"), &val) && val == 123);
ASSERT(mg_to_size_t(mg_str(""), &val) == false);
ASSERT(mg_to_size_t(mg_str(" 123x"), &val) == false);
ASSERT(mg_to_size_t(mg_str("-"), &val) == false);
mg_snprintf(buf, sizeof(buf), "%lu", max);
ASSERT(mg_to_size_t(mg_str(buf), &val) && val == max);
#if 0
ASSERT(mg_to_size_t(mg_str("18446744073709551616"), &val) ==
false); // range +1
ASSERT(mg_to_size_t(mg_str("18446744073709551610"), &val) == false);
// TODO(): ASSERT(mg_to_size_t(mg_str("18446744073709551609"), &val) &&
// val == 18446744073709551609U); // our max or SIZE_MAX
#endif
}

{
Expand Down

0 comments on commit dce4e0c

Please sign in to comment.