git: 9401bfb06108 - stable/14 - hastd: Use fixed-length protocol names

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Sun, 20 Sep 2026 17:07:56 UTC
The branch stable/14 has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=9401bfb06108e49cc125a237469886da34bb4f38

commit 9401bfb06108e49cc125a237469886da34bb4f38
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-09-08 20:55:15 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-09-20 16:51:17 +0000

    hastd: Use fixed-length protocol names
    
    All communication between hastd nodes and internally between hastd and
    its worker children passes through the same pair of send / receive
    functions.  The receive function uses recv(2) with the MSG_WAITALL flag,
    which in theory means we should never get a short read.  However, when
    handing off a socket to a worker child, we also pass a variable-length
    string identifying the type of socket we're passing, and reading this
    string relies on a short read.  This used to work because the arrival of
    the descriptor would interrupt the recv(2) call, but this bug was fixed
    when the AF_UNIX code was rewritten a while ago and hastd has been
    broken ever since.
    
    Fixing the length of the protocol name to four characters including the
    terminating null solves the short-read bug by never requiring a short
    read (nothing else in hastd requires one).
    
    Note that this issue appears to have been reported independently first
    by Alessandro Sagratini in PR 292322 and then by Martin Vidovic in
    D57511.  I ended up going in a different direction than Martin's patch,
    but his analysis was invaluable, hence the double credit below.
    
    PR:             292322
    Reported by:    Martin Vidovic <xtronom@gmail.com>
    MFC after:      1 week
    Event:          EuroBSDcon DevSummit 2026
    Reviewed by:    xtronom_gmail.com, kevans, glebius, gjb
    Differential Revision:  https://reviews.freebsd.org/D59521
    
    (cherry picked from commit b7e5c2e008f5b441611830ad3a0329de0882419e)
---
 sbin/hastd/proto.c            | 15 +++++----------
 sbin/hastd/proto_impl.h       |  2 +-
 sbin/hastd/proto_socketpair.c |  2 +-
 3 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/sbin/hastd/proto.c b/sbin/hastd/proto.c
index 35f73bb8d0bf..a7548ae2709d 100644
--- a/sbin/hastd/proto.c
+++ b/sbin/hastd/proto.c
@@ -282,7 +282,6 @@ proto_recv(const struct proto_conn *conn, void *data, size_t size)
 int
 proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
 {
-	const char *protoname;
 	int ret, fd;
 
 	PJDLOG_ASSERT(conn != NULL);
@@ -294,11 +293,9 @@ proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
 	PJDLOG_ASSERT(mconn->pc_proto != NULL);
 	fd = proto_descriptor(mconn);
 	PJDLOG_ASSERT(fd >= 0);
-	protoname = mconn->pc_proto->prt_name;
-	PJDLOG_ASSERT(protoname != NULL);
 
 	ret = conn->pc_proto->prt_send(conn->pc_ctx,
-	    (const unsigned char *)protoname, strlen(protoname) + 1, fd);
+	    mconn->pc_proto->prt_name, sizeof(mconn->pc_proto->prt_name), fd);
 	proto_close(mconn);
 	if (ret != 0) {
 		errno = ret;
@@ -311,7 +308,7 @@ int
 proto_connection_recv(const struct proto_conn *conn, bool client,
     struct proto_conn **newconnp)
 {
-	char protoname[128];
+	char protoname[sizeof(conn->pc_proto->prt_name)];
 	struct proto *proto;
 	struct proto_conn *newconn;
 	int ret, fd;
@@ -322,10 +319,8 @@ proto_connection_recv(const struct proto_conn *conn, bool client,
 	PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
 	PJDLOG_ASSERT(newconnp != NULL);
 
-	bzero(protoname, sizeof(protoname));
-
-	ret = conn->pc_proto->prt_recv(conn->pc_ctx, (unsigned char *)protoname,
-	    sizeof(protoname) - 1, &fd);
+	ret = conn->pc_proto->prt_recv(conn->pc_ctx, protoname,
+	    sizeof(protoname), &fd);
 	if (ret != 0) {
 		errno = ret;
 		return (-1);
@@ -334,7 +329,7 @@ proto_connection_recv(const struct proto_conn *conn, bool client,
 	PJDLOG_ASSERT(fd >= 0);
 
 	TAILQ_FOREACH(proto, &protos, prt_next) {
-		if (strcmp(proto->prt_name, protoname) == 0)
+		if (memcmp(proto->prt_name, protoname, sizeof(protoname)) == 0)
 			break;
 	}
 	if (proto == NULL) {
diff --git a/sbin/hastd/proto_impl.h b/sbin/hastd/proto_impl.h
index 0a0074545f38..181a4cd4a17d 100644
--- a/sbin/hastd/proto_impl.h
+++ b/sbin/hastd/proto_impl.h
@@ -53,7 +53,7 @@ typedef void prt_remote_address_t(const void *, char *, size_t);
 typedef void prt_close_t(void *);
 
 struct proto {
-	const char		*prt_name;
+	char			prt_name[4];
 	prt_client_t		*prt_client;
 	prt_connect_t		*prt_connect;
 	prt_connect_wait_t	*prt_connect_wait;
diff --git a/sbin/hastd/proto_socketpair.c b/sbin/hastd/proto_socketpair.c
index 9608eb13afff..ac0a86aacdd9 100644
--- a/sbin/hastd/proto_socketpair.c
+++ b/sbin/hastd/proto_socketpair.c
@@ -220,7 +220,7 @@ sp_close(void *ctx)
 }
 
 static struct proto sp_proto = {
-	.prt_name = "socketpair",
+	.prt_name = "skp",
 	.prt_client = sp_client,
 	.prt_send = sp_send,
 	.prt_recv = sp_recv,