Skip to content

[FIX] Reject malformed --service all values instead of aborting - #2405

Open
kaihere14 wants to merge 1 commit into
CCExtractor:masterfrom
kaihere14:fix/service-all-malformed
Open

kaihere14 wants to merge 1 commit into
CCExtractor:masterfrom
kaihere14:fix/service-all-malformed

Conversation

@kaihere14

Copy link
Copy Markdown
Contributor

In raising this pull request, I confirm the following (please check boxes):

Reason for this PR:

  • This PR adds new functionality.
  • This PR fixes a bug that I have personally experienced or that a real user has reported and for which a sample exists.
  • This PR is porting code from C to Rust.

Sanity check:

  • I have read and understood the contributors guide.
  • I have checked that another pull request for this purpose does not exist.
  • If the PR adds new functionality, I've added it to the changelog. If it's just a bug fix, I have NOT added it to the changelog.
  • I am NOT adding new C code unless it's to fix an existing, reproducible bug.

Problem

--service picks which CEA-708 services to extract. Besides service numbers (1,2), it accepts all and all[charset] (e.g. all[EUC-KR], as --help documents). A small typo in the all form crashes ccextractor instead of reporting an error:

  • --service all1, --service all[ and --service allé panic. The panic can't unwind out of ccxr_parse_parameters (extern "C"), so the process aborts with SIGABRT (exit 134).
  • --service all[EUC-KR (missing ]) doesn't crash, but loses the last letter of the charset and fails later with a confusing iconv error about "EUC-K". allEUC-KR] becomes "UC-KR".

#2393 fixed the same kind of abort for service numbers (--service 99999999999999999999). This is the all branch of the same function, which that PR didn't touch.

Regression

This came with the Rust argument parser (#1619, first released in v0.96). The C parse_708_services() it replaced only took a charset when the value was longer than all[] (s_len > all_len + 2), so it never crashed. The Rust port changed the guard to s.len() > 3 and kept the slice:

let charset = if s.len() > 3 { &s[4..s.len() - 1] } else { "" };

This skips 4 bytes (all[) and drops the last one (]) without checking that either bracket is there. For a 4-byte value like all1, the slice is &s[4..3]: the start is past the end, and Rust panics. For allé, byte 4 is inside the 2-byte é, which also panics.

Fix

A small helper, all_services_charset(), returns the charset only for the two documented forms: "" for all and X for all[X]. Anything else that starts with all is reported as a malformed parameter (exit 7), with the same wording and exit code that --service already uses for bad service numbers:

Error: [CEA-708] Malformed parameter: Invalid service list (all1), use all or all[charset].

Valid values parse exactly as before.

Repro

Sample: VH1.ts, an ATSC MPEG transport stream with CEA-608 captions (212,140,032 bytes, sha256 f9879aff48295d8ef9055289521ff8162e671a7a10eeac931fd4b3570fabb96a). The crash happens while the arguments are parsed, before the input is read, so any input file shows it.

ccextractor VH1.ts --service all1 -o out.srt; echo "exit $?"

On master (d7eb132):

thread '<unnamed>' panicked at src/parser.rs:292:46:
byte range starts at 4 but ends at 3
fatal runtime error: failed to initiate panic, error 5, aborting
exit 134

With this PR:

Error: [CEA-708] Malformed parameter: Invalid service list (all1), use all or all[charset].
exit 7

Testing

Built master (d7eb132) and this branch with mac/build.command and ran both on VH1.ts.

Malformed values:

--service master this PR
all1 panic "byte range starts at 4 but ends at 3", exit 134 Malformed parameter error, exit 7
all[ panic "byte range starts at 4 but ends at 3", exit 134 Malformed parameter error, exit 7
allé panic "start byte index 4 is not a char boundary", exit 134 Malformed parameter error, exit 7
all[EUC-KR can't create iconv for charset "EUC-K", exit 1 Malformed parameter error, exit 7
allEUC-KR] can't create iconv for charset "UC-KR", exit 1 Malformed parameter error, exit 7

Valid values, unchanged: all, all[EUC-KR], all[] and 1 exit 0 on both builds, with identical output and identical logs (ignoring build info and processing time). The CEA-708 settings both builds print match, e.g. [CEA-708: 63 decoders active] and [CEA-708: using charset "EUC-KR" for all services] for all[EUC-KR]. --service 0 still gives Invalid service number (0), valid range is 1-63. (exit 7) on both. The sample carries only CEA-608, so these runs compare the parsed settings and logs rather than CEA-708 subtitle files.

  • New unit test test_all_services_charset: accepts all, all[EUC-KR] and all[], and rejects all1, all[, allé, all[EUC-KR and allEUC-KR]. The existing --service tests (all, all[EUC-KR], numbers, per-service charsets) still pass.
  • cargo test: 427 passed. cargo fmt --check and cargo clippy are clean.

parse_708_services() took the charset of "all[X]" by slicing the value
from byte 4 to one before the end whenever it was longer than "all".
It never checked for the brackets, so:

- "all1" and "all[" panicked (the range starts at 4 but ends at 3),
  and "allé" panicked slicing inside a character. The panic can't
  unwind out of ccxr_parse_parameters, so the process aborted
  (SIGABRT, exit 134).
- "all[EUC-KR" lost its last letter and failed later in iconv with
  charset "EUC-K"; "allEUC-KR]" became "UC-KR".

This came with the Rust parser (CCExtractor#1619). The C parser only took a
charset when the value was longer than "all[]", so it never panicked,
though it did not check the brackets either.

Accept "all" and "all[charset]" only, and report anything else as a
malformed parameter (exit 7), as CCExtractor#2393 does for service numbers.
@kaihere14

Copy link
Copy Markdown
Contributor Author

@cfsmp3 A simple way to picture this bug, since it follows on from #2393:

The old line &s[4..s.len() - 1] works like a pair of scissors told "start cutting after the 4th letter and stop one letter before the end", with no check of what the letters are.

  • On all[EUC-KR] that cuts out EUC-KR, as intended.
  • On a 4-letter value like all1, the cut would start after letter 4 but end after letter 3. The start is already past the end, so there is nothing valid to cut. Rust treats that as a bug and panics, and because the panic can't leave the extern "C" parser, ccextractor aborts (exit 134).
  • On allé the cut lands in the middle of é, which takes two bytes, with the same result.
  • On all[EUC-KR (no closing ]), the scissors still cut one letter off the end, so the charset turns into EUC-K.

The fix checks that the value really is all or all[...] before cutting, and otherwise reports the usual "Malformed parameter" error (exit 7), as #2393 does for bad service numbers.

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