Skip to content

txt: bound schema rows and columns in readstat_parse_txt - #431

Merged
evanmiller merged 1 commit into
WizardMac:devfrom
ziyziy89:txt-schema-row-bounds
Nov 6, 2026
Merged

evanmiller merged 1 commit into
WizardMac:devfrom
ziyziy89:txt-schema-row-bounds

Conversation

@ziyziy89

@ziyziy89 ziyziy89 commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

readstat_parse_txt sizes line_lens from rows_per_observation and then indexes it with each schema entry's row, writing col + len there, but neither value is checked and both come straight from the dictionary file. In a Stata .dct, _line(3) with the default _lines(1) reads and writes line_lens[2] past an 8-byte allocation (ASan heap-buffer-overflow at readstat_txt_read.c:203), and _line(0) or a SAS INPUT #0 name $ 1-5; wraps the uint32_t row to 0xFFFFFFFF. _column(0) wraps col to UINT32_MAX, so col + len wraps to a small line length and txt_parse_fixed_width then copies from &line_buffer[4294967295]. The readstat CLI hits this for any .dat read with a .dct/.sas/.sps.

Reject entries whose row is not below rows_per_observation or whose col + len overflows uint32_t with READSTAT_ERROR_PARSE before line_lens is touched. All three dictionary parsers and hand-built schemas go through this function, so one check covers them. The new test in test_readstat aborts under ASan without the fix and passes with it.

readstat_parse_txt allocates line_lens with rows_per_observation
entries and then indexes it with each schema entry's row, storing
col + len there. Neither value is checked, and both come from the
dictionary file. In a Stata .dct, _line(N) is independent of _lines(),
so _line(3) with the default single line writes past line_lens, and
_line(0) or a SAS INPUT #0 wraps the row to 0xFFFFFFFF. _column(0)
wraps col to UINT32_MAX, so col + len wraps small, the line buffer is
sized from that, and txt_parse_fixed_width copies from
&line_buffer[col].

Reject rows outside rows_per_observation and col + len that overflows
before line_lens is touched.
@evanmiller
evanmiller merged commit 2ed8377 into WizardMac:dev Nov 6, 2026
14 checks passed
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.

2 participants