diff --git a/lib/libc/inet/inet_net_pton.c b/lib/libc/inet/inet_net_pton.c --- a/lib/libc/inet/inet_net_pton.c +++ b/lib/libc/inet/inet_net_pton.c @@ -211,15 +211,18 @@ static int inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) { - struct in6_addr in6; int ret; int bits; - size_t bytes; char buf[INET6_ADDRSTRLEN + sizeof("/128")]; char *sep; const char *errstr; - if (strlcpy(buf, src, sizeof buf) >= sizeof buf) { + if (size < sizeof(struct in6_addr)) { + errno = EMSGSIZE; + return (-1); + } + + if (strlcpy(buf, src, sizeof(buf)) >= sizeof(buf)) { errno = EMSGSIZE; return (-1); } @@ -228,7 +231,7 @@ if (sep != NULL) *sep++ = '\0'; - ret = inet_pton(AF_INET6, buf, &in6); + ret = inet_pton(AF_INET6, buf, dst); if (ret != 1) return (-1); @@ -242,12 +245,6 @@ } } - bytes = (bits + 7) / 8; - if (bytes > size) { - errno = EMSGSIZE; - return (-1); - } - memcpy(dst, &in6.s6_addr, bytes); return (bits); } diff --git a/lib/libc/tests/net/inet_net_test.cc b/lib/libc/tests/net/inet_net_test.cc --- a/lib/libc/tests/net/inet_net_test.cc +++ b/lib/libc/tests/net/inet_net_test.cc @@ -153,12 +153,11 @@ // A prefix with an infix ::. { "2001:db8::1/128", 128, "2001:db8::1/128" }, - // A prefix with bits set which are outside the prefix; - // these should be silently ignored. - { "2001:db8:1:1:1:1:1:1/32", 32, "2001:db8::/32" }, + // A prefix with bits set which are outside the prefix. + { "2001:db8:1:1:1:1:1:1/32", 32, "2001:db8:1:1:1:1:1:1/32" }, // As above but with infix ::. - { "2001:db8::1/32", 32, "2001:db8::/32" }, + { "2001:db8::1/32", 32, "2001:db8::1/32" }, // A prefix with only ::, commonly used to represent the // entire address space. @@ -182,11 +181,13 @@ { "2001:db8::1", 128, "2001:db8::1/128" }, // Test vectors provided in PR bin/289198. - { "fe80::1/64", 64, "fe80::/64" }, + { "fe80::1/64", 64, "fe80::1/64" }, { "fe80::f000:74ff:fe54:bed2/64", - 64, "fe80::/64" }, + 64, + "fe80::f000:74ff:fe54:bed2/64" }, { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64", - 64, "ffff:ffff:ffff:ffff::/64" }, + 64, + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64" }, { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" }, }; @@ -324,10 +325,48 @@ ATF_REQUIRE_EQ(ret, nullptr); } +ATF_TEST_CASE_WITHOUT_HEAD(inet_net_pton4_zero) +ATF_TEST_CASE_BODY(inet_net_pton4_zero) +{ + /* + * Ensure inet_net_pton() zeroes the address before returning it. + */ + auto addr = in_addr{}; + + std::memset(&addr, 0xFF, sizeof(addr)); + auto bits = inet_net_pton(AF_INET, "10/8", &addr, sizeof(addr)); + ATF_REQUIRE(bits == 8); + + auto buf = std::vector(INET_ADDRSTRLEN + 3 + 1); + auto p = inet_net_ntop(AF_INET, &addr, bits, buf.data(), buf.size()); + ATF_REQUIRE(p != nullptr); + ATF_REQUIRE_EQ("10/8"s, p); +} + +ATF_TEST_CASE_WITHOUT_HEAD(inet_net_pton6_zero) +ATF_TEST_CASE_BODY(inet_net_pton6_zero) +{ + /* + * Ensure inet_net_pton() zeroes the address before returning it. + */ + auto addr = in6_addr{}; + + std::memset(&addr, 0xFF, sizeof(addr)); + auto bits = inet_net_pton(AF_INET6, "2001:db8::/32", &addr, sizeof(addr)); + ATF_REQUIRE(bits == 32); + + auto buf = std::vector(INET6_ADDRSTRLEN + 4 + 1); + auto p = inet_net_ntop(AF_INET6, &addr, bits, buf.data(), buf.size()); + ATF_REQUIRE(p != nullptr); + ATF_REQUIRE_EQ("2001:db8::/32"s, p); +} + ATF_INIT_TEST_CASES(tcs) { ATF_ADD_TEST_CASE(tcs, inet_net_inet4); ATF_ADD_TEST_CASE(tcs, inet_net_inet6); + ATF_ADD_TEST_CASE(tcs, inet_net_pton4_zero); + ATF_ADD_TEST_CASE(tcs, inet_net_pton6_zero); ATF_ADD_TEST_CASE(tcs, inet_net_pton_invalid); ATF_ADD_TEST_CASE(tcs, inet_net_ntop_invalid); }