Skip to content

FS-Tee Grate.#92

Open
stupendoussuperpowers wants to merge 24 commits into
mainfrom
tee-grate
Open

FS-Tee Grate.#92
stupendoussuperpowers wants to merge 24 commits into
mainfrom
tee-grate

Conversation

@stupendoussuperpowers

Copy link
Copy Markdown
Contributor

No description provided.

@rennergade

Copy link
Copy Markdown
Contributor

should just be 'fs-tee' now

Comment thread rust-grates/fs-tee-grate/src/handlers/tee.rs Outdated
Comment thread rust-grates/fs-tee-grate/src/handlers/tee.rs Outdated
Comment thread rust-grates/fs-tee-grate/src/handlers/lifecycle.rs Outdated
Comment thread rust-grates/fs-tee-grate/src/handlers/lifecycle.rs
Comment thread rust-grates/fs-tee-grate/src/tee.rs
Comment thread rust-grates/fs-tee-grate/src/handlers/tee.rs Outdated
Comment thread rust-grates/fs-tee-grate/src/handlers/tee.rs Outdated
Comment thread rust-grates/fs-tee-grate/src/handlers/tee.rs
Comment thread rust-grates/fs-tee-grate/src/tee.rs

@rennergade rennergade left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a handful of comments

@rennergade

rennergade commented May 19, 2026

Copy link
Copy Markdown
Contributor

Seems like theres a merge conflict. Some thoughts I have:

  • The tee dispatcher runs the primary syscall first, then runs the secondary syscall using the same
    guest pointers and buffers:

    rust-grates/fs-tee-grate/src/handlers/tee.rs:84

    For read-like syscalls, this means the return value comes from the primary path, but the bytes left
    in target memory may come from the secondary path. Examples: read, pread, readv, stat, getdents,
    readlink, etc.

    fs-tee should either avoid running secondary copyout syscalls against the target’s real output
    buffers, or copy/restore the primary output before returning.

  • pipe()/pipe2() fallback calls SYS_OPEN and does not record pipe FD mappings

    In tee_pipe and tee_pipe2, the fallback path uses SYS_OPEN:

    rust-grates/fs-tee-grate/src/handlers/tee.rs:334
    rust-grates/fs-tee-grate/src/handlers/tee.rs:613

    That should be SYS_PIPE / SYS_PIPE2. Also, the handlers do not record the two returned pipe FDs, so
    later reads/writes on those pipe descriptors cannot be translated to the secondary path.

    This breaks tee behavior for programs that use pipe or pipe2 unless the secondary grate happens to
    provide a matching alternate handler.

  • Secondary handler lookup picks the first registration, not the topmost one

    get_interposition_request uses .find():

    rust-grates/fs-tee-grate/src/utils.rs:33

    If multiple grates in the secondary stack register the same syscall, this selects the first one that
    registered. In a stacked grate chain, the later/topmost registration should win. This should likely
    use .rfind(), matching the intended handler stack order.

  • file-backed mmap is mirrored without translating the fd

    mmap is registered as a path/no-FD-translation handler:

    rust-grates/fs-tee-grate/src/handlers/tee.rs:191

    But file-backed mmap uses arg5 as the fd. If primary and secondary fd numbers differ, the secondary
    mmap runs against the wrong fd or fails. mmap needs special handling: skip fd translation for
    anonymous mappings, but translate arg5 for file-backed mappings.

@stupendoussuperpowers

Copy link
Copy Markdown
Contributor Author

@rennergade, addressed all these. Tests still pass too. Feel free to review again.

Comment thread rust-grates/fs-tee-grate/src/handlers/tee.rs
Comment thread rust-grates/fs-tee-grate/src/handlers/tee.rs
Comment thread rust-grates/fs-tee-grate/src/handlers/tee.rs Outdated
@stupendoussuperpowers

Copy link
Copy Markdown
Contributor Author

Added a fdtables::close in the tee_close handler. Along with error checks before record_fd_pair and in the fork handler.

Comment thread rust-grates/fs-tee-grate/test/run_tests.sh Outdated
Comment thread rust-grates/fs-tee-grate/src/handlers/tee.rs
read_buf[n] = '\0';
printf("read: %s", read_buf);

int dupfd = dup(fd);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exerciser calls dup/dup2/dup3, but the test only checks that the target exits successfully. It does not assert that the secondary path saw successful mirrored results or that fs-tee-secondary.log has matching success values. That means the fd translation bug above can pass if the primary path works while secondary calls fail/log -1.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any proposals on what a test for the secondary paths should look like? Those values are never really returned anywhere.

Checking the log file seems to be unreliable.

I don't think this is limited to dup* either, pretty much all the tests above are only checking to make sure the primary paths are not hampered.

@rennergade rennergade left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put in some comments related to the dup family and a small fix to the test runner that should make it more reliable.

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.

3 participants