Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
0

Configure Feed

Select the types of activity you want to include in your feed.

ircd.rs / docs / superpowers / plans / 2026-06-19-p11-slice270-topiclen-enforcement.md
3.0 kB

P11 slice 270 — enforce TOPICLEN on TOPIC set#

Goal#

leveva advertises TOPICLEN=255 in 005/ISUPPORT (isupport::TOPICLEN) but command::topic records a TOPIC set of any length verbatim — the advertised cap is cosmetic. charybdis/the IRCnet oracle enforce it by copying the new topic into a fixed char topic[TOPICLEN+1] buffer (rb_strlcpy), i.e. silent truncation. This slice makes leveva honour its own advertised TOPICLEN.

Locked decisions#

  • Truncate, do not reject. Match charybdis: an over-length topic is silently cut to the cap, not refused with a numeric. (There is no ERR_* for "topic too long".)
  • Measured in Unicode grapheme clusters (UAX #29), not bytes. Consistent with leveva's grapheme-based length policy: LINELEN (slice 121) and Message::to_wire both count graphemes. A grapheme boundary is always a char boundary, so the cut is always valid UTF-8.
  • Enforced at the setting (home) server only. The local TOPIC handler truncates once at the top, so the echo, the local-member fan-out, the stored topic, the later 332 query, and the s2s::relay::local_topic propagation all carry the same truncated text. A topic arriving over S2S (relay::inbound_topic) is trusted — its origin already truncated it — exactly as charybdis trusts a remote TOPIC.

Design#

  • isupport::truncate_topic(text: &str) -> &str — pure, returns the longest prefix of text that is at most TOPICLEN grapheme clusters (the whole string when it already fits). Mirrors the grapheme_indices(true).nth(LINELEN) cut in Message::to_wire. Directly fuzzable.
  • command::topic — in the Some(text) set branch, let text = truncate_topic(text); before it is used for set_topic / the TOPIC echo / the member fan-out / the relay.

Tests (RED first)#

  • command::topic:
    • topic_set_truncates_to_topiclen — set a TOPICLEN + 50 ASCII topic; the echo trailing and the later 332 query both carry exactly TOPICLEN graphemes.
    • topic_set_at_exactly_topiclen_is_untouched — a TOPICLEN topic survives whole.
    • topic_set_truncates_multibyte_on_a_grapheme_boundary — an over-length multi-byte topic truncates to exactly TOPICLEN graphemes and stays valid UTF-8.
  • isupport:
    • truncate_topic_caps_and_passes_through — under/at/over the cap.
    • Fuzz truncate_topic_proptest — for arbitrary input: result is a byte-prefix of the input, is ≤ TOPICLEN graphemes, equals the input iff input ≤ TOPICLEN graphemes, is idempotent, and is always valid UTF-8 (it is a &str).

Divergences#

  • Grapheme cap, not byte cap. charybdis truncates by bytes; leveva by graphemes (its uniform length unit). For ASCII — the overwhelming common case — identical.
  • Home-server enforcement only (above): inbound S2S topics are trusted, not re-truncated.

Gate#

cargo test -p leveva green; cargo clippy -p leveva --tests clean; cargo build --workspace 0 warnings.