From 7afa284efccb06a857a1efbd387c865efd27fbed Mon Sep 17 00:00:00 2001 From: Stefan Meinecke Date: Sun, 18 Oct 2026 02:14:06 +0200 Subject: [PATCH] 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. --- common.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/common.c b/common.c index 2b5491c..28b52e9 100644 --- a/common.c +++ b/common.c @@ -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);