Skip to content

fix(3207, 3209) Difference between the exec command in runc and youki#3210

Merged
saku3 merged 75 commits intoyouki-dev:mainfrom
tommady:close-issue-3207
Apr 7, 2026
Merged

fix(3207, 3209) Difference between the exec command in runc and youki#3210
saku3 merged 75 commits intoyouki-dev:mainfrom
tommady:close-issue-3207

Conversation

@tommady
Copy link
Copy Markdown
Collaborator

@tommady tommady commented Jul 29, 2025

Description

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Test updates
  • CI/CD related changes
  • Other (please describe):

Testing

  • Added new unit tests
  • Added new integration tests
  • Ran existing test suite
  • Tested manually (please provide steps)

Related Issues

Fixes #3207 #3209

Additional Context

dependabot bot and others added 14 commits August 11, 2025 20:48
Bumps the patch group with 4 updates: [libc](https://github.com/rust-lang/libc), [clap](https://github.com/clap-rs/clap), [serde_json](https://github.com/serde-rs/json) and [clap_complete](https://github.com/clap-rs/clap).


Updates `libc` from 0.2.174 to 0.2.175
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.175/CHANGELOG.md)
- [Commits](rust-lang/libc@0.2.174...0.2.175)

Updates `clap` from 4.5.4 to 4.5.13
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](clap-rs/clap@clap_complete-v4.5.4...clap_complete-v4.5.13)

Updates `serde_json` from 1.0.141 to 1.0.142
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](serde-rs/json@v1.0.141...v1.0.142)

Updates `clap_complete` from 4.5.1 to 4.5.13
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](clap-rs/clap@clap_complete-v4.5.1...clap_complete-v4.5.13)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.175
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: clap
  dependency-version: 4.5.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: serde_json
  dependency-version: 1.0.142
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: clap_complete
  dependency-version: 4.5.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the patch group with 3 updates: [oci-spec](https://github.com/youki-dev/oci-spec-rs), [thiserror](https://github.com/dtolnay/thiserror) and [anyhow](https://github.com/dtolnay/anyhow).


Updates `oci-spec` from 0.8.1 to 0.8.2
- [Changelog](https://github.com/youki-dev/oci-spec-rs/blob/main/release.md)
- [Commits](youki-dev/oci-spec-rs@v0.8.1...v0.8.2)

Updates `thiserror` from 2.0.12 to 2.0.14
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](dtolnay/thiserror@2.0.12...2.0.14)

Updates `anyhow` from 1.0.98 to 1.0.99
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](dtolnay/anyhow@1.0.98...1.0.99)

---
updated-dependencies:
- dependency-name: oci-spec
  dependency-version: 0.8.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: thiserror
  dependency-version: 2.0.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: anyhow
  dependency-version: 1.0.99
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
…Option of vector of string

Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
…ux yet

Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
tommady and others added 14 commits August 17, 2025 11:26
Signed-off-by: tommady <tommady@users.noreply.github.com>
Bumps the patch group with 1 update: [thiserror](https://github.com/dtolnay/thiserror).


Updates `thiserror` from 2.0.14 to 2.0.15
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](dtolnay/thiserror@2.0.14...2.0.15)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-version: 2.0.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the patch group with 1 update: [serde_json](https://github.com/serde-rs/json).


Updates `serde_json` from 1.0.142 to 1.0.143
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](serde-rs/json@v1.0.142...v1.0.143)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-version: 1.0.143
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Bumps the patch group with 1 update: [thiserror](https://github.com/dtolnay/thiserror).


Updates `thiserror` from 2.0.15 to 2.0.16
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](dtolnay/thiserror@2.0.15...2.0.16)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-version: 2.0.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Bumps the patch group with 1 update: [regex](https://github.com/rust-lang/regex).


Updates `regex` from 1.11.1 to 1.11.2
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](rust-lang/regex@1.11.1...1.11.2)

---
updated-dependencies:
- dependency-name: regex
  dependency-version: 1.11.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the patch group with 1 update: [tracing-subscriber](https://github.com/tokio-rs/tracing).


Updates `tracing-subscriber` from 0.3.19 to 0.3.20
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](tokio-rs/tracing@tracing-subscriber-0.3.19...tracing-subscriber-0.3.20)

---
updated-dependencies:
- dependency-name: tracing-subscriber
  dependency-version: 0.3.20
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
@tommady tommady requested a review from saku3 February 8, 2026 02:54
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Copy link
Copy Markdown
Member

@saku3 saku3 left a comment

Choose a reason for hiding this comment

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

Sorry for the delayed review.

I left comments on with_apparmor and ignore_paused_test.rs. Could you please take a look?

Also, since this(998d1c2 and 691e046) change is unrelated to the issue we’re addressing here, let’s handle it in a separate PR.

@@ -9,8 +9,6 @@ use nix::sys::wait::{WaitStatus, waitpid};
use crate::workload::executor::default_executor;

pub fn exec(args: Exec, root_path: PathBuf) -> Result<i32> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

