Skip to content

Commit bd851ac

Browse files
authored
Fix potential buffer overflow in http_load snprintf calls (#12723)
The snprintf function returns the number of characters that would have been written if the buffer was large enough, not the number actually written. This could cause hdr_bytes and req_bytes to increment beyond the buffer size, leading to out-of-bounds writes in subsequent snprintf calls. Fixed by: - Checking snprintf return value before incrementing offset - Only incrementing if return value is positive and less than remaining space - Applied to all snprintf calls that use += pattern in read_url_file() - Using braces for all conditional statements
1 parent bb34d9e commit bd851ac

File tree

1 file changed

+60
-19
lines changed

1 file changed

+60
-19
lines changed

tools/http_load/http_load.c

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* http_load - multiprocessing http test client
22
**
3-
** Copyright © 1998,1999,2001 by Jef Poskanzer <[email protected]>.
3+
** Copyright 1998,1999,2001 by Jef Poskanzer <[email protected]>.
44
** All rights reserved.
55
**
66
** Redistribution and use in source and binary forms, with or without
@@ -648,18 +648,43 @@ read_url_file(char *url_file)
648648
constructed by the URL host and possibly port (if not port 80) */
649649

650650
char hdr_buf[2048];
651-
int hdr_bytes = 0;
652-
hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "User-Agent: %s\r\n", user_agent);
653-
if (cookie)
654-
hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "Cookie: %s\r\n", cookie);
655-
if (do_accept_gzip)
656-
hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "Accept-Encoding: gzip\r\n");
651+
int hdr_bytes = 0;
652+
int n;
653+
654+
n = snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "User-Agent: %s\r\n", user_agent);
655+
if (n > 0 && (size_t)n < sizeof(hdr_buf) - hdr_bytes) {
656+
hdr_bytes += n;
657+
}
658+
659+
if (cookie) {
660+
n = snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "Cookie: %s\r\n", cookie);
661+
if (n > 0 && (size_t)n < sizeof(hdr_buf) - hdr_bytes) {
662+
hdr_bytes += n;
663+
}
664+
}
665+
666+
if (do_accept_gzip) {
667+
n = snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "Accept-Encoding: gzip\r\n");
668+
if (n > 0 && (size_t)n < sizeof(hdr_buf) - hdr_bytes) {
669+
hdr_bytes += n;
670+
}
671+
}
672+
657673
/* Add Connection: keep-alive header if keep_alive requested, and version != "1.1" */
658-
if ((keep_alive > 0) && !is_http_1_1)
659-
hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "Connection: keep-alive\r\n");
674+
if ((keep_alive > 0) && !is_http_1_1) {
675+
n = snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "Connection: keep-alive\r\n");
676+
if (n > 0 && (size_t)n < sizeof(hdr_buf) - hdr_bytes) {
677+
hdr_bytes += n;
678+
}
679+
}
680+
660681
if (extra_headers != NULL) {
661-
hdr_bytes += snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "%s\r\n", extra_headers);
682+
n = snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "%s\r\n", extra_headers);
683+
if (n > 0 && (size_t)n < sizeof(hdr_buf) - hdr_bytes) {
684+
hdr_bytes += n;
685+
}
662686
}
687+
663688
snprintf(&hdr_buf[hdr_bytes], sizeof(hdr_buf) - hdr_bytes, "\r\n");
664689

665690
while (fgets(line, sizeof(line), fp) != (char *)0) {
@@ -725,20 +750,36 @@ read_url_file(char *url_file)
725750
req_bytes = snprintf(req_buf, sizeof(req_buf), "GET %.500s HTTP/%s\r\n", urls[num_urls].filename, http_version);
726751

727752
if (extra_headers == NULL || !strstr(extra_headers, "Host:")) {
728-
if (urls[num_urls].port != 80)
729-
req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "Host: %s:%d\r\n", urls[num_urls].hostname,
730-
urls[num_urls].port);
731-
else
732-
req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "Host: %s\r\n", urls[num_urls].hostname);
753+
if (urls[num_urls].port != 80) {
754+
n = snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "Host: %s:%d\r\n", urls[num_urls].hostname,
755+
urls[num_urls].port);
756+
if (n > 0 && (size_t)n < sizeof(req_buf) - req_bytes) {
757+
req_bytes += n;
758+
}
759+
} else {
760+
n = snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "Host: %s\r\n", urls[num_urls].hostname);
761+
if (n > 0 && (size_t)n < sizeof(req_buf) - req_bytes) {
762+
req_bytes += n;
763+
}
764+
}
733765
}
734766
if (unique_id == 1) {
735-
req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "X-ID: ");
736-
urls[num_urls].unique_id_offset = req_bytes;
737-
req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "%09u\r\n", 0);
767+
n = snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "X-ID: ");
768+
if (n > 0 && (size_t)n < sizeof(req_buf) - req_bytes) {
769+
req_bytes += n;
770+
urls[num_urls].unique_id_offset = req_bytes;
771+
n = snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, "%09u\r\n", 0);
772+
if (n > 0 && (size_t)n < sizeof(req_buf) - req_bytes) {
773+
req_bytes += n;
774+
}
775+
}
738776
}
739777

740778
// add the common hdr here
741-
req_bytes += snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, hdr_buf, 0);
779+
n = snprintf(&req_buf[req_bytes], sizeof(req_buf) - req_bytes, hdr_buf, 0);
780+
if (n > 0 && (size_t)n < sizeof(req_buf) - req_bytes) {
781+
req_bytes += n;
782+
}
742783

743784
urls[num_urls].buf_bytes = req_bytes;
744785
urls[num_urls].buf = strdup_check(req_buf);

0 commit comments

Comments
 (0)