#56 handling unix paths with maximum length (no NUL term)

This commit is contained in:
fpagliughi
2023-01-18 20:11:25 -05:00
parent ba5b5352ba
commit 647ead0351
3 changed files with 61 additions and 23 deletions

View File

@@ -74,8 +74,8 @@ public:
/** The address family for this type of address */
static constexpr sa_family_t ADDRESS_FAMILY = AF_UNIX;
// TODO: This only applies to Linux
static constexpr size_t MAX_PATH_NAME = 108;
/** The max length of the file path */
static constexpr size_t MAX_PATH_NAME = sizeof(sockaddr_un::sun_path);
/**
* Constructs an empty address.
@@ -83,8 +83,8 @@ public:
*/
unix_address() : addr_() {}
/**
* Constructs an address for the specified path.
* @param path The
* Constructs an address given the specified path.
* @param path The path to the socket file.
*/
unix_address(const std::string& path);
/**
@@ -108,7 +108,7 @@ public:
* initialized as a UNIX-domain address (i.e. family is not
* AF_UNIX)
*/
unix_address(const sockaddr_un& addr) : addr_(addr) {}
unix_address(const sockaddr_un& addr);
/**
* Constructs the address by copying the specified address.
* @param addr The other address
@@ -125,7 +125,9 @@ public:
* Gets the path to which this address refers.
* @return The path to which this address refers.
*/
std::string path() const { return std::string(addr_.sun_path); }
std::string path() const {
return std::string(addr_.sun_path, strnlen(addr_.sun_path, MAX_PATH_NAME));
}
/**
* Gets the size of the address structure.
* Note: In this implementation, this should return sizeof(this) but
@@ -170,7 +172,7 @@ public:
* "unix:<path>"
*/
std::string to_string() const {
return std::string("unix:") + std::string(addr_.sun_path);
return std::string("unix:") + path();
}
};

View File

@@ -55,17 +55,20 @@ unix_address::unix_address(const string& path)
::strncpy(addr_.sun_path, path.c_str(), MAX_PATH_NAME);
}
unix_address::unix_address(const sockaddr& addr)
unix_address::unix_address(const sockaddr& addr) : addr_{}
{
auto domain = addr.sa_family;
if (domain != AF_UNIX)
if (addr.sa_family != ADDRESS_FAMILY)
throw std::invalid_argument("Not a UNIX-domain address");
// TODO: We should check the path, or at least see that it has
// proper NUL termination.
std::memcpy(&addr_, &addr, sizeof(sockaddr));
}
unix_address::unix_address(const sockaddr_un& addr) : addr_(addr)
{
if (addr.sun_family != ADDRESS_FAMILY)
throw std::invalid_argument("Not a UNIX-domain address");
}
// --------------------------------------------------------------------------
ostream& operator<<(ostream& os, const unix_address& addr)

View File

@@ -46,6 +46,15 @@ using namespace sockpp;
std::string PATH { "/tmp/sock" };
TEST_CASE("unix_address sizes", "[address]") {
#if defined(__linux__)
REQUIRE(108 == unix_address::MAX_PATH_NAME);
#endif
// On most systems, size should be 104, 108, or larger.
REQUIRE(unix_address::MAX_PATH_NAME > 64);
}
TEST_CASE("unix_address default constructor", "[address]") {
unix_address addr;
@@ -65,8 +74,9 @@ TEST_CASE("unix_address path constructor", "[address]") {
// Check the low-level struct
REQUIRE(AF_UNIX == addr.sockaddr_un_ptr()->sun_family);
REQUIRE(0 == strcmp(PATH.c_str(),
(const char*) &addr.sockaddr_un_ptr()->sun_path));
REQUIRE(0 == strncmp(PATH.c_str(),
(const char*) &addr.sockaddr_un_ptr()->sun_path,
unix_address::MAX_PATH_NAME));
SECTION("copy constructor") {
unix_address addr2(addr);
@@ -77,8 +87,9 @@ TEST_CASE("unix_address path constructor", "[address]") {
// Check the low-level struct
REQUIRE(AF_UNIX == addr2.sockaddr_un_ptr()->sun_family);
REQUIRE(0 == strcmp(PATH.c_str(),
(const char*) &addr2.sockaddr_un_ptr()->sun_path));
REQUIRE(0 == strncmp(PATH.c_str(),
(const char*) &addr2.sockaddr_un_ptr()->sun_path,
unix_address::MAX_PATH_NAME));
}
SECTION("sockaddr conversions") {
@@ -91,9 +102,33 @@ TEST_CASE("unix_address path constructor", "[address]") {
// Check the low-level struct
REQUIRE(AF_UNIX == addr2.sockaddr_un_ptr()->sun_family);
REQUIRE(0 == strcmp(PATH.c_str(),
(const char*) &(addr2.sockaddr_un_ptr()->sun_path)));
REQUIRE(0 == strncmp(PATH.c_str(),
(const char*) &addr2.sockaddr_un_ptr()->sun_path,
unix_address::MAX_PATH_NAME));
}
SECTION("full path") {
// Test what happens if 'sun_path' is full, with no NUL termination
std::string path;
sockaddr_un unaddr;
unaddr.sun_family = AF_UNIX;
for (size_t i=0; i<unix_address::MAX_PATH_NAME; ++i) {
char c = 'a' + (i % 26);
unaddr.sun_path[i] = c;
path.push_back(c);
}
// sockaddr_un constructor
unix_address addr(unaddr);
REQUIRE(unix_address::MAX_PATH_NAME == addr.path().size());
REQUIRE(path == addr.path());
// path (string) constructor
unix_address addr2(path);
REQUIRE(unix_address::MAX_PATH_NAME == addr2.path().size());
REQUIRE(path == addr2.path());
}
}
TEST_CASE("unix_address sockaddr_un constructor", "[address]") {
@@ -109,16 +144,14 @@ TEST_CASE("unix_address sockaddr_un constructor", "[address]") {
// Check the low-level struct
REQUIRE(AF_UNIX == addr.sockaddr_un_ptr()->sun_family);
REQUIRE(0 == strcmp(PATH.c_str(),
(const char*) &addr.sockaddr_un_ptr()->sun_path));
REQUIRE(0 == strncmp(PATH.c_str(),
(const char*) &addr.sockaddr_un_ptr()->sun_path,
unix_address::MAX_PATH_NAME));
// TODO: Restore this when all address checks in place
/*
SECTION("reject bad sockaddr_un") {
unaddr.sun_family = AF_INET;
REQUIRE_THROWS_AS([&] {
unix_address addr2(unaddr);
}(), std::invalid_argument);
}
*/
}