with_apparmor seems to be missing.


let id2 = id.clone();
let dir2 = dir.to_path_buf();
std::thread::spawn(move || {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry, I understand now.

In this case, I think the previous implementation (adding a short sleep) is acceptable.
It aligns with runc’s behavior, so I don’t expect it to cause issues in practice.

Also, since the spawn order doesn’t guarantee the actual execution order, resume may run first, meaning the test might not actually verify that exec works while the container is paused.

@saku3
Copy link
Copy Markdown
Member

saku3 commented Feb 28, 2026

I think everything looks mostly fine aside from the parts I commented on.

PTAL @utam0k

tommady added 6 commits March 1, 2026 03:15
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
@tommady
Copy link
Copy Markdown
Collaborator Author

tommady commented Mar 1, 2026

it’s strange that both integration verifications failed

# Start group example
1 / 1 : hello world : not ok
	container stderr was not empty, found : 
thread 'main' (1) panicked at library/std/src/io/stdio.rs:1165:9:
failed printing to stdout: Broken pipe (os error 32)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

I couldn’t reproduce this on my local machine

@saku3
Copy link
Copy Markdown
Member

saku3 commented Mar 1, 2026

This is tough...

I checked it in my repository’s GitHub Actions as well.

  • Running only the example and exec tests → fails.
  • Running the tests with batch_size set to 1 → succeeds.

It’s possible the exec tests aren’t cleaning up properly.

tommady added 4 commits March 13, 2026 04:45
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
Signed-off-by: tommady <tommady@users.noreply.github.com>
@tommady
Copy link
Copy Markdown
Collaborator Author

tommady commented Mar 13, 2026

This is tough...

I checked it in my repository’s GitHub Actions as well.

  • Running only the example and exec tests → fails.

  • Running the tests with batch_size set to 1 → succeeds.

It’s possible the exec tests aren’t cleaning up properly.

Hi @saku3, @utam0k,

You were absolutely spot on with your observation about batch_size=1.
The issue was indeed caused by tests interfering with each other when run concurrently!

I've pushed a fix for this. The root cause was that preserve_fds_test was modifying the global file descriptor table in the parent contest test runner process by manually clearing the FD_CLOEXEC flag and running dup2(fd, 3).

Because contest runs tests concurrently by default, this led to two distinct issues:

  1. Race condition in hello_world: Overwriting fd=3 in the parent silently closed the pipe stdout used by other concurrently running tests (like hello_world), causing them to panic with a "Broken pipe" (OS error 32).
  2. FD Leak causing EPERM: Clearing the O_CLOEXEC flag on the host file descriptor caused it to leak into child processes spawned by other tests, which interfered with mount/remount operations in new namespaces and caused EPERM errors.

To fix this, the file descriptor modifications have been confined entirely to the child process specifically spawned for preserve_fds_test by using CommandExt::pre_exec.
This allows us to run dup2(fd, 3) safely after fork() but before exec(), preventing any side effects on the test runner or other concurrent tests.

Please feel free to review the changes when you have time.
Thanks.

@tommady tommady requested a review from saku3 March 19, 2026 07:56
@saku3
Copy link
Copy Markdown
Member

saku3 commented Mar 31, 2026

@tommady
Sorry for the delay.
I haven’t had much time since my last review.
I’ll review this within the next three days.
In the meantime, could you please resolve the conflicts?

Copy link
Copy Markdown
Member

@saku3 saku3 left a comment

Choose a reason for hiding this comment

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

Thank you for working through this patiently.

I added one more comment.

I think the preserve_fds_test looks good.

fn load_container_state(&self, container_dir: PathBuf) -> Result<Container, LibcontainerError> {
let container = Container::load(container_dir)?;
if !container.can_exec() {
if !container.can_exec()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I missed that.

With the current condition, statuses that should not allow exec, such as Stopped, would end up allowing exec.

I think it would be better to handle it like this.
(I wrote it this way for readability first, though it may be possible to simplify it further.)

        if container.status() == ContainerStatus::Paused {
            if !self.ignore_paused {
                return Err(...);
            }
        } else if !container.can_exec() {
            return Err(...);
        }

Copy link
Copy Markdown
Collaborator Author

@tommady tommady Apr 3, 2026

Choose a reason for hiding this comment

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

Great catch on that logic bug!

I think using match is the way to go here. It’s a lot more readable than the nested if statements and makes it much easier to see exactly which statuses allow execution and which don't.

Thanks for pointing that out!

Signed-off-by: tommady <tommady@users.noreply.github.com>
Copy link
Copy Markdown
Member

@saku3 saku3 left a comment

Choose a reason for hiding this comment

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

LGTM.

Thank you so, so much!

@saku3 saku3 merged commit ddd6abb into youki-dev:main Apr 7, 2026
28 checks passed
@github-actions github-actions bot mentioned this pull request Apr 7, 2026
@tommady tommady deleted the close-issue-3207 branch April 8, 2026 04:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Difference between the exec command in runc and youki

3 participants