Skip to content

Fix keytab parser panics and signed record-length framing (#1)#3

Merged
p0dalirius merged 1 commit into
mainfrom
bugfix-keytab-parsing-robustness
Jun 11, 2026
Merged

Fix keytab parser panics and signed record-length framing (#1)#3
p0dalirius merged 1 commit into
mainfrom
bugfix-keytab-parsing-robustness

Conversation

@p0dalirius

Copy link
Copy Markdown
Collaborator

Linked Issue

Closes #1

Root Cause

The record-parsing read path made two flawed assumptions. First, it trusted the input to be well-formed: every fixed-offset index (data[0:4], data[0:2], data[0]) and every variable-length slice (data[:c.Length], data[:k.Size]) ran without checking that enough bytes remained, and the error returned by each sub-parser was discarded. Second, it misread the record framing: the per-record length, which the keytab format defines as a signed 32-bit value, was read as uint32, and the next-record offset was computed from the bytes the entry fields happened to consume (data[entry.RawBytesSize:]) instead of from the record length. A negative length (a zero-filled hole) therefore became a huge unsigned size and triggered a slice-bounds panic, and any padding between the parsed fields and the record boundary desynchronized parsing.

Fix Description

  • CountedOctetString.FromBytes, KeyBlock.FromBytes, and KeytabEntry.FromBytes now validate len(data) before each read and return a descriptive error instead of panicking, and they propagate the errors returned by the sub-parsers they call.
  • Keytab.FromBytes reads the per-record length as a signed int32 and interprets it per the file format: a positive value is a record of that size, a negative value is a zero-filled hole that is skipped, and 0 marks end-of-file. It advances by the record length field rather than by consumed bytes, and validates the header and each record length against the remaining buffer.

How Verified

  • go test ./... passes, including new tests.
  • keytab describe -f example.kt still parses all three entries.
  • head -c 50 example.kt > truncated.kt && keytab describe -f truncated.kt now prints Error parsing keytab file: keytab entry at offset 2 claims 62 bytes but only 48 remain instead of panicking.
  • A keytab containing a valid hole record before the entries parses all three entries (the hole is skipped).

Test Coverage

  • Added: src/keytab/Keytab_parsing_test.go:
    • Test_Keytab_TruncatedInputReturnsError — parsing every truncation prefix of a valid file never panics.
    • Test_Keytab_HoleIsSkipped — a negative-length hole record is skipped and the following entry parses.
    • Test_Keytab_EndOfFileMarker — a zero-length record terminates parsing and trailing bytes are ignored.

Scope of Change

  • Files changed: src/keytab/Keytab.go, src/keytab/KeytabEntry.go, src/keytab/KeyBlock.go, src/keytab/CountedOctetString.go, src/keytab/Keytab_parsing_test.go
  • Submodule pointer updated: no
  • Behavioral changes outside the bug fix: none

Risk and Rollout

Local to the parse path; output of ToBytes/serialization is unchanged. Safe to merge directly.

The parser indexed fixed offsets and sliced variable-length fields without
validating buffer lengths, ignored the error returned by every sub-parser,
read the per-record length as unsigned, and advanced to the next record by
the number of bytes consumed rather than by the record length. As a result
it panicked on truncated input and on hole records, and mis-parsed valid
files that contain holes or trailing padding.

Add bounds checks before every read, propagate sub-parser errors, treat the
record length as a signed int32 (negative = zero-filled hole, 0 = end of
file), and advance by the record length field.

Fixes #1
@p0dalirius p0dalirius merged commit ff01af2 into main Jun 11, 2026
5 checks passed
@p0dalirius p0dalirius deleted the bugfix-keytab-parsing-robustness branch June 11, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant