Linux: support RESOLVE_NO_XDEV when openat2 is unavailable
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 45/100
- issue の種類
- 機能追加
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- linux, rust
調査の方向性
cap-primitives/src/rustix/linux/fs/open_impl.rs と既存の manually::open() resolver から始め、次に cap-std-ext の open_dir_noxdev() パスと公開 cap-fs-ext API を追跡します。fallback が symlink のトラバーサルまたは降下の前に、開かれた各コンポーネントをチェックすること、必要な場合に EXDEV または明示的な unsupported エラーを返すこと、そしてこのポリシーなしの opens を変更せずに維持することを確認します。
索引モデルが issue の本文から書いたものです。
説明
TL;DR: On Linux, cap-primitives falls back to its manual path resolver when
openat2() is unavailable, but the fallback cannot enforce
RESOLVE_NO_XDEV. Downstream users therefore cannot safely reject mount
crossings on systems where openat2() returns ENOSYS.
Context: This surfaced through bootc's open_dir_noxdev() usage under QEMU
linux-user, but the missing behavior is general and is not specific to bootc or
QEMU. The downstream report is
https://github.com/bootc-dev/bootc/issues/1481.
Current behavior
cap-primitives/src/rustix/linux/fs/open_impl.rs uses openat2() for its fast
path and falls back to manually::open() when the syscall is unavailable. The
manual resolver preserves capability containment and resolves symlinks one
component at a time, but it has no NO_XDEV policy.
As a result, cap-std-ext implements open_dir_noxdev() with a direct
openat2() call. It handles EXDEV, but propagates ENOSYS instead of using a
capability-safe fallback.
Reproduction
| Component | Value |
|---|---|
| Host and VM | x86_64, Fedora 44 |
| Container | aarch64 Fedora bootc |
| Affected emulator | QEMU linux-user 8.2.9 |
| Working emulator | QEMU linux-user 10.2.2 |
| cap-primitives | 4.0.3 |
| cap-std-ext | 5.1.2 |
With QEMU 8.2.9 registered through binfmt_misc:
$ podman run --rm --arch arm64 \
quay.io/fedora/fedora-bootc:latest \
bootc container lint
error: Linting: Function not implemented (os error 38)
The trace reports unsupported AArch64 syscall 437 immediately before the
failure. That syscall is openat2, same image passes under QEMU 10.2.2,
which implements openat2.
Required behavior
The fallback must reject crossing any mount, including same filesystem bind
mounts and mounts reached through symlinks, while retaining the manual
resolver's containment and race-resistance properties.
A final st_dev comparison is insufficient because a bind mount may have the
same device and inode as its source. Checking only the final descriptor is also
insufficient: an intermediate component or symlink may cross a mount even when
the final component is not a mount root. Each opened component must therefore
be checked before symlink interpretation or descent.
If reliable mount information is unavailable, the operation should return an
explicit unsupported error rather than silently perform a normal open.
Proposed direction
- Keep
openat2()as the fast path and addRESOLVE_NO_XDEVwhen requested. - On
ENOSYS, reuse the existing manual component resolver rather than add a
separate path walker. - Check every newly opened descriptor for a mount crossing before following a
symlink or descending into that component. - Return
EXDEVfor a detected crossing and fail closed when mount identity
cannot be determined reliably. - Expose this as an existing-directory operation through the public layer the
maintainers consider appropriate, such ascap-fs-ext. Existing opens
should remain unchanged when the policy is not requested.
STATX_ATTR_MOUNT_ROOT appears suitable for the fallback, under QEMU 8.2.9 it
correctly identified all 153 mount points visible in /proc/self/mountinfo, a
same filesystem bind mount, and descriptors held across mount and detach
operations. STATX_MNT_ID was not reliable in this environment because QEMU
reported the field as available but returned zero for tested paths.
The initial API should be limited to opening existing directories, applying a
general OpenOptions flag to effectful operations such as truncation would
require a broader design because validating the result after opening is too
late.
References
- Downstream report: https://github.com/bootc-dev/bootc/issues/1481
openat2(2): https://man7.org/linux/man-pages/man2/openat2.2.htmlstatx(2): https://man7.org/linux/man-pages/man2/statx.2.html- cap-std-ext API: https://docs.rs/cap-std-ext/latest/cap_std_ext/dirext/trait.CapStdExtDirExt.html
- 主要言語
- Rust
- スター
- 821
- フォーク
- 59
- PR マージ指標
- 30日以内にマージされた PR はありません
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
bytecodealliance/cap-std のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
bytecodealliance/cap-std#427 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
bytecodealliance/cap-std#416 · コメント 2 件 ·
-
Archiving cap-std オープン
難易度 5/5 1週間以上 初心者へのやさしさ 15/100
bytecodealliance/cap-std#426 · コメント 2 件 ·
-
難易度 5/5 1週間以上 初心者へのやさしさ 42/100
bytecodealliance/cap-std#408 · コメント 4 件 · リアクション 2 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
bytecodealliance/cap-std#406 · コメント 1 件 · リアクション 2 件 ·
bytecodealliance/cap-std の issue をすべて見る
似ている issue
-
bug CLI custom-model
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
rust-bitcoin/rust-bitcoin#6930 · コメント 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
fulcrumgenomics/ferro-hgvs#2251 ·
-
A-allocators A-docs C-enhancement T-libs
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100