aboutsummaryrefslogtreecommitdiff
path: root/hotline/flattened_file_object_test.go
diff options
context:
space:
mode:
authorJeff Halter <868228+jhalter@users.noreply.github.com>2026-05-31 14:48:31 -0700
committerJeff Halter <868228+jhalter@users.noreply.github.com>2026-05-31 14:48:31 -0700
commit123d1a305bc68474034f5989362148508bdbf7f5 (patch)
tree341a0030c5a1a9abfaa73fa31bd59c7e5c216bf7 /hotline/flattened_file_object_test.go
parent588dce918aeda0efc4db80b30525d28943c029cd (diff)
Validate client input to prevent panics from malformed transactions
A malicious or buggy client could send transaction fields with the wrong length and trigger runtime panics (slice/index out of range, slice-to-array conversion, nil deref) in the parsing and handler code. These were caught by the connection-level recover, so they dropped the client connection and dumped a stack trace to stdout rather than crashing the process, but they are still incorrect behavior, a log-flood vector, and a latent crash if the recover scope ever changes. Fix at the source and harden the safety net: - Add ClientIDFromBytes / ChatIDFromBytes helpers that return ok=false on a length mismatch, and use them in the transaction handlers instead of direct [2]byte(...) / [4]byte(...) conversions on field data. Nil-check ClientMgr.Get results, and length-guard FieldOptions and the HandleUpdateUser sub-field header. Malformed input now yields an error reply (or a clean no-op for reply-less handlers) instead of panicking. - Bounds-check FileResumeData.UnmarshalBinary (header length and fork count) and guard the ForkInfoList[0] accesses against an empty list. - Bounds-check FlatFileInformationFork parsing (reachable on upload): validate the fixed header, name, and comment lengths, and fix a latent 72+nameSize uint16 overflow. Route Write through UnmarshalBinary. - panic.go: stop printing stack traces to stdout (keep structured logging) so a client cannot flood stdout by repeatedly triggering a panic. - handleTransaction: recover per-transaction so one malformed request no longer tears down the whole client connection. Adds tests for the new helpers, the hardened resume-data and flat-file-object decoders, and handler-level malformed-ID handling.
Diffstat (limited to 'hotline/flattened_file_object_test.go')
-rw-r--r--hotline/flattened_file_object_test.go23
1 files changed, 23 insertions, 0 deletions
diff --git a/hotline/flattened_file_object_test.go b/hotline/flattened_file_object_test.go
index 6279157..6c525c4 100644
--- a/hotline/flattened_file_object_test.go
+++ b/hotline/flattened_file_object_test.go
@@ -35,6 +35,29 @@ func TestFlatFileInformationFork_UnmarshalBinary(t *testing.T) {
},
wantErr: assert.NoError,
},
+ {
+ name: "when the buffer is shorter than the fixed header returns an error instead of panicking",
+ args: args{b: make([]byte, 10)},
+ wantErr: assert.Error,
+ },
+ {
+ name: "when the declared name size overruns the buffer returns an error",
+ args: args{b: func() []byte {
+ b := make([]byte, 72)
+ binary.BigEndian.PutUint16(b[70:72], 50) // claims a 50-byte name that isn't present
+ return b
+ }()},
+ wantErr: assert.Error,
+ },
+ {
+ name: "when the declared comment size overruns the buffer returns an error",
+ args: args{b: func() []byte {
+ b := make([]byte, 74) // 72 header + 2 comment-size bytes, no name
+ binary.BigEndian.PutUint16(b[72:74], 50) // claims a 50-byte comment that isn't present
+ return b
+ }()},
+ wantErr: assert.Error,
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {