Skip to content

Conversation

@THE-Amrit-mahto-05
Copy link
Contributor

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

  • I have read and understood the contributors guide.
  • I have checked that another pull request for this purpose does not exist.
  • I have considered, and confirmed that this submission will be valuable to others.
  • I accept that this submission may not be used, and the pull request closed at the will of the maintainer.
  • I give this submission freely, and claim no ownership to its content.
  • I have mentioned this change in the changelog.

My familiarity with the project is as follows (check one):

  • I have never used CCExtractor.
  • I have used CCExtractor just a couple of times.
  • I absolutely love CCExtractor, but have not contributed previously.
  • I am an active contributor to CCExtractor.

Description

fixed critical vulnerabilities in the DTVCC (CEA-708) decoder

Issues Fixed:

  1. Heap Buffer Overflow in dtvcc_process_data

    • Trigger: Malformed CEA-708 streams with packet length > 128.
    • Fix: Added bounds check using CCX_DTVCC_MAX_PACKET_LENGTH.
  2. Out-of-Bounds Read in dtvcc_process_current_packet

    • Trigger: Extended header (service_number 7) read beyond packet buffer.
    • Fix: Added length check to stop processing truncated extended headers.

Impact if unpatched:

  • Heap memory corruption.
  • Undefined behavior while processing malformed DTVCC streams.
  • Potential crash during caption extraction.

Testing:

  • Verified packets exceeding CCX_DTVCC_MAX_PACKET_LENGTH are safely ignored.
  • Verified truncated extended headers do not cause memory over-read.
  • Confirmed normal streams continue to decode correctly with no regression.

fixed #1966

Copy link
Contributor

@cfsmp3 cfsmp3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said in a different PR, I don't think we should be spending time here - all of this is going to be Rust soon.

But if you do it, checks needs to be really needed, otherwise it's just bloat - if you need to know if you are guarding against possible out of range accesses and things like that, not just look for maximums that can't be reached because something prevents it.

while (tbuf < seiend - 1) // Use -1 because of trailing marker
{
tbuf = sei_message(ctx, tbuf, seiend - 1);
if (!tbuf)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary. sei_message never returns NULLs.

int anchor_point = data[4] >> 4;
int col_count = (data[5] & 0x3f) + 1; // according to CEA-708-D

if (row_count > CCX_DTVCC_MAX_ROWS || col_count > CCX_DTVCC_MAX_COLUMNS)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this even possible, considering that we are doing a mask with 0xf?

Copy link
Contributor

@cfsmp3 cfsmp3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on these security fixes. Many of the changes are valid, but some checks are unnecessary - they guard against conditions that are mathematically impossible given the code structure.

Dead Code - Please Remove

1. dtvcc_window_copy_to_screen - "secondary safety guard" (lines ~595-598 in your diff)

if (copyrows > window->row_count)
    copyrows = window->row_count;
if (copycols > window->col_count)
    copycols = window->col_count;

This can NEVER trigger. Given:

int copyrows = top + window->row_count >= SCREENGRID_ROWS ? SCREENGRID_ROWS - top : window->row_count;
  • Case 1: copyrows = SCREENGRID_ROWS - top → We're in the branch where top + row_count >= SCREENGRID_ROWS, which means row_count >= SCREENGRID_ROWS - top, so copyrows <= row_count. Never triggers.
  • Case 2: copyrows = row_countcopyrows > row_count is trivially false.

Please remove this dead code.

2. dtvcc_process_character - pen bounds check

if (window->pen_row < 0 || window->pen_row >= CCX_DTVCC_MAX_ROWS ||
    window->pen_column < 0 || window->pen_column >= CCX_DTVCC_MAX_COLUMNS)

These conditions are impossible:

  • pen_row < 0: pen_row is initialized to 0, only decremented with if (pen_row > 0) pen_row--, and SetPenLocation parses it from data[1] & 0xf (always 0-15)
  • pen_row >= MAX_ROWS: Your DefineWindow validation ensures row_count <= MAX_ROWS, and your SetPenLocation validation ensures row < row_count, so pen_row is bounded

Please remove this redundant check.

3. dtvcc_window_copy_to_screen - redundant invariant check

if (window->row_count > CCX_DTVCC_MAX_ROWS || window->col_count > CCX_DTVCC_MAX_COLUMNS)

This is redundant since you're adding the same validation in dtvcc_handle_DFx_DefineWindow. If DefineWindow rejects invalid sizes, they can never reach this function.

Please remove this redundant check.

Valid Changes ✓

These are good and should stay:

  • SEI bounds checks in avc_functions.c
  • DefineWindow size validation
  • SetPenLocation bounds validation
  • VBI early return on undersized buffer
  • Teletext size checks
  • PSI buffer overflow check
  • Extended header bounds check
  • DTVCC packet length checks

Note

I'm closing #1960, #1962, #1964, #1966 since this PR includes all their commits.

@THE-Amrit-mahto-05
Copy link
Contributor Author

Thanks for the detailed review @cfsmp3

I’ve updated the PR to remove all the redundant and unreachable checks you pointed out:
Removed the unnecessary NULL check after sei_message()
Removed dead invariant checks for DTVCC window dimensions
Removed the unreachable pen bounds checks

The changes are now strictly limited to eliminating dead code without altering behavior.
Please let me know if this looks good now.

@ccextractor-bot
Copy link
Collaborator

CCExtractor CI platform finished running the test files on linux. Below is a summary of the test results, when compared to test for commit f5dc1cf...:
Report Name Tests Passed
Broken 13/13
CEA-708 14/14
DVB 6/7
DVD 3/3
DVR-MS 2/2
General 27/27
Hardsubx 1/1
Hauppage 3/3
MP4 3/3
NoCC 10/10
Options 86/86
Teletext 21/21
WTV 13/13
XDS 34/34

Your PR breaks these cases:

  • ccextractor --autoprogram --out=srt --latin1 --quant 0 85271be4d2...

Congratulations: Merging this PR would fix the following tests:

  • ccextractor --autoprogram --out=ttxt --latin1 --ucla dab1c1bd65..., Last passed: Never
  • ccextractor --out=srt --latin1 --autoprogram 29e5ffd34b..., Last passed: Never
  • ccextractor --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never
  • ccextractor --startcreditsnotbefore 1 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never
  • ccextractor --startcreditsnotafter 2 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never
  • ccextractor --startcreditsforatleast 1 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never
  • ccextractor --startcreditsforatmost 2 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never

It seems that not all tests were passed completely. This is an indication that the output of some files is not as expected (but might be according to you).

Check the result page for more info.

@ccextractor-bot
Copy link
Collaborator

CCExtractor CI platform finished running the test files on windows. Below is a summary of the test results, when compared to test for commit f5dc1cf...:
Report Name Tests Passed
Broken 13/13
CEA-708 14/14
DVB 7/7
DVD 3/3
DVR-MS 2/2
General 27/27
Hardsubx 1/1
Hauppage 3/3
MP4 3/3
NoCC 10/10
Options 86/86
Teletext 21/21
WTV 13/13
XDS 34/34

Congratulations: Merging this PR would fix the following tests:

  • ccextractor --autoprogram --out=srt --latin1 --quant 0 85271be4d2..., Last passed: Never
  • ccextractor --autoprogram --out=ttxt --latin1 --ucla dab1c1bd65..., Last passed: Never
  • ccextractor --out=srt --latin1 --autoprogram 29e5ffd34b..., Last passed: Never
  • ccextractor --out=spupng c83f765c66..., Last passed: Never
  • ccextractor --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never
  • ccextractor --startcreditsnotbefore 1 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never
  • ccextractor --startcreditsnotafter 2 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never
  • ccextractor --startcreditsforatleast 1 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never
  • ccextractor --startcreditsforatmost 2 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9..., Last passed: Never

All tests passed completely.

Check the result page for more info.

@cfsmp3 cfsmp3 merged commit dfaebd5 into CCExtractor:master Jan 3, 2026
22 of 23 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.

3 participants