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 @@ ...@@ -28,10 +28,19 @@
#include <stdint.h> #include <stdint.h>
struct sockaddr; struct sockaddr;
struct sockaddr_un;
namespace kj { namespace kj {
namespace _ { // private 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 { class CidrRange {
public: public:
CidrRange(StringPtr pattern); CidrRange(StringPtr pattern);
...@@ -64,10 +73,8 @@ public: ...@@ -64,10 +73,8 @@ public:
NetworkFilter(ArrayPtr<const StringPtr> allow, ArrayPtr<const StringPtr> deny, NetworkFilter(ArrayPtr<const StringPtr> allow, ArrayPtr<const StringPtr> deny,
NetworkFilter& next); 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 shouldAllow(const struct sockaddr* addr, uint addrlen) override;
bool shouldAllowParse(const struct sockaddr* addr, uint addrlen);
private: private:
Vector<CidrRange> allowCidrs; Vector<CidrRange> allowCidrs;
......
...@@ -475,20 +475,20 @@ KJ_TEST("CIDR parsing") { ...@@ -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; struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
inet_pton(AF_INET, addrStr.cStr(), &addr.sin_addr); 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; struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6; addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, addrStr.cStr(), &addr.sin6_addr); 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") { KJ_TEST("NetworkFilter") {
......
...@@ -450,10 +450,11 @@ public: ...@@ -450,10 +450,11 @@ public:
return str('[', buffer, "]:", ntohs(addr.inet6.sin6_port)); return str('[', buffer, "]:", ntohs(addr.inet6.sin6_port));
} }
case AF_UNIX: { case AF_UNIX: {
if (addr.unixDomain.sun_path[0] == '\0') { auto path = _::safeUnixPath(&addr.unixDomain, addrlen);
return str("unix-abstract:", addr.unixDomain.sun_path + 1); if (path.size() > 0 && path[0] == '\0') {
return str("unix-abstract:", path.slice(1, path.size()));
} else { } else {
return str("unix:", addr.unixDomain.sun_path); return str("unix:", path);
} }
} }
default: default:
...@@ -641,8 +642,8 @@ public: ...@@ -641,8 +642,8 @@ public:
return filter.shouldAllow(&addr.generic, addrlen); return filter.shouldAllow(&addr.generic, addrlen);
} }
bool parseAllowedBy(const _::NetworkFilter& filter) { bool parseAllowedBy(_::NetworkFilter& filter) {
return filter.shouldAllowParse(&addr.generic); return filter.shouldAllowParse(&addr.generic, addrlen);
} }
private: private:
......
...@@ -654,7 +654,7 @@ public: ...@@ -654,7 +654,7 @@ public:
} }
bool parseAllowedBy(const _::NetworkFilter& filter) { bool parseAllowedBy(const _::NetworkFilter& filter) {
return filter.shouldAllowParse(&addr.generic); return filter.shouldAllowParse(&addr.generic, addrlen);
} }
static SocketAddress getWildcardForFamily(int family) { static SocketAddress getWildcardForFamily(int family) {
......
...@@ -217,6 +217,26 @@ Own<DatagramPort> LowLevelAsyncIoProvider::wrapDatagramSocketFd( ...@@ -217,6 +217,26 @@ Own<DatagramPort> LowLevelAsyncIoProvider::wrapDatagramSocketFd(
namespace _ { // private 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) { CidrRange::CidrRange(StringPtr pattern) {
size_t slashPos = KJ_REQUIRE_NONNULL(pattern.findFirst('/'), "invalid CIDR", 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 ...@@ -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 !_WIN32
if (addr->sa_family == AF_UNIX) { 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; return allowAbstractUnix;
} else { } else {
return allowUnix; return allowUnix;
...@@ -492,17 +515,18 @@ bool NetworkFilter::shouldAllow(const struct sockaddr* addr) const { ...@@ -492,17 +515,18 @@ bool NetworkFilter::shouldAllow(const struct sockaddr* addr) const {
} }
KJ_IF_MAYBE(n, next) { KJ_IF_MAYBE(n, next) {
return n->shouldAllow(addr); return n->shouldAllow(addr, addrlen);
} else { } else {
return true; return true;
} }
} }
bool NetworkFilter::shouldAllowParse(const struct sockaddr* addr) const { bool NetworkFilter::shouldAllowParse(const struct sockaddr* addr, uint addrlen) {
bool matched = false; bool matched = false;
#if !_WIN32 #if !_WIN32
if (addr->sa_family == AF_UNIX) { 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; if (allowAbstractUnix) matched = true;
} else { } else {
if (allowUnix) matched = true; if (allowUnix) matched = true;
...@@ -520,7 +544,7 @@ bool NetworkFilter::shouldAllowParse(const struct sockaddr* addr) const { ...@@ -520,7 +544,7 @@ bool NetworkFilter::shouldAllowParse(const struct sockaddr* addr) const {
if (matched) { if (matched) {
KJ_IF_MAYBE(n, next) { KJ_IF_MAYBE(n, next) {
return n->shouldAllowParse(addr); return n->shouldAllowParse(addr, addrlen);
} else { } else {
return true; return true;
} }
...@@ -530,27 +554,5 @@ bool NetworkFilter::shouldAllowParse(const struct sockaddr* addr) const { ...@@ -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 _ (private)
} // namespace kj } // 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