Skip to content

fuse: check O_LARGEFILE before masking it out of the open flags - #13969

Open
copybara-service[bot] wants to merge 1 commit into
masterfrom
test/cl958610773
Open

fuse: check O_LARGEFILE before masking it out of the open flags#13969
copybara-service[bot] wants to merge 1 commit into
masterfrom
test/cl958610773

Conversation

@copybara-service

Copy link
Copy Markdown

fuse: check O_LARGEFILE before masking it out of the open flags

Files larger than 2GiB on a FUSE mount cannot be opened inside the sandbox: every
open() fails with EOVERFLOW ("Value too large for defined data type"), no matter what
flags the caller passes.

In pkg/sentry/fsimpl/fuse/inode.go, Open() masks the open flags against a whitelist
that does not include O_LARGEFILE on the line immediately before testing for it:

opts.Flags &= linux.O_ACCMODE | linux.O_CREAT | linux.O_EXCL | linux.O_TRUNC |
	linux.O_DIRECTORY | linux.O_NOFOLLOW | linux.O_NONBLOCK | linux.O_NOCTTY |
	linux.O_APPEND | linux.O_DIRECT
i.attrMu.Lock()
defer i.attrMu.Unlock()
if opts.Flags&linux.O_LARGEFILE == 0 && i.size.Load() > linux.MAX_NON_LFS {
	return nil, linuxerr.EOVERFLOW
}

O_LARGEFILE is always clear by the time it is tested, so the guard is unconditional for
any file over MAX_NON_LFS. This is not an obscure path: openat(2) adds O_LARGEFILE
for all 64-bit callers (pkg/sentry/syscalls/linux/sys_file.go) and the VFS layer
preserves it (pkg/sentry/vfs/vfs.go), so the flag is set on essentially every open and
the check should essentially never fire. No other filesystem implementation has this
check, which is why only FUSE mounts are affected.

Present since 298b5f3 ("Refactor FUSE inode implementation.", 2023-02-01), so in every
release from release-20230214.0 onwards.

Reproduced with rclone's FUSE mount under runsc do: reading a 3GiB file through the
mount fails at open(), a 1GiB file on the same mount succeeds, and the same 3GiB file
read outside the mount succeeds.

The fix moves the mask below the check. TestFUSEOpenLargeFile covers both directions —
a file over MAX_NON_LFS opens with O_LARGEFILE and still returns EOVERFLOW without
it — and fails on the unpatched inode.go.

Assisted-by: Claude Code
FUTURE_COPYBARA_INTEGRATE_REVIEW=#13957 from jbbakeng:jbbakeng/fuse-largefile-open 3115757

@copybara-service copybara-service Bot added the exported Issue was exported automatically label Aug 3, 2026
Files larger than 2GiB on a FUSE mount cannot be opened inside the sandbox: every
`open()` fails with `EOVERFLOW` ("Value too large for defined data type"), no matter what
flags the caller passes.

In `pkg/sentry/fsimpl/fuse/inode.go`, `Open()` masks the open flags against a whitelist
that does not include `O_LARGEFILE` on the line immediately before testing for it:

```go
opts.Flags &= linux.O_ACCMODE | linux.O_CREAT | linux.O_EXCL | linux.O_TRUNC |
	linux.O_DIRECTORY | linux.O_NOFOLLOW | linux.O_NONBLOCK | linux.O_NOCTTY |
	linux.O_APPEND | linux.O_DIRECT
i.attrMu.Lock()
defer i.attrMu.Unlock()
if opts.Flags&linux.O_LARGEFILE == 0 && i.size.Load() > linux.MAX_NON_LFS {
	return nil, linuxerr.EOVERFLOW
}
```

`O_LARGEFILE` is always clear by the time it is tested, so the guard is unconditional for
any file over `MAX_NON_LFS`. This is not an obscure path: `openat(2)` adds `O_LARGEFILE`
for all 64-bit callers (`pkg/sentry/syscalls/linux/sys_file.go`) and the VFS layer
preserves it (`pkg/sentry/vfs/vfs.go`), so the flag is set on essentially every open and
the check should essentially never fire. No other filesystem implementation has this
check, which is why only FUSE mounts are affected.

Present since 298b5f3 ("Refactor FUSE inode implementation.", 2023-02-01), so in every
release from `release-20230214.0` onwards.

Reproduced with rclone's FUSE mount under `runsc do`: reading a 3GiB file through the
mount fails at `open()`, a 1GiB file on the same mount succeeds, and the same 3GiB file
read outside the mount succeeds.

The fix moves the mask below the check. `TestFUSEOpenLargeFile` covers both directions —
a file over `MAX_NON_LFS` opens with `O_LARGEFILE` and still returns `EOVERFLOW` without
it — and fails on the unpatched `inode.go`.

Assisted-by: Claude Code
FUTURE_COPYBARA_INTEGRATE_REVIEW=#13957 from jbbakeng:jbbakeng/fuse-largefile-open 3115757
PiperOrigin-RevId: 958610773
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

exported Issue was exported automatically

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant