SIGN IN SIGN UP
oven-sh / bun UNCLAIMED

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one

0 0 150 Rust

patch: don't panic applying a rename whose destination dir overflows the path buffer (#31306)

### What does this PR do?

Fixes a fuzzer-found crash in patch application: applying a patchfile
whose `rename to` destination has a long parent directory aborts the
process with

```
panic: range end index 4107 out of range for slice of length 4094
```

#### Repro

```js
// BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING=1
import { patchInternals } from "bun:internal-for-testing";
const hugeDir = Buffer.alloc(8000, "a").toString();
patchInternals.apply(`rename from from.txt\nrename to ${hugeDir}/to.txt\n`, someDir);
```

The same code path runs during `bun install` when applying
`patchedDependencies`, so a hostile `.patch` file can crash the install.

#### Cause

`PatchFile::apply`'s `FileRename` branch built the destination's parent
directory as an **absolute** path by joining the patch dir's absolute
path with the patch-supplied dirname via `resolve_path::join_z`. That
join normalizes into a fixed 4096-byte thread-local buffer (`JOIN_BUF` →
`join_string_buf(&buf[..4095])` → `normalize_string_node_t` writes into
`buf[1..]`, i.e. 4094 bytes), so any joined path longer than that trips
a slice-bounds panic — the `4107` / `4094` numbers from the fuzz report
correspond exactly to a ~4081-byte dirname joined with a 26-byte patch
dir path.

#### Fix

Create the destination's parent directory **relative to the patch dir
fd** with `sys::mkdir_recursive_at_mode(patch_dir, todir, 0o755)`, the
same way the `FileCreation` branch already does. This removes the
unbounded fixed-buffer join entirely; over-long paths now surface as a
regular `ENAMETOOLONG` error that `patchInternals.apply` / `bun install`
report as a normal failure.

Because the cached absolute patch-dir path is now only needed by the
Windows-only branches, `ApplyState`'s field/method are marked
`#[cfg_attr(unix, allow(dead_code))]` and the remaining `platform::Auto`
uses go through the existing `paths` alias.

#### Verification

- New test in `test/js/bun/patch/patch.test.ts` (`apply > rename > to a
destination dir longer than the path buffer throws instead of crashing`)
spawns a subprocess that applies such a patch: without the fix the
subprocess aborts with the panic above; with the fix it throws a
catchable `ENAMETOOLONG` and exits 0.
- The original fuzz input (4,158-byte patchfile with a 4,127-byte
`rename to` path) now yields `ENAMETOOLONG` instead of the panic.
- All existing tests in `test/js/bun/patch/patch.test.ts` pass (23/23),
including the `rename > folders` test that exercises the changed mkdir
path.
R
robobun committed
d2f274d22de5f01b2cc24a6262ad46ae29447487
Parent: 8dcbb44
Committed by GitHub <noreply@github.com> on 5/24/2026, 4:07:48 AM