https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=298085

            Bug ID: 298085
           Summary: hastd/hastctl abort on a legitimate zero-size protocol
                    message (hast_proto_recv_hdr asserts non-NULL on an
                    empty ebuf)
           Product: Base System
           Version: 16.0-CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: bin
          Assignee: [email protected]
          Reporter: [email protected]

hastd and hastctl both link hast_proto.c's hast_proto_recv_hdr(), which asserts
that ebuf_data() returns a non-NULL pointer before receiving a message's
payload — but ebuf_data() legitimately returns NULL for a zero-size buffer, and
a zero-size payload (a bare protocol header with no attached nv data) is a
valid message on the wire. Any peer that sends one crashes the receiving
process with SIGABRT.

In practice this makes service hastd onerestart 100% reproducible crash, even
against a completely empty /etc/hast.conf: hastd's own stop_precmd (see
/etc/rc.d/hastd) runs hastctl role init all before stopping the daemon, and
that exchange includes a zero-size message — so hastctl (not hastd itself)
aborts every single time.

Environment:
- FreeBSD 16.0-CURRENT, main-n288684-420428718da7, amd64
- Reproduced independently on two separate physical/virtual machines running
the same CURRENT snapshot
- Not related to the connection-migration bug tracked in bug 292322 / reviewed
as D57511 (a different function, proto_common_recv's MSG_WAITALL sizing) — this
is a separate defect

Reproduction:
On a system with hastd_enable="YES" (an otherwise empty /etc/hast.conf is
sufficient — no resources need to be configured):

  # service hastd onerestart

Proposed fix: Only dereference/receive when there's actually a nonzero-size
payload to read — there is nothing to assert or receive when hdr.size == 0:

--- a/sbin/hastd/hast_proto.c
+++ b/sbin/hastd/hast_proto.c
@@ -149,10 +149,12 @@ hast_proto_recv_hdr(const struct proto_conn *conn, struct
nv **nvp)
        if (ebuf_add_tail(eb, NULL, hdr.size) == -1)
                goto fail;
-       hptr = ebuf_data(eb, NULL);
-       PJDLOG_ASSERT(hptr != NULL);
-       if (proto_recv(conn, hptr, hdr.size) == -1)
-               goto fail;
+       if (hdr.size > 0) {
+               hptr = ebuf_data(eb, NULL);
+               PJDLOG_ASSERT(hptr != NULL);
+               if (proto_recv(conn, hptr, hdr.size) == -1)
+                       goto fail;
+       }
        nv = nv_ntoh(eb);
        if (nv == NULL)
                goto fail;


This has been built and tested locally: hastd/hastctl rebuilt from a patched
tree, installed on two machines, and service hastd onerestart now succeeds
cleanly and repeatedly on both, including under a real, active hastd
configuration (not just an empty one).

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to