Commit 9137a15f authored by Kenton Varda's avatar Kenton Varda

Apparently unix addresses are not required to have a NUL terminator. Handle this.

parent d601b842
......@@ -28,10 +28,19 @@
#include <stdint.h>
struct sockaddr;
struct sockaddr_un;
namespace kj {
namespace _ { // private
// =======================================================================================
#if !_WIN32
kj::ArrayPtr<const char> safeUnixPath(const struct sockaddr_un* addr, uint addrlen);
// sockaddr_un::sun_path is not required to have a NUL terminator! Thus to be safe unix address
// paths MUST be read using this function.
#endif
class CidrRange {
public:
CidrRange(StringPtr pattern);
......@@ -64,10 +73,8 @@ public:
NetworkFilter(ArrayPtr<const StringPtr> allow, ArrayPtr<const StringPtr> deny,
NetworkFilter& next);
bool shouldAllow(const struct sockaddr* addr) const;
bool shouldAllowParse(const struct sockaddr* addr) const;
bool shouldAllow(const struct sockaddr* addr, uint addrlen) override;
bool shouldAllowParse(const struct sockaddr* addr, uint addrlen);
private:
Vector<CidrRange> allowCidrs;
......
......@@ -475,20 +475,20 @@ KJ_TEST("CIDR parsing") {
}
}
bool allowed4(const _::NetworkFilter& filter, StringPtr addrStr) {
bool allowed4(_::NetworkFilter& filter, StringPtr addrStr) {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
inet_pton(AF_INET, addrStr.cStr(), &addr.sin_addr);
return filter.shouldAllow(reinterpret_cast<struct sockaddr*>(&addr));
return filter.shouldAllow(reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
}
bool allowed6(const _::NetworkFilter& filter, StringPtr addrStr) {
bool allowed6(_::NetworkFilter& filter, StringPtr addrStr) {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, addrStr.cStr(), &addr.sin6_addr);
return filter.shouldAllow(reinterpret_cast<struct sockaddr*>(&addr));
return filter.shouldAllow(reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
}
KJ_TEST("NetworkFilter") {
......
......@@ -450,10 +450,11 @@ public:
return str('[', buffer, "]:", ntohs(addr.inet6.sin6_port));
}
case AF_UNIX: {
if (addr.unixDomain.sun_path[0] == '\0') {
return str("unix-abstract:", addr.unixDomain.sun_path + 1);
auto path = _::safeUnixPath(&addr.unixDomain, addrlen);
if (path.size() > 0 && path[0] == '\0') {
return str("unix-abstract:", path.slice(1, path.size()));
} else {
return str("unix:", addr.unixDomain.sun_path);
return str("unix:", path);
}
}
default:
......@@ -641,8 +642,8 @@ public:
return filter.shouldAllow(&addr.generic, addrlen);
}
bool parseAllowedBy(const _::NetworkFilter& filter) {
return filter.shouldAllowParse(&addr.generic);
bool parseAllowedBy(_::NetworkFilter& filter) {
return filter.shouldAllowParse(&addr.generic, addrlen);
}
private:
......
......@@ -654,7 +654,7 @@ public:
}
bool parseAllowedBy(const _::NetworkFilter& filter) {
return filter.shouldAllowParse(&addr.generic);
return filter.shouldAllowParse(&addr.generic, addrlen);
}
static SocketAddress getWildcardForFamily(int family) {
......
......@@ -217,6 +217,26 @@ Own<DatagramPort> LowLevelAsyncIoProvider::wrapDatagramSocketFd(
namespace _ { // private
#if !_WIN32
kj::ArrayPtr<const char> safeUnixPath(const struct sockaddr_un* addr, uint addrlen) {
KJ_REQUIRE(addr->sun_family == AF_UNIX, "not a unix address");
KJ_REQUIRE(addrlen >= offsetof(sockaddr_un, sun_path), "invalid unix address");
size_t maxPathlen = addrlen - offsetof(sockaddr_un, sun_path);
size_t pathlen;
if (maxPathlen > 0 && addr->sun_path[0] == '\0') {
// Linux "abstract" unix address
pathlen = strnlen(addr->sun_path + 1, maxPathlen - 1) + 1;
} else {
pathlen = strnlen(addr->sun_path, maxPathlen);
}
return kj::arrayPtr(addr->sun_path, pathlen);
}
#endif // !_WIN32
CidrRange::CidrRange(StringPtr pattern) {
size_t slashPos = KJ_REQUIRE_NONNULL(pattern.findFirst('/'), "invalid CIDR", pattern);
......@@ -465,10 +485,13 @@ NetworkFilter::NetworkFilter(ArrayPtr<const StringPtr> allow, ArrayPtr<const Str
}
}
bool NetworkFilter::shouldAllow(const struct sockaddr* addr) const {
bool NetworkFilter::shouldAllow(const struct sockaddr* addr, uint addrlen) {
KJ_REQUIRE(addrlen > sizeof(addr->sa_family));
#if !_WIN32
if (addr->sa_family == AF_UNIX) {
if (reinterpret_cast<const struct sockaddr_un*>(addr)->sun_path[0] == '\0') {
auto path = safeUnixPath(reinterpret_cast<const struct sockaddr_un*>(addr), addrlen);
if (path.size() > 0 && path[0] == '\0') {
return allowAbstractUnix;
} else {
return allowUnix;
......@@ -492,17 +515,18 @@ bool NetworkFilter::shouldAllow(const struct sockaddr* addr) const {
}
KJ_IF_MAYBE(n, next) {
return n->shouldAllow(addr);
return n->shouldAllow(addr, addrlen);
} else {
return true;
}
}
bool NetworkFilter::shouldAllowParse(const struct sockaddr* addr) const {
bool NetworkFilter::shouldAllowParse(const struct sockaddr* addr, uint addrlen) {
bool matched = false;
#if !_WIN32
if (addr->sa_family == AF_UNIX) {
if (reinterpret_cast<const struct sockaddr_un*>(addr)->sun_path[0] == '\0') {
auto path = safeUnixPath(reinterpret_cast<const struct sockaddr_un*>(addr), addrlen);
if (path.size() > 0 && path[0] == '\0') {
if (allowAbstractUnix) matched = true;
} else {
if (allowUnix) matched = true;
......@@ -520,7 +544,7 @@ bool NetworkFilter::shouldAllowParse(const struct sockaddr* addr) const {
if (matched) {
KJ_IF_MAYBE(n, next) {
return n->shouldAllowParse(addr);
return n->shouldAllowParse(addr, addrlen);
} else {
return true;
}
......@@ -530,27 +554,5 @@ bool NetworkFilter::shouldAllowParse(const struct sockaddr* addr) const {
}
}
bool NetworkFilter::shouldAllow(const struct sockaddr* addr, uint addrlen) {
switch (addr->sa_family) {
case AF_INET:
KJ_REQUIRE(addrlen >= sizeof(struct sockaddr_in));
break;
case AF_INET6:
KJ_REQUIRE(addrlen >= sizeof(struct sockaddr_in6));
break;
#if !_WIN32
case AF_UNIX: {
auto un = reinterpret_cast<const struct sockaddr_un*>(addr);
static const size_t PATH_OFFSET = offsetof(struct sockaddr_un, sun_path);
KJ_REQUIRE(addrlen >= PATH_OFFSET &&
memchr(un->sun_path, 0, addrlen - PATH_OFFSET) != nullptr);
break;
}
#endif
}
return shouldAllow(addr);
}
} // namespace _ (private)
} // namespace kj
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment