• src/syncterm/rlogin.c

    From Deucе@VERT to Git commit to main/sbbs/master on Sun Mar 15 14:09:13 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/3d562c10cc0b6e57fae85e8d
    Modified Files:
    src/syncterm/rlogin.c
    Log Message:
    Fix GHost protocol 1-byte stack buffer overflow in rlogin.c

    Move bounds check before recv() in both GHost negotiation loops.
    Previously, rbuf[++idx]=0 wrote one byte past rbuf[10] before the
    if(idx >= sizeof(rbuf)) check could fire. Now idx is checked against sizeof(rbuf)-1 before each recv(), preventing the overflow.

    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Deucе@VERT to Git commit to main/sbbs/master on Sat May 9 18:36:58 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/d6dc31c7e5e083e7e254c97c
    Modified Files:
    src/syncterm/rlogin.c
    Log Message:
    SyncTERM: rlogin OOB via exceptfds + MSG_OOB

    Winsock2's SO_OOBINLINE + SIOCATMARK combo doesn't reliably surface
    RFC 1282 urgent-mode control bytes, so rlogin's mode-switch / window-
    size requests were dropped on Windows. Drop SO_OOBINLINE entirely and
    detect urgent via select()'s exceptfds, consuming the byte from its
    separate mailbox with recv(MSG_OOB) once SIOCATMARK shows the inline
    stream has drained to the mark. Same code path on Windows and POSIX.

    socket_check() is left untouched (many out-of-tree consumers); the
    input thread now uses a bespoke inline select() that watches both
    readfds and exceptfds. Once OOB is signaled exceptfds is dropped from
    the wait set to avoid a busy-loop while we wait for the inline read
    pointer to reach the urgent point — RFC 1282 mode-switch bytes
    (0x10/0x20) apply to data following the urgent ptr, so pre-mark inline
    data must drain in the old mode first.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Deucе@VERT to Git commit to main/sbbs/master on Sun May 10 09:06:35 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/65fdf2d1c97cff5a11c77490
    Modified Files:
    src/syncterm/rlogin.c
    Log Message:
    SyncTERM: gate rlogin OOB consume on recv()==0 + exceptfds

    The previous SIOCATMARK gate doesn't survive Win32: per dotnet/runtime
    issue #24310 and Microsoft's own docs, Winsock's SIOCATMARK has
    inverted polarity (returns 1 for "no OOB pending", 0 for "OOB pending")
    and doesn't track stream position at all — it only answers "is there
    urgent data still queued." In SO_OOBINLINE=on mode it's pinned to
    TRUE outright. That's the wrong question for an at-mark gate.

    What does work, on POSIX at least, is the documented pseudo-EOF.
    With SO_OOBINLINE off, "a read never reads across the urgent mark":
    when the inline read pointer reaches tp->urg_seq with the urgent byte
    still queued, recv() returns 0 even though the connection is alive
    (see Linux tcp(7), `tcp_recvmsg` in the kernel). Combined with
    exceptfds having fired (the oob_pending latch), recv()==0 is exactly
    the at-mark signal we need.

    So the input thread now:

    - Latches oob_pending on the first exceptfds notification (and
    drops exceptfds from the select set so we don't spin).
    - Reads inline normally; recv() > 0 just buffers as before.
    - On recv()==0 with oob_pending, treats it as the urgent-mark
    pseudo-EOF, pulls the byte via recv(MSG_OOB), and dispatches.
    Mode-switch bytes (0x10 / 0x20) still apply correctly to data
    following the urgent ptr because we've drained pre-mark inline
    in the old mode first.
    - On recv()<=0 with no oob_pending, treats it as a real peer-close
    and breaks out as before.

    Win32 may not reproduce the recv()==0 pseudo-EOF — Microsoft's docs
    say boundaries are preserved ("three reads to get past OOB") but
    don't pin down what the boundary read actually returns, and there's
    no authoritative empirical reference for it. If Windows simply
    blocks/EAGAINs at the boundary instead, this gate just never fires
    there: the OOB byte sits unread in its mailbox and the 0x80
    window-size handshake still doesn't fire. That's a regression we
    can't fix without empirical Windows testing, but it's strictly
    better than the prior SIOCATMARK gate, which falsely declared
    at-mark on every iteration and kept calling recv(MSG_OOB) on an
    empty queue.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net