unix sockets: terminate sun_path, reject over-long paths early

Both start_listen_unix() and connect_unix() copied the configured
path into sun_path without checking its length and without zeroing
the sockaddr first. A path of 107+ bytes fills sun_path completely,
leaving it unterminated; bind()/connect() then read past the array
into uninitialised stack bytes (verified: garbage bytes visible in
the sockaddr passed to bind).

Fail listen startup with a clear message when the path cannot fit -
before unlink()ing whatever file currently sits at that path - and
make connect_unix() return -1 so the connection is dropped cleanly.
Zero both sockaddr structures, check the socket() return value in
connect_unix(), label unix listen endpoints AF_UNIX instead of
AF_INET, and route the "binding" message through print_message() so
it respects verbosity flags like everything else.
This commit is contained in:
Stefan Meinecke authored and Yves Rutschle committed 2026-10-18 22:04:22 +02:00
1 parent d51da940da
commit 7afa284efc
1 file changed
+23 -4
+23 -4
View File
@@ -203,6 +203,15 @@ static int start_listen_inet(struct listen_endpoint *sockfd[], int num_addr, str
/* Same, but for UNIX sockets */
static int start_listen_unix(struct listen_endpoint *sockfd[], int num_addr, struct sslhcfg_listen_item* cfg)
{
struct sockaddr_un sun;
/* Fail before unlink()ing an existing file we could not bind anyway */
if (strlen(cfg->host) >= sizeof(sun.sun_path)) {
print_message(msg_config_error, "unix socket path too long (%zd, max %zd): %s\n",
strlen(cfg->host), sizeof(sun.sun_path) - 1, cfg->host);
exit(4);
}
int fd = socket(AF_UNIX, cfg->is_udp ? SOCK_DGRAM : SOCK_STREAM, 0);
CHECK_RES_DIE(fd, "socket(AF_UNIX)");
@@ -212,10 +221,10 @@ static int start_listen_unix(struct listen_endpoint *sockfd[], int num_addr, str
exit(4);
}
struct sockaddr_un sun;
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
strncpy(sun.sun_path, cfg->host, sizeof(sun.sun_path)-1);
printf("binding [%s]\n", sun.sun_path);
print_message(msg_config, "binding [%s]\n", sun.sun_path);
res = bind(fd, (struct sockaddr*)&sun, sizeof(sun));
CHECK_RES_DIE(res, "bind(AF_UNIX)");
@@ -226,7 +235,7 @@ static int start_listen_unix(struct listen_endpoint *sockfd[], int num_addr, str
memset(&(*sockfd)[num_addr-1], 0, sizeof((*sockfd)[num_addr-1]));
(*sockfd)[num_addr-1].socketfd = fd;
(*sockfd)[num_addr-1].type = cfg->is_udp ? SOCK_DGRAM : SOCK_STREAM;
(*sockfd)[num_addr-1].family = AF_INET;
(*sockfd)[num_addr-1].family = AF_UNIX;
(*sockfd)[num_addr-1].endpoint_cfg = cfg;
return num_addr;
@@ -475,10 +484,20 @@ static int connect_unix(struct connection *cnx, int fd_from, connect_blocking bl
struct sockaddr_storage ss;
struct sockaddr_un* sun = (struct sockaddr_un*)&ss;
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (strlen(cnx->proto->host) >= sizeof(sun->sun_path)) {
print_message(msg_system_error, "unix socket path too long (%zd, max %zd): %s\n",
strlen(cnx->proto->host), sizeof(sun->sun_path) - 1,
cnx->proto->host);
return -1;
}
memset(&ss, 0, sizeof(ss));
sun->sun_family = AF_UNIX;
strncpy(sun->sun_path, cnx->proto->host, sizeof(sun->sun_path)-1);
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
CHECK_RES_RETURN(fd, "socket", -1);
int res = connect(fd, (struct sockaddr*)sun, sizeof(*sun));
CHECK_RES_RETURN(res, "connect", res);