Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libcontainer: support set stdios for container #2961

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions crates/libcontainer/src/container/builder.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::os::fd::OwnedFd;
use std::path::PathBuf;

use super::init_builder::InitContainerBuilder;
Expand All @@ -24,6 +25,12 @@ pub struct ContainerBuilder {
/// The function that actually runs on the container init process. Default
/// is to execute the specified command in the oci spec.
pub(super) executor: Box<dyn Executor>,
// RawFd set to stdin of the container init process.
pub stdin: Option<OwnedFd>,
// RawFd set to stdout of the container init process.
pub stdout: Option<OwnedFd>,
// RawFd set to stderr of the container init process.
pub stderr: Option<OwnedFd>,
}

/// Builder that can be used to configure the common properties of
Expand Down Expand Up @@ -70,6 +77,9 @@ impl ContainerBuilder {
console_socket: None,
preserve_fds: 0,
executor: workload::default::get_executor(),
stdin: None,
stdout: None,
stderr: None,
}
}

Expand Down Expand Up @@ -257,13 +267,84 @@ impl ContainerBuilder {
self.executor = Box::new(executor);
self
}

/// Sets the stdin of the container, for those who use libcontainer as an library,
/// the container stdin may not have to be set to an opened file descriptor
/// rather than the stdin of the current process.
/// # Example
///
/// ```no_run
/// # use libcontainer::container::builder::ContainerBuilder;
/// # use libcontainer::syscall::syscall::SyscallType;
/// # use libcontainer::workload::default::DefaultExecutor;
/// # use nix::unistd::pipe;
///
/// let (r, _w) = pipe().unwrap();
/// ContainerBuilder::new(
/// "74f1a4cb3801".to_owned(),
/// SyscallType::default(),
/// )
/// .with_stdin(r);
/// ```
pub fn with_stdin(mut self, stdin: OwnedFd) -> Self {
self.stdin = Some(stdin);
self
}

/// Sets the stdout of the container, for those who use libcontainer as an library,
/// the container stdout may not have to be set to an opened file descriptor
/// rather than the stdout of the current process.
/// # Example
///
/// ```no_run
/// # use libcontainer::container::builder::ContainerBuilder;
/// # use libcontainer::syscall::syscall::SyscallType;
/// # use libcontainer::workload::default::DefaultExecutor;
/// # use nix::unistd::pipe;
///
/// let (_r, w) = pipe().unwrap();
/// ContainerBuilder::new(
/// "74f1a4cb3801".to_owned(),
/// SyscallType::default(),
/// )
/// .with_stdout(w);
/// ```
pub fn with_stdout(mut self, stdout: OwnedFd) -> Self {
self.stdout = Some(stdout);
self
}

/// Sets the stderr of the container, for those who use libcontainer as an library,
/// the container stderr may not have to be set to an opened file descriptor
/// rather than the stderr of the current process.
/// # Example
///
/// ```no_run
/// # use libcontainer::container::builder::ContainerBuilder;
/// # use libcontainer::syscall::syscall::SyscallType;
/// # use libcontainer::workload::default::DefaultExecutor;
/// # use nix::unistd::pipe;
///
/// let (_r, w) = pipe().unwrap();
/// ContainerBuilder::new(
/// "74f1a4cb3801".to_owned(),
/// SyscallType::default(),
/// )
/// .with_stderr(w);
/// ```
pub fn with_stderr(mut self, stderr: OwnedFd) -> Self {
self.stderr = Some(stderr);
self
}
}

#[cfg(test)]
mod tests {
use std::os::fd::AsRawFd;
use std::path::PathBuf;

use anyhow::{Context, Result};
use nix::unistd::pipe;

use crate::container::builder::ContainerBuilder;
use crate::syscall::syscall::SyscallType;
Expand Down Expand Up @@ -334,4 +415,35 @@ mod tests {
assert!(result.is_ok());
Ok(())
}

#[test]
fn test_stdios() -> Result<()> {
let (r, _w) = pipe()?;
let stdin_raw = r.as_raw_fd();
let builder =
ContainerBuilder::new("74f1a4cb3801".to_owned(), SyscallType::default()).with_stdin(r);
assert_eq!(
builder.stdin.as_ref().map(|o| o.as_raw_fd()),
Some(stdin_raw)
);

let (_r, w) = pipe()?;
let stdout_raw = w.as_raw_fd();
let builder =
ContainerBuilder::new("74f1a4cb3801".to_owned(), SyscallType::default()).with_stdout(w);
assert_eq!(
builder.stdout.as_ref().map(|o| o.as_raw_fd()),
Some(stdout_raw)
);

let (_r, w) = pipe()?;
let stderr_raw = w.as_raw_fd();
let builder =
ContainerBuilder::new("74f1a4cb3801".to_owned(), SyscallType::default()).with_stderr(w);
assert_eq!(
builder.stderr.as_ref().map(|o| o.as_raw_fd()),
Some(stderr_raw)
);
Ok(())
}
}
10 changes: 10 additions & 0 deletions crates/libcontainer/src/container/builder_impl.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fs;
use std::io::Write;
use std::os::fd::{AsRawFd, OwnedFd};
use std::os::unix::prelude::RawFd;
use std::path::PathBuf;
use std::rc::Rc;
Expand Down Expand Up @@ -51,6 +52,12 @@ pub(super) struct ContainerBuilderImpl {
pub executor: Box<dyn Executor>,
/// If do not use pivot root to jail process inside rootfs
pub no_pivot: bool,
// RawFd set to stdin of the container init process.
pub stdin: Option<OwnedFd>,
// RawFd set to stdout of the container init process.
pub stdout: Option<OwnedFd>,
// RawFd set to stderr of the container init process.
pub stderr: Option<OwnedFd>,
}

impl ContainerBuilderImpl {
Expand Down Expand Up @@ -157,6 +164,9 @@ impl ContainerBuilderImpl {
detached: self.detached,
executor: self.executor.clone(),
no_pivot: self.no_pivot,
stdin: self.stdin.as_ref().map(|x| x.as_raw_fd()),
stdout: self.stdout.as_ref().map(|x| x.as_raw_fd()),
stderr: self.stderr.as_ref().map(|x| x.as_raw_fd()),
};

let (init_pid, need_to_clean_up_intel_rdt_dir) =
Expand Down
3 changes: 3 additions & 0 deletions crates/libcontainer/src/container/init_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ impl InitContainerBuilder {
detached: self.detached,
executor: self.base.executor,
no_pivot: self.no_pivot,
stdin: self.base.stdin,
stdout: self.base.stdout,
stderr: self.base.stderr,
};

builder_impl.create()?;
Expand Down
3 changes: 3 additions & 0 deletions crates/libcontainer/src/container/tenant_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ impl TenantContainerBuilder {
detached: self.detached,
executor: self.base.executor,
no_pivot: false,
stdin: self.base.stdin,
stdout: self.base.stdout,
stderr: self.base.stderr,
};

let pid = builder_impl.create()?;
Expand Down
6 changes: 6 additions & 0 deletions crates/libcontainer/src/process/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@ pub struct ContainerArgs {
pub executor: Box<dyn Executor>,
/// If do not use pivot root to jail process inside rootfs
pub no_pivot: bool,
// RawFd set to stdin of the container init process.
pub stdin: Option<RawFd>,
// RawFd set to stdout of the container init process.
pub stdout: Option<RawFd>,
// RawFd set to stderr of the container init process.
pub stderr: Option<RawFd>,
}
15 changes: 14 additions & 1 deletion crates/libcontainer/src/process/container_init_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use nc;
use nix::mount::{MntFlags, MsFlags};
use nix::sched::CloneFlags;
use nix::sys::stat::Mode;
use nix::unistd::{self, setsid, Gid, Uid};
use nix::unistd::{self, close, dup2, setsid, Gid, Uid};
use oci_spec::runtime::{
IOPriorityClass, LinuxIOPriority, LinuxNamespaceType, LinuxSchedulerFlag, LinuxSchedulerPolicy,
Scheduler, Spec, User,
Expand Down Expand Up @@ -374,6 +374,19 @@ pub fn container_init_process(
tracing::error!(?err, "failed to set up tty");
InitProcessError::Tty(err)
})?;
} else {
if let Some(stdin) = args.stdin {
dup2(stdin, 0).map_err(InitProcessError::NixOther)?;
close(stdin).map_err(InitProcessError::NixOther)?;
}
if let Some(stdout) = args.stdout {
dup2(stdout, 1).map_err(InitProcessError::NixOther)?;
close(stdout).map_err(InitProcessError::NixOther)?;
}
if let Some(stderr) = args.stderr {
dup2(stderr, 2).map_err(InitProcessError::NixOther)?;
close(stderr).map_err(InitProcessError::NixOther)?;
}
}

apply_rest_namespaces(&namespaces, spec, syscall.as_ref())?;
Expand Down