From: Florian Westphal Date: Wed, 13 Dec 2023 16:37:11 +0000 (+0100) Subject: meta: fix tc classid parsing out-of-bounds access X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=801a06aece44d4954df03bd0e61c3e2e9ee557e9;p=thirdparty%2Fnftables.git meta: fix tc classid parsing out-of-bounds access commit 7008b1200fb4988b7cd7ee1c5399cae071688d50 upstream. AddressSanitizer: heap-buffer-overflow on address 0x6020000003af ... #0 0x7f9a83cbb402 in tchandle_type_parse src/meta.c:89 #1 0x7f9a83c6753f in symbol_parse src/datatype.c:138 strlen() - 1 can underflow if length was 0. Simplify the function, there is no need to duplicate the string while scanning it. Expect the first strtol to stop at ':', scan for the minor number next. The second scan is required to stop at '\0'. Fixes: 6f2eb8548e0d ("src: meta priority support using tc classid") Signed-off-by: Florian Westphal --- diff --git a/src/meta.c b/src/meta.c index 71ed1033..aef08a4f 100644 --- a/src/meta.c +++ b/src/meta.c @@ -66,50 +66,39 @@ static struct error_record *tchandle_type_parse(struct parse_ctx *ctx, struct expr **res) { uint32_t handle; - char *str = NULL; if (strcmp(sym->identifier, "root") == 0) handle = TC_H_ROOT; else if (strcmp(sym->identifier, "none") == 0) handle = TC_H_UNSPEC; else if (strchr(sym->identifier, ':')) { + char *colon, *end; uint32_t tmp; - char *colon; - - str = xstrdup(sym->identifier); - - colon = strchr(str, ':'); - if (!colon) - goto err; - - *colon = '\0'; errno = 0; - tmp = strtoull(str, NULL, 16); - if (errno != 0) + tmp = strtoul(sym->identifier, &colon, 16); + if (errno != 0 || sym->identifier == colon) goto err; - handle = (tmp << 16); - if (str[strlen(str) - 1] == ':') - goto out; + if (*colon != ':') + goto err; + handle = tmp << 16; errno = 0; - tmp = strtoull(colon + 1, NULL, 16); - if (errno != 0) + tmp = strtoul(colon + 1, &end, 16); + if (errno != 0 || *end) goto err; handle |= tmp; } else { handle = strtoull(sym->identifier, NULL, 0); } -out: - xfree(str); + *res = constant_expr_alloc(&sym->location, sym->dtype, BYTEORDER_HOST_ENDIAN, sizeof(handle) * BITS_PER_BYTE, &handle); return NULL; err: - xfree(str); return error(&sym->location, "Could not parse %s", sym->dtype->desc); } diff --git a/tests/shell/testcases/bogons/nft-f/tchandle_type_parse_heap_overflow b/tests/shell/testcases/bogons/nft-f/tchandle_type_parse_heap_overflow new file mode 100644 index 00000000..ea7186bf --- /dev/null +++ b/tests/shell/testcases/bogons/nft-f/tchandle_type_parse_heap_overflow @@ -0,0 +1,6 @@ +table t { +map m { + type ipv4_addr : classid + elements = { 1.1.26.3 : ::a } +} +}