Skip to content

Keep host paths safe from guest-controlled paths (v2 port of #469) - #501

Closed
fresh-fx59 wants to merge 3 commits into
Lakr233:mainfrom
fresh-fx59:fix/path-integrity-v2
Closed

fresh-fx59 wants to merge 3 commits into
Lakr233:mainfrom
fresh-fx59:fix/path-integrity-v2

Conversation

@fresh-fx59

@fresh-fx59 fresh-fx59 commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #469, per #469 (comment) ("if problem still exists, feel free to ask me open this again").

I re-checked the v2 rewrite (tag 2.0.1). Three of the four issues were still present and one was partial, so this is a fresh port onto current main instead of reopening the old branch.

What was still open in 2.0.1

  1. Manifest paths — VPhoneVirtualMachineManifest.resolve(path:in:) only appended the path; load()/write() did not check diskImage, nvramStorage, sepStorage, romImages.*. VPhoneBundle.swift and VPhoneVirtualMachineLaunchCommand.swift joined the disk path by hand.
  2. Guest → host file copies — names from the guest (VPhoneRemoteFile) were not checked for /, .. or empty; downloadFile/downloadDirectory/drag-out wrote with Data.write / createDirectory(withIntermediateDirectories:), following existing symlinks in the destination.
  3. Privileged writes into mounted guest volumes (FirmwarePatcher/CryptexFilesystem) — setMode, copy/move and the in-place launchd_cache_loader patch resolved paths through any symlink in the guest volume; copyfile had no COPYFILE_NOFOLLOW and failures were only printed; volumes mounted in shared /Volumes with no device check.
  4. Host control channel (partial) — length parse and timeouts are good, but the body cap was 2 GiB and host-side file download/upload buffered whole files as Data.

Changes

  • Manifest: resolve now throws; rejects empty/absolute paths, .. components and symlinked components (including dangling), and confirms the real path stays under the bundle. Checked on load and write; hand-joined callers go through resolve.
  • Downloads: new VPhoneHostSafeFile (name validation, one-level no-follow directory creation, temp file with O_CREAT|O_EXCL|O_NOFOLLOW + rename). Used by the file browser and drag-out.
  • Guest volumes: withGuestParent walks with openat(O_NOFOLLOW|O_DIRECTORY); final ops are no-follow (fchmodat(AT_SYMLINK_NOFOLLOW), openat, renameat). copyfile uses COPYFILE_NOFOLLOW and throws on failure. hdiutil attach -nobrowse -owners on -mountrandom <0700 dir> plus a statfs check that the mount comes from the expected device.
  • Channel: in-memory bodies capped at 64 MiB; new streaming downloadFile(path:to:) / uploadFile(path:from:) in 64 KiB chunks, used by the file browser.

Validation

Not yet verified: a full restore/CFW install on a real VM (mount + guest-volume writes) and live file transfers against a running guest. Still path-based and out of scope here: VPhoneSigner.sign(fileAt:), deleteAppleDoubleFiles, the mobileactivationd patch.

🤖 Generated with Claude Code

serpens-sdd CI and others added 3 commits September 25, 2026 13:18
resolve(path:in:) now rejects empty, absolute, '.' and '..' paths and any
symlinked component (broken links included), and checks the real path stays
under the bundle. load() and write() validate every path field; the
hand-joined disk paths go through resolve.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Guest names must be a single plain component. Downloads create folders one
level at a time with O_NOFOLLOW and write through an O_CREAT|O_EXCL|O_NOFOLLOW
temp file renamed into place; drag-out gets the same name check. The guest
HTTP client caps in-memory bodies at 64 MiB and moves file content in 64 KiB
chunks to and from a FileHandle.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Guest-volume writes run as root. A helper now walks each path from the
mount root with openat(O_NOFOLLOW|O_DIRECTORY) and finishes with
fchmodat(AT_SYMLINK_NOFOLLOW), O_EXCL|O_NOFOLLOW temp files and renameat.
setMode, copies, moves, symlink creation, tree removal and the in-place
launchd_cache_loader patch go through it. copyfile uses COPYFILE_NOFOLLOW and
failures throw. Images attach with -nobrowse -owners on under a private 0700
-mountrandom directory, and statfs must show the expected device before any
write.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@fresh-fx59
fresh-fx59 force-pushed the fix/path-integrity-v2 branch from d0c2de1 to ece480e Compare September 25, 2026 10:19
@Lakr233

Lakr233 commented Sep 25, 2026

Copy link
Copy Markdown
Owner

You have to resolve conflict before submit it again, and a fix is alreay on the branch.

@Lakr233 Lakr233 closed this Sep 25, 2026
@fresh-fx59
fresh-fx59 deleted the fix/path-integrity-v2 branch September 25, 2026 11:55
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.

2 participants