Skip to content

fix(im): correct 64-bit MP4 box size handling to prevent panic on crafted media#1165

Merged
YangJunzhou-01 merged 1 commit into
larksuite:mainfrom
lhfer:fix/mp4-64bit-box-size-overflow
May 29, 2026
Merged

fix(im): correct 64-bit MP4 box size handling to prevent panic on crafted media#1165
YangJunzhou-01 merged 1 commit into
larksuite:mainfrom
lhfer:fix/mp4-64bit-box-size-overflow

Conversation

@lhfer

@lhfer lhfer commented May 28, 2026

Copy link
Copy Markdown
Contributor

Summary

The three MP4 box walkers in shortcuts/im/helpers.go mishandle the 64-bit ("largesize") box-size form. They set boxEnd to the raw largesize instead of offset + largesize — even though the 32-bit branch directly below correctly uses offset + size — and convert the uint64 to a signed int without any bounds check. This silently loses the duration of MP4s that carry a 64-bit box size at a non-zero offset, and panics the CLI (slice bounds out of range) on a crafted or corrupt MP4 whose largesize has the high bit set. The in-memory walkers run on URL-sourced IM media, whose bytes the caller does not control, so a malformed download crashes the process instead of degrading gracefully.

Changes

  • findMP4Box, readMp4DurationBytes, readMp4Duration: compute boxEnd = offset + largesize, mirroring the existing 32-bit offset + size.
  • Reject largesize values smaller than the 16-byte 64-bit header or larger than the remaining input, so malformed media returns 0 / -1 (the parsers' documented best-effort contract) instead of overflowing uint64 → int(64) into a negative boxEnd and panicking (CWE-190). The lower bound also guarantees the walk always makes forward progress.
  • Add shortcuts/im/mp4_box_test.go covering the overflow (must not panic) and a 64-bit box at a non-zero offset (must walk correctly).

Test Plan

  • go test -race ./shortcuts/im/... passes. The added regression tests panic / fail on the pre-fix code and pass after the fix.
  • go build ./..., go vet ./..., and gofmt -l are clean; no new dependencies (go.mod / go.sum unchanged).
  • Manual lark-cli <domain> <command> verification — this is an internal binary-parser fix with no change to any shortcut's flags, params, or request structure, so per AGENTS.md no dry-run E2E is required; behavior is covered by the added unit tests.

Related Issues

  • None

Summary by CodeRabbit

  • Bug Fixes

    • Hardened MP4 duration parsing to validate 64-bit box sizes before use, preventing integer overflows, out-of-bounds reads, and crashes when encountering malformed or oversized boxes.
  • Tests

    • Added tests covering 64-bit box size scenarios, malformed largesize values, and non-zero offsets to ensure duration extraction and box searching behave correctly without panics.

Review Change Stack

@CLAassistant

CLAassistant commented May 28, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 80758197-706a-43a4-a5e4-f8172729b26d

📥 Commits

Reviewing files that changed from the base of the PR and between 3003007 and b8976ad.

📒 Files selected for processing (2)
  • shortcuts/im/helpers.go
  • shortcuts/im/mp4_box_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • shortcuts/im/mp4_box_test.go
  • shortcuts/im/helpers.go

📝 Walkthrough

Walkthrough

Validates 64-bit MP4 "largesize" headers before computing box boundaries in findMP4Box, readMp4DurationBytes, and readMp4Duration, and adds tests that cover malformed largesize overflow and non-zero-offset 64-bit boxes.

Changes

MP4 Box Overflow Hardening

Layer / File(s) Summary
Largesize validation in findMP4Box
shortcuts/im/helpers.go
findMP4Box reads 64-bit largesize when size==1, rejects values <16 or beyond the remaining [offset,end) window, and only then computes boxEnd; invalid largesize yields (-1,-1).
Largesize validation in readMp4DurationBytes and readMp4Duration
shortcuts/im/helpers.go
readMp4DurationBytes and readMp4Duration validate 64-bit largesize against fileSize - offset and require >=16 bytes before computing boxEnd; invalid largesize returns 0.
Test helpers and overflow/non-zero-offset validation
shortcuts/im/mp4_box_test.go
Adds helpers to build 32-bit and 64-bit boxes and three tests: malformed largesize overflow (no panic, returns 0 / (-1,-1)); 64-bit moov at non-zero offset returning expected duration; and findMP4Box locating payload after a preceding 64-bit box.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • liangshuo-1

Poem

🐰 I hop through bytes both small and wide,
I nudge the largesize to check inside,
No overflowing fright, no panic leap,
The mvhd numbers safely keep,
Happy parsers, dreams of safe runtime sweet.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main fix: correcting 64-bit MP4 box size handling to prevent panics on crafted media, which aligns with the primary change in the changeset.
Description check ✅ Passed The description is comprehensive and follows the template with all required sections: Summary explaining the bug and its impact, Changes listing all modifications, Test Plan documenting verification steps, and Related Issues section. All critical information is present and detailed.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added domain/im PR touches the im domain size/M Single-domain feat or fix with limited business impact labels May 28, 2026
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Actionable comments posted: 0

@lhfer
lhfer force-pushed the fix/mp4-64bit-box-size-overflow branch from 9b1beed to 3003007 Compare May 29, 2026 02:29
…fted media

The size==1 (64-bit "largesize") branch of all three MP4 box walkers
(findMP4Box, readMp4DurationBytes, readMp4Duration) set boxEnd to the raw
largesize instead of offset+largesize — even though the 32-bit branch right
below correctly uses offset+size. Two consequences:

- Correctness: for any MP4 that carries a 64-bit box size at a non-zero
  offset, the box walk is computed from the wrong end, so the moov/mvhd
  lookup is truncated and the media duration is silently lost.

- Robustness/security (CWE-190): the unguarded uint64->int(64) conversion of
  a largesize with the high bit set yields a negative boxEnd. The in-memory
  walkers then assign it to offset and feed it back as a slice index
  (data[offset:]), panicking with "slice bounds out of range" and crashing
  the CLI on a crafted or corrupt MP4. This is reachable via URL-sourced IM
  media, whose bytes the caller does not control.

Fix: compute boxEnd as offset+largesize (matching the 32-bit branch) and
reject largesize values smaller than the 16-byte header or larger than the
remaining input. Malformed media now honours the parsers' best-effort
contract by returning 0/-1 instead of panicking, and the bounds guarantee
the conversion can no longer overflow.

Add regression tests covering both the overflow (must not panic) and a
64-bit box at a non-zero offset (must walk correctly).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@lhfer
lhfer force-pushed the fix/mp4-64bit-box-size-overflow branch from 3003007 to b8976ad Compare May 29, 2026 02:31
@codecov

codecov Bot commented May 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.79%. Comparing base (a2cc5e1) to head (b8976ad).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/im/helpers.go 66.66% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1165      +/-   ##
==========================================
+ Coverage   68.77%   68.79%   +0.01%     
==========================================
  Files         628      628              
  Lines       58670    58679       +9     
==========================================
+ Hits        40353    40367      +14     
+ Misses      15021    15014       -7     
- Partials     3296     3298       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@b8976adc7a4f2ee3358119f35776f006a8d11804

🧩 Skill update

npx skills add lhfer/cli#fix/mp4-64bit-box-size-overflow -y -g

@YangJunzhou-01

Copy link
Copy Markdown
Collaborator

Thanks for the fix. I reviewed the change and it looks good to me.

The implementation correctly treats 64-bit MP4 largesize as the box length and computes boxEnd as offset + largesize, with bounds validation before converting to signed offsets. This addresses both the non-zero-offset duration parsing bug and the crafted/corrupt MP4 panic risk.

The added regression tests cover the overflow/no-panic case and 64-bit boxes at non-zero offsets.

Verified with:

  • go test ./shortcuts/im -run 'TestMP4Box|TestParseMp4Duration|TestParseMediaDuration' -count=1
  • go test -race ./shortcuts/im

LGTM, thanks for the careful fix.

@YangJunzhou-01
YangJunzhou-01 merged commit e18ea9a into larksuite:main May 29, 2026
18 checks passed
@lhfer

lhfer commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for the review!

tuxedomm pushed a commit to zhumiaoxin/cli that referenced this pull request Jun 6, 2026
…fted media (larksuite#1165)

The size==1 (64-bit "largesize") branch of all three MP4 box walkers
(findMP4Box, readMp4DurationBytes, readMp4Duration) set boxEnd to the raw
largesize instead of offset+largesize — even though the 32-bit branch right
below correctly uses offset+size. Two consequences:

- Correctness: for any MP4 that carries a 64-bit box size at a non-zero
  offset, the box walk is computed from the wrong end, so the moov/mvhd
  lookup is truncated and the media duration is silently lost.

- Robustness/security (CWE-190): the unguarded uint64->int(64) conversion of
  a largesize with the high bit set yields a negative boxEnd. The in-memory
  walkers then assign it to offset and feed it back as a slice index
  (data[offset:]), panicking with "slice bounds out of range" and crashing
  the CLI on a crafted or corrupt MP4. This is reachable via URL-sourced IM
  media, whose bytes the caller does not control.

Fix: compute boxEnd as offset+largesize (matching the 32-bit branch) and
reject largesize values smaller than the 16-byte header or larger than the
remaining input. Malformed media now honours the parsers' best-effort
contract by returning 0/-1 instead of panicking, and the bounds guarantee
the conversion can no longer overflow.

Add regression tests covering both the overflow (must not panic) and a
64-bit box at a non-zero offset (must walk correctly).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/im PR touches the im domain size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants