Repository navigation
hostfs: FsBackend, mounts served by the embedder - #181
Conversation
b18f9bd to
ceb7915
Compare
|
Folded into #179, which now carries both the network filter and these FsBackend commits. |
The kernel's hostfs_setattr passes the mode as a C int; the host function took a u32, so hyperlight refused every call on its parameter type and os.chmod on any mount failed with EIO. Signed-off-by: danbugs <danilochiarlone@gmail.com>
There was a problem hiding this comment.
🟡 Changes recommended
Host-directory listings collect all entries before enforcing the response limit, allowing excessive host memory use and metadata work.
1 open issue
What changed in this PR
Adds embedder-served filesystem mounts so applications can enforce quotas, permissions, and path policies per guest operation while retaining host-directory mounts.
Changes:
- Introduces
FsBackend, metadata types, andMount::backend. - Routes hostfs operations through backends, adds response validation, and fixes
chmodargument handling. - Adds integration tests and documents backend contracts and the breaking
Mountconstruction change.
| File | Description |
|---|---|
| tests/python.rs | Tests host-side chmod behavior and permission masking. |
| tests/fs_backend.rs | Tests memory-backed mounts, quotas, read-only access, and invalid backend responses. |
| src/main.rs | Uses mount constructors in CLI parsing. |
| src/lib.rs | Exports backend APIs and adds backend mount construction. |
| src/hostfs.rs | Implements backend dispatch, panic handling, and response validation. |
| src/errno.rs | Maps nonpositive raw error codes to EIO. |
| src/cli/manifest.rs | Updates mount path resolution for the private backend field. |
| docs/fs.md | Documents backend usage, responsibilities, and protocol limits. |
| CHANGELOG.md | Records backend support, API changes, and the chmod fix. |
Review effort: Balanced
| // TODO: an entry that cannot be read is skipped and a non-UTF-8 | ||
| // name is decoded lossily, neither reported to the guest. | ||
| Ok(self | ||
| .0 | ||
| .read_dir(path)? | ||
| .flatten() | ||
| .map(|entry| DirEntry { | ||
| is_dir: entry.metadata().map(|m| m.is_dir()).unwrap_or(false), | ||
| name: entry.file_name().to_string_lossy().into_owned(), | ||
| }) | ||
| .collect()) |
There was a problem hiding this comment.
Fixed in 2566c9d: DirBackend::list now counts the serialized size as it goes and stops one entry past what a reply holds, so fs_list still answers EOVERFLOW without reading the rest of the directory into host memory. A unit test lists a 2,000-entry directory and checks it stops just past the budget; the Python EOVERFLOW guest test still passes.
hostfs's operations go through an FsBackend now, one method each, with the wire encoding kept in hostfs. A host directory is the built-in backend, so Mount::rw and Mount::ro behave as before; Mount::backend mounts one of the embedder's instead, which decides every stat, read, write, listing and rename the guest's VFS makes, and answers with an io::Error the guest sees as errno. A read-only mount is still refused writes before its backend is asked. Signed-off-by: danbugs <danilochiarlone@gmail.com>

Adds
Mount::backend, so an embedder can serve a guest mount itself instead of handing over a host directory. hyperlight-sandbox needs it to serve Unikraft guests'/inputand/outputthroughCapFs, the code behind its WASI file calls, so quotas, permissions and link rules are checked per operation rather than after a run (hyperlight-dev/hyperlight-sandbox#252).FsBackendhas one method per hostfs operation:stat,read,write,create_dir,remove,truncate,list,rename.symlinkandhard_linkrefuse by default, andchmodis ignored by default. Errors reach the guest as errno, and a panic in a backend is caught and becomesEIO.Mount::rwandMount::robehave as before. A read-only mount still refuses writes withEROFSbefore its backend is asked.FileStatandDirEntryare#[non_exhaustive], with constructors. The docs spell out what a backend is given: untrusted paths and offsets,listcalled once per entry and expected to keep a stable order, and files and directories only, since the kernel makes no symlink nodes on hostfs.readlinkreplies are capped, and a raw OS error of 0 or less becomesEIO.os.chmodon any mount failed withEIO. The host took the mode asu32, but the kernel sends a Cint. It now works, with only the permission bits passed on, so a guest can't set setuid, setgid or sticky on host files.Mounthas a private field, so build one with its constructors and destructure it with...EROFS, huge offsets), against a backend that panics or returns bad answers, and withchmodon a directory mount.