6.3 KiB
Phase 1.0Y: offline shsrv framing audit
Status: SOURCE_FAMILY_FRAMING_PARTIAL_PROMPT_COMPLETION_UNPROVEN
Date: 2026-07-22
This phase audits only clean, already-local official shsrv Git history and implements a pure host model. It creates no socket, address, live CLI, command formatter or target artifact. No device action occurred.
Bound source history
| Reference | Commit | Framing family |
|---|---|---|
| v0.7 | 74287f5db6b20320efd7892d7b29cf438fe7cb98 |
legacy raw |
| v0.8 | 8f76139ee69df4b8cb7c3aee401f05bccb2c2a31 |
legacy raw |
| v0.9 | 2f2bc5501d40064c18c06f06f7b1f4cab756389b |
libtelnet/NVT introduced |
| v0.19/current | 6f320637d56d344a0e7797753099e33238bbf146 |
libtelnet/NVT |
Commit 2f2bc55 added libtelnet.c, libtelnet.h and the Telnet state machine
to sh.c. The current reference is also official tag v0.19. Both local trees
are clean. Every local official tag from v0.9 through v0.19 was checked for the
same empty option table, NVT flag, send path and libtelnet.c presence. These
facts identify official source families; they do not identify the deployed
binary.
Byte-flow graph
legacy v0.7-v0.8:
peer bytes -> socket-backed stdin -> sh_readline
stdout/stderr -> socket bytes unchanged
v0.9-v0.19:
peer bytes -> read(4096) -> telnet_recv/NVT -> pipe -> sh_readline
stdout/stderr -> pipe -> read(4096) -> telnet_send_text/NVT -> peer
The current server configures an empty Telnet option table and does not call
telnet_negotiate. It therefore sends no proactive negotiation bytes. From
the initial RFC1143 state, received IAC WILL x produces IAC DONT x, and
received IAC DO x produces IAC WONT x; initial WONT and DONT produce no
reply. A client that sends only plain command bytes triggers none of these
replies.
Exact source-family transformations
| Property | legacy raw | libtelnet/NVT |
|---|---|---|
| incoming plain bytes | unchanged | unchanged except NVT EOL |
| incoming CR LF | remains CR LF; CR is later an argument delimiter | becomes LF |
| incoming CR NUL | unchanged | becomes CR |
| incoming IAC IAC | remains two bytes | becomes one IAC application byte |
| outgoing LF | LF | CR LF |
| outgoing CR | CR | CR NUL |
| outgoing IAC | one IAC | doubled IAC |
| proactive negotiation | none | none |
| server-side command echo | none in source | none in source |
The official host wrapper invokes an external telnet program, optionally
under rlwrap. Local echo, negotiation defaults, chunking and display behavior
therefore belong to that external client and are not defined by shsrv. The
wrapper has no bounded evidence, sanitization or timeout contract and is not a
Chimera client candidate.
Prompt and completion
Both source families use the same control flow:
sh_greetwrites the automatic greeting;sh_promptwritesPWD + "$ "without a newline and flushes;sh_readlinewaits for LF;helpcompletes synchronously, while forkedstat/sumare waited for;- all streams are flushed and the loop emits the next prompt.
This proves source ordering but not an exact live boundary:
setenv("PWD", "/", 0)does not overwrite an inheritedPWD;- the prompt has no length or prefix field;
- arbitrary inherited
PWDcan itself contain the two-byte$shape; - an external Telnet client's local echo is outside the server contract;
- stdout, stderr and negotiation writes can be chunked/interleaved;
- current
sh_on_telnet_dataandsh_on_telnet_sendeach use onewriteand only log a short write; they do not finish the remaining bytes; - the exact deployed source family and binary remain unproven.
The allowlisted Phase-1.0W path alphabet excludes whitespace, $, pipe and
shell separators. The audited v0.19 static strings for help, stat and sum
contain no $ except sh_prompt. This makes a terminal $ a useful
source-shaped candidate under that exact source, but not a deployed completion
attestation. The offline model therefore never returns
exact_completion_proven=true.
Command framing evidence
sh_readline consumes one byte at a time and ends a command at LF. Both source
families therefore accept plain LF termination. In the legacy family, an
external Telnet client's preceding CR is removed later by the argument-token
delimiter. Multiple already-buffered newline-terminated commands would be
processed sequentially by the source loop.
No Chimera command-byte formatter is added here. A future passive client contract can avoid Telnet negotiation entirely and use a bounded, prevalidated LF-only batch. That claim remains design-only until separately implemented and tested.
Robustness and side effects
| Finding | Classification |
|---|---|
| automatic model/serial/firmware/temperature/frequency greeting | HIGH_FUNCTIONAL_ACCEPTANCE_REQUIRED |
| current single-write handling for pipe and socket | PROTOCOL_INTEGRITY_RISK |
| no server-side session deadline | SESSION_HANG_RISK |
| IAC IP/SUSP/ABORT may signal a running child | HIGH_FUNCTIONAL_EXCLUDED_INPUT |
| legacy Telnet controls pass into the shell byte stream | PROTOCOL_INTEGRITY_RISK |
| disconnect exits the shell process; outer server can accept again | SOURCE_DESIGN_ONLY_RUNTIME_UNPROVEN |
| no live filesystem write or autoload in framing model | SAFE_OFFLINE |
IAC command generation is excluded from every future Chimera plan. The model records synthetic IAC commands so tests cannot silently treat them as text.
Offline model
tools/phase10y_shsrv_framing_model.py models both source families with fixed
65,536-byte and 256-chunk limits. It covers NVT EOL, IAC escaping, initial
unsupported-option replies, subnegotiation removal and prompt-candidate
classification. It has no network import, CLI, target, command sender or file
output. Its 22 tests use synthetic bytes only.
Decision
- official framing families:
PROVEN_FROM_LOCAL_OFFICIAL_SOURCE; - deployed family and binary:
UNPROVEN; - source prompt order:
PROVEN_FROM_SOURCE; - terminal
$recognition:SOURCE_SHAPE_CANDIDATE_ONLY; - exact live command completion:
UNPROVEN; - passive no-negotiation approach:
OFFLINE_DESIGN_CANDIDATE; - live network adapter or collection:
NOT_AUTHORIZED.
The next permitted step is an offline-only passive, source-family-tolerant batch contract. It must retain deadline sealing and partial-result rejection, must never emit Telnet commands, and still may not add a real socket or device address.