Skip to content

Reject metaflac numeric arguments that do not fit in 32 bits - #946

Open
trestoncuzzort wants to merge 1 commit into
xiph:masterfrom
trestoncuzzort:metaflac-uint32-range
Open

trestoncuzzort wants to merge 1 commit into
xiph:masterfrom
trestoncuzzort:metaflac-uint32-range

Conversation

@trestoncuzzort

Copy link
Copy Markdown

Where unsigned long has 64 bits, parse_uint32() stores the result of strtoul() in a FLAC__uint32 without a range check, so a number above 2^32 − 1 is truncated before the callers check it. parse_add_padding() and parse_block_number() narrow their values in the same way.

On Linux x86-64, with a copy of test/metaflac.flac.in (44100 Hz, 8 bits, 1 channel), each of these exits 0 on master:

option result on master
--set-sample-rate=4294967297 sample rate 1
--set-channels=4294967298 2 channels
--set-min-blocksize=4294967312 minimum block size 16
--set-min-framesize=4294967297 minimum frame size 1
--add-padding=4294967312 a padding block of 16 bytes is added
--list --block-number=4294967296 block 0 is listed

With the change each of them fails with the message that the option already has for a value out of range (for example ERROR (--set-sample-rate): invalid sample rate), and the file is left as it was.

parse_uint32() now goes through parse_uint64() and rejects a value above 2^32 − 1, parse_add_padding() checks the 2^24 limit before it narrows, and parse_block_number() uses parse_uint32().

Tests. test_metaflac.sh gets a block with nine such options, each of which must fail and leave the file unchanged, and a check that values in range are still accepted. On master it stops at Testing that --set-sample-rate=4294967297 is rejected... ERROR: it should have failed but didn't; with the change it passes. All 10 ctest tests pass before and after (CMake build without Ogg, GCC 13.3, Linux x86-64). I did not run the autotools build or the other CI platforms.

Not part of this change: --set-channels=0 is accepted on master and still is, although the message says "value must be > 0"; the file then reports 8 channels and a sample rate of 44111. I can add that check here or send it separately, as you prefer.

I also checked parse_uint32() and parse_add_padding() with the CBMC model checker (6.11.0), run through the case gate of my tool dawnr: for every string of up to 11 characters the result and the stored value are compared with the decimal value of the digits. The current functions fail that (for example "9677309084", and the same input fails when run natively) and the changed ones pass. CBMC has no strtoul, so the model uses stand-ins; a native run of the same harness with glibc over 563,422,433 strings agrees: the current code fails for the 13,110,962 numbers above 2^32 − 1 and the changed code for none. The harness and the results are in https://github.com/trestoncuzzort/dawnr/tree/5d6ac9cc026a2b6ee9513a931c952094f3182a8f/t/native_fixtures/flac-metaflac-parse-uint32.

Where unsigned long has 64 bits, parse_uint32() stored the result of
strtoul() in a FLAC__uint32 without a range check, so for example
--set-sample-rate=4294967297 set a sample rate of 1. parse_add_padding()
and parse_block_number() narrowed their values in the same way:
--add-padding=4294967312 added 16 bytes of padding and
--block-number=4294967296 selected block 0.

Parse the number in 64 bits and reject a value that does not fit.
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