From 92c27bbda9e809683537e5cc48adad0d5c390587 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Fri, 6 Nov 2026 18:27:44 +0100 Subject: Gives urlencoded_parse a destination bound --- src/ot_http.c | 34 ++++++++++++++++++---------------- src/ot_urlencoded.c | 12 ++++++++---- src/ot_urlencoded.h | 4 ++-- 3 files changed, 28 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/ot_http.c b/src/ot_http.c index 29f41a3..fc49333 100644 --- a/src/ot_http.c +++ b/src/ot_http.c @@ -313,7 +313,7 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c #endif while (scanon) { - switch (urlencoded_match_keyword(keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM)) { + switch (urlencoded_match_keyword(keywords_main, &read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_PARAM)) { case -2: scanon = 0; break; /* TERMINATOR */ @@ -323,11 +323,11 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c urlencoded_skip_value(&read_ptr); break; case 1: /* matched "mode" */ - if ((mode = urlencoded_match_keyword(keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0) + if ((mode = urlencoded_match_keyword(keywords_mode, &read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_VALUE)) <= 0) HTTPERROR_400_PARAM; break; case 2: /* matched "format" */ - if ((format = urlencoded_match_keyword(keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0) + if ((format = urlencoded_match_keyword(keywords_format, &read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_VALUE)) <= 0) HTTPERROR_400_PARAM; break; case 3: @@ -505,7 +505,7 @@ static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws, } while (scanon) { - switch (urlencoded_match_keyword(keywords_scrape, &read_ptr, SCAN_SEARCHPATH_PARAM)) { + switch (urlencoded_match_keyword(keywords_scrape, &read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_PARAM)) { case -2: scanon = 0; break; /* TERMINATOR */ @@ -515,10 +515,12 @@ static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws, urlencoded_skip_value(&read_ptr); break; case 1: /* matched "info_hash" */ + { /* ignore this, when we have less than 20 bytes */ - if (urlencoded_parse(&read_ptr, (char *)(multiscrape_buf + numwant++), SCAN_SEARCHPATH_VALUE) != (ssize_t)sizeof(ot_hash)) + ot_hash *slot = multiscrape_buf + numwant++; + if (urlencoded_parse(&read_ptr, (char *)slot, (char *)(slot + 1), SCAN_SEARCHPATH_VALUE) != (ssize_t)sizeof(ot_hash)) HTTPERROR_400_PARAM; - break; + } break; } } @@ -622,7 +624,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct scanon = 1; while (scanon) { - switch (urlencoded_match_keyword(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM)) { + switch (urlencoded_match_keyword(keywords_announce, &read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_PARAM)) { case -2: scanon = 0; break; /* TERMINATOR */ @@ -632,14 +634,14 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct urlencoded_skip_value(&read_ptr); break; case 1: /* matched "port" */ - len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); + len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_VALUE); if ((len <= 0) || scan_int(write_ptr, len, &tmp) || (tmp > 0xffff)) HTTPERROR_400_PARAM; port = htons((uint16_t)tmp); OT_SETPORT(&ws->peer, &port); break; case 2: /* matched "left" */ - if ((len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0) + if ((len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_VALUE)) <= 0) HTTPERROR_400_PARAM; if (scan_int(write_ptr, len, &tmp)) tmp = 0; @@ -647,7 +649,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct OT_PEERFLAG(&ws->peer) |= PEER_FLAG_SEEDING; break; case 3: /* matched "event" */ - switch (urlencoded_match_keyword(keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE)) { + switch (urlencoded_match_keyword(keywords_announce_event, &read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_VALUE)) { case -1: HTTPERROR_400_PARAM; case 1: /* matched "completed" */ @@ -661,7 +663,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct } break; case 4: /* matched "numwant" */ - len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); + len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_VALUE); if ((len <= 0) || scan_int(write_ptr, len, &tmp)) HTTPERROR_400_PARAM; if (tmp < 0) @@ -671,7 +673,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct numwant = (size_t)tmp; break; case 5: /* matched "compact" */ - len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); + len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_VALUE); if ((len <= 0) || scan_int(write_ptr, len, &tmp)) HTTPERROR_400_PARAM; if (!tmp) @@ -681,7 +683,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct if (ws->hash) HTTPERROR_400_DOUBLEHASH; /* ignore this, when we have less than 20 bytes */ - if (urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20) + if (urlencoded_parse(&read_ptr, write_ptr = read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_VALUE) != 20) HTTPERROR_400_PARAM; ws->hash = (ot_hash *)write_ptr; break; @@ -689,7 +691,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct case 7: /* matched "ip" */ { char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16; - len = urlencoded_parse(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE); + len = urlencoded_parse(&read_ptr, tmp_buf2, ws->outbuf + G_OUTBUF_SIZE, SCAN_SEARCHPATH_VALUE); tmp_buf2[len] = 0; if ((len <= 0) || ip_parse(tmp_buf2, tmp_buf1) != (size_t)len) HTTPERROR_400_PARAM; @@ -698,7 +700,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct #endif case 8: /* matched "peer_id" */ /* ignore this, when we have less than 20 bytes */ - if (urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20) + if (urlencoded_parse(&read_ptr, write_ptr = read_ptr, ws->request + ws->request_size, SCAN_SEARCHPATH_VALUE) != 20) HTTPERROR_400_PARAM; ws->peer_id = write_ptr; break; @@ -772,7 +774,7 @@ ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) { In reality we abandoned requiring the url to be correct. This now only decodes url encoded characters, we check for announces and scrapes by looking for "a*" or "sc" */ - len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_PATH); + len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, ws->request + ws->request_size, SCAN_PATH); /* If parsing returned an error, leave with not found */ if (g_redirecturl && (len == -2)) diff --git a/src/ot_urlencoded.c b/src/ot_urlencoded.c index 4109bb5..c977adb 100644 --- a/src/ot_urlencoded.c +++ b/src/ot_urlencoded.c @@ -68,17 +68,18 @@ void urlencoded_skip_value(char **string) { *string = (char *)s; } -int urlencoded_match_keyword(const ot_keywords *keywords, char **string, SCAN_SEARCHPATH_FLAG flags) { +int urlencoded_match_keyword(const ot_keywords *keywords, char **string, const char *deststring_end, SCAN_SEARCHPATH_FLAG flags) { char *deststring = *string; - ssize_t match_length = urlencoded_parse(string, deststring, flags); + ssize_t match_length = urlencoded_parse(string, deststring, deststring_end, flags); if (match_length < 0) return match_length; if (match_length == 0) return -3; + /* Compare on the exact decoded length. */ while (keywords->key) { - if (!strncmp(keywords->key, deststring, match_length) && !keywords->key[match_length]) + if ((size_t)match_length == strlen(keywords->key) && !memcmp(keywords->key, deststring, (size_t)match_length)) return keywords->value; keywords++; } @@ -86,7 +87,7 @@ int urlencoded_match_keyword(const ot_keywords *keywords, char **string, SCAN_SE return -3; } -ssize_t urlencoded_parse(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags) { +ssize_t urlencoded_parse(char **string, char *deststring, const char *deststring_end, SCAN_SEARCHPATH_FLAG flags) { const unsigned char *s = *(const unsigned char **)string; unsigned char *d = (unsigned char *)deststring; unsigned char b, c; @@ -106,6 +107,9 @@ ssize_t urlencoded_parse(char **string, char *deststring, SCAN_SEARCHPATH_FLAG f c |= (b << 4); } + if ((const char *)d >= deststring_end) + return -1; + /* Write (possibly decoded) character to output */ *d++ = c; } diff --git a/src/ot_urlencoded.h b/src/ot_urlencoded.h index 9882468..053e079 100644 --- a/src/ot_urlencoded.h +++ b/src/ot_urlencoded.h @@ -28,7 +28,7 @@ typedef enum { or -1 for parse error or -2 for terminator found */ -ssize_t urlencoded_parse(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags); +ssize_t urlencoded_parse(char **string, char *deststring, const char *deststring_end, SCAN_SEARCHPATH_FLAG flags); /* string in: pointer to source out: pointer to next scan position @@ -38,7 +38,7 @@ ssize_t urlencoded_parse(char **string, char *deststring, SCAN_SEARCHPATH_FLAG f or -2 for terminator found or -3 for no keyword matched */ -int urlencoded_match_keyword(const ot_keywords *keywords, char **string, SCAN_SEARCHPATH_FLAG flags); +int urlencoded_match_keyword(const ot_keywords *keywords, char **string, const char *deststring_end, SCAN_SEARCHPATH_FLAG flags); /* string in: pointer to value of a param=value pair to skip out: pointer to next scan position on return -- cgit v1.3