Conversation
base64toip() parses the P10 base64 IP field of a server NICK
introduction with no length validation. In the non-IPv4 path the '_'
compression marker computes the fill count as
(25 - strlen(input)) / 3 - pos
where 25 is an int and strlen() is size_t, so the subtraction is
unsigned. For any remainder longer than 25 characters it wraps to a
value near 2^64, truncates into the 32-bit loop counter, and the loop
zeroes ~1.4 billion words upward from the 16-byte irc_in_addr,
overrunning the stack local in ms_nick() or the heap Client in
set_nick_name() and crashing the server. The counter never lands in a
small range, so the write count is not attacker-controlled: this is a
remote denial of service with collateral corruption, reachable from any
established server link.
A second defect in the same function reads three bytes per group with
no end-of-string check, so a short field (e.g. "AB") runs past the NUL
and assembles adjacent read-buffer bytes into the stored IP, an
information leak surfaced through oper WHOIS/USERIP/WHO %i and G-line
matching.
Fix both by validating the input shape:
- cap the encoding at 24 characters, which makes the underflow
unreachable;
- compute the '_' compression by assigning pos = 8 - words rather than
running a loop whose bound can wrap, rejecting a non-whole or
overflowing word count;
- require three readable characters before decoding each group.
Malformed input now yields the all-zero address instead of running off
the end, matching the function's existing silent contract.
Add regression coverage to ircd_in_addr_t: an overlong '_' field (with
and without leading groups), a two-character field guarded against
adjacent-buffer leakage, a full round-trip of every iptobase64() form,
and the maximal 24-character encoding. The first three abort or crash on
the pre-fix function and pass after. A trailing canary region around the
destination catches any bounded overrun in addition to the crash.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
base64toip()(ircd/numnicks.c) parses the P10 base64 IP field of aserver
NICKintroduction with no length validation. Two defects in thenon-IPv4 path are memory-safety bugs reachable from any established
server-to-server link.
1. Unsigned underflow → multi-gigabyte out-of-bounds write (CWE-191 → CWE-787)
The
_compression marker computes its fill count as:25isint,strlen()issize_t, so the subtraction is unsigned.For any remainder longer than 25 characters it wraps to a value near
2^64, survives
/ 3and- pos, and truncates into the 32-bit loopcounter. The loop then zeroes ~1.4 billion words upward from the 16-byte
struct irc_in_addr, overrunning the stack local inms_nick()(
m_nick.c:415) or the heapClientinset_nick_name()(
s_user.c:551), and crashes the server before it relays the line.The counter never lands in a small range across the reachable input
space, so the write length is not attacker-controlled. This is a
remote denial of service with collateral corruption, not a route to code
execution.
2. Unchecked group read → information leak
The decode loop reads three bytes per group with no end-of-string check,
so a short field (e.g.
AB) consumes past the terminating NUL andassembles adjacent read-buffer bytes into the stored IP, later visible
through oper
WHOIS/USERIP/WHO %iand matched against G-lines.Reachability
Both callers are on the server
NICKpath and take the IP asparv[parc - 3]with no prior validation. Trigger:Requires a linked peer (a compromised/buggy server or a services package
emitting a malformed IP field), not a plain client. That is the threat
model IRC networks operate under: a single compromised leaf should not be
able to kill its hub.
Fix
Validate the input shape in
base64toip():unreachable;
_compression by assigningpos = 8 - wordsrather thanrunning a loop whose bound can wrap, rejecting a non-whole or
overflowing word count;
Malformed input now yields the all-zero address, matching the function's
existing silent contract. No signature or call-site change.
Tests
Regression coverage added to
ircd/test/ircd_in_addr_t.c:_field (with and without leading groups) — the underflow;iptobase64()form (IPv4, IPv6, and_compression at start/middle/end);
A trailing canary region around the destination catches any bounded
overrun in addition to a crash. Cases 1–3 crash or fail on the pre-fix
function and pass after.
Verified with a paired build of the same test binary against the
pre-fix and post-fix
numnicks.o:numnicksbase64toip)numnicks