`format_ipv6()` formats IPv6 addresses as hex-strings. However, sizing for the output buffer is not done quite right. `format_ipv6()` itself uses the size of `struct in6_addr` to verify that the buffer size is large enough, and the output buffer for the call in util/db.c is sized the same way. However, the size that should be used is that of the `s6_addr` member of `struct in6_addr`, not that of the whole structure. The elements of the `ipbin_array` array in ulogd_filter_IP2BIN.c are sized using a local macro, `IPADDR_LENGTH`, which is defined as 128, the number of bits in an IPv6 address; this is much larger than necessary. Define an appropriate macro and use that instead. Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx> --- filter/ulogd_filter_IP2BIN.c | 6 ++---- include/ulogd/ulogd.h | 13 +++++++++++-- util/db.c | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/filter/ulogd_filter_IP2BIN.c b/filter/ulogd_filter_IP2BIN.c index 7f7bea5071a7..f1ca4eee7d76 100644 --- a/filter/ulogd_filter_IP2BIN.c +++ b/filter/ulogd_filter_IP2BIN.c @@ -28,8 +28,6 @@ #include <ulogd/ulogd.h> #include <netinet/if_ether.h> -#define IPADDR_LENGTH 128 - enum input_keys { KEY_OOB_FAMILY, KEY_OOB_PROTOCOL, @@ -114,7 +112,7 @@ static struct ulogd_key ip2bin_keys[] = { }; -static char ipbin_array[MAX_KEY - START_KEY + 1][IPADDR_LENGTH]; +static char ipbin_array[MAX_KEY - START_KEY + 1][FORMAT_IPV6_BUFSZ]; static int ip2bin(struct ulogd_key *inp, int index, int oindex) { @@ -161,7 +159,7 @@ static int ip2bin(struct ulogd_key *inp, int index, int oindex) return ULOGD_IRET_ERR; } - format_ipv6(ipbin_array[oindex], IPADDR_LENGTH, addr); + format_ipv6(ipbin_array[oindex], sizeof(ipbin_array[oindex]), addr); return ULOGD_IRET_OK; } diff --git a/include/ulogd/ulogd.h b/include/ulogd/ulogd.h index 5eafb21f9cfe..5b6134d94ea3 100644 --- a/include/ulogd/ulogd.h +++ b/include/ulogd/ulogd.h @@ -23,6 +23,15 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +/* + * Minimum size of buffer required to hold an ipv6 address encoded as a + * hex-string, e.g.: + * + * ::1 -> "0x00000000000000000000000000000001" + * 2600:1408:ec00:36::1736:7f28 -> "0x26001408ec0000360000000017367f28" + */ +#define FORMAT_IPV6_BUFSZ (2 + sizeof(((struct in6_addr) {}).s6_addr) * 2 + 1) + /* All types with MSB = 1 make use of value.ptr * other types use one of the union's member */ @@ -233,11 +242,11 @@ format_ipv6(char *buf, size_t size, const struct in6_addr *ipv6) { unsigned i = 0; - if (size > 2 + sizeof (*ipv6) * 2) { + if (size >= FORMAT_IPV6_BUFSZ) { buf[i++] = '0'; buf[i++] = 'x'; - for (unsigned j = 0; i < sizeof(*ipv6); j += 4, i += 8) { + for (unsigned j = 0; i < sizeof(ipv6->s6_addr); j += 4, i += 8) { sprintf(buf + i, "%02hhx%02hhx%02hhx%02hhx", ipv6->s6_addr[j + 0], ipv6->s6_addr[j + 1], diff --git a/util/db.c b/util/db.c index 11c3e6ad8454..69f4290f5c87 100644 --- a/util/db.c +++ b/util/db.c @@ -370,7 +370,7 @@ static void __format_query_db(struct ulogd_pluginstance *upi, char *start) sprintf(stmt_ins, "%u,", res->u.value.ui32); else { struct in6_addr ipv6; - char addrbuf[2 + sizeof(ipv6) * 2 + 1]; + char addrbuf[FORMAT_IPV6_BUFSZ]; memcpy(ipv6.s6_addr, res->u.value.ui128, sizeof(ipv6.s6_addr)); -- 2.47.2