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.