fix: CountNameList undercounts leading-comma name-lists - #1123
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes an off-by-one allocation sizing bug in CountNameList() that could reject valid (but odd) SSH name-lists with a leading comma (empty first token), which in turn could cause DoExtInfoServerSigAlgs() to fail when parsing server-sig-algs.
Changes:
- Stop discounting a leading comma in
CountNameList()so its computed capacity matches whatGetNameListRaw()can emit. - Preserve the existing behavior of discounting a trailing comma, consistent with
GetNameListRaw()stripping only trailing commas.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Thanks — the undercount is real and the reproduction is right. ,ssh-rsa counts 1 but parses to 2 names, and GetNameListRaw() returns WS_BUFFER_E on a list a peer can legitimately put on the wire. We went a different direction with the fix, so I'm going to close this rather than merge it. Dropping the leading-comma discount makes CountNameList() agree with GetNameListRaw() for ,ssh-rsa, but the trailing-comma discount stays, and the two still disagree elsewhere. A server-sig-algs value of exactly "," counts as 1 (two commas' worth, minus the trailing discount), allocates, and then fills 0 — GetNameListRaw() strips the trailing comma and has nothing left to parse. MatchIdLists() falls through its leftSz > 0 guard, returns ID_UNKNOWN, and DoExtInfoServerSigAlgs() sets WS_MATCH_UA_KEY_ID_E. On master that input is ignored as an empty extension. So the patch fixes one spurious rejection and introduces another. The deeper issue is that CountNameList() exists only to predict GetNameListRaw()'s output size. Any fix that keeps both functions has to keep them in lockstep forever, which is the situation that produced this bug. |
Bug
CountNameList()(src/internal.c) sizes the allocation thatGetNameListRaw()then fills. It discounts both a leading and a trailing comma, but
GetNameListRaw()only strips a trailing comma — it still emits the emptyleading token (the
idListIdx == 0first-token case). For a name-list with aleading comma such as
,ssh-rsa,CountNameList()returns 1 whileGetNameListRaw()needs 2 slots, so the fill hits the capacity guard andreturns
WS_BUFFER_E.The visible effect is in
DoExtInfoServerSigAlgs(), which sizes theserver-sig-algsbuffer fromCountNameList(): a peer advertising aleading-comma / empty-first-element name-list is spuriously rejected and the
connection fails. No memory-safety impact — the capacity guard fails closed.
Fix
Drop the leading-comma discount in
CountNameList().GetNameListRaw()keepsthat first token, so the count must include it. Over-counting an empty leading
element is harmless:
GetNameListRaw()caps writes at the capacity and rewritesthe caller's size to the actual filled count.
Verification
Built
--enable-allagainst wolfSSL master; compiles clean. Traced,ssh-rsa,ssh-rsa,ssh-dss(normal, unaffected), and,,ssh-rsa(harmless over-alloc)by hand against
GetNameListRaw.Reported by static analysis (Fenrir finding F-6817). Distinct from the
trailing-comma name-list issue tracked separately.