mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-05-02 05:34:46 +00:00
forwarder: Drop privileges when using hybrid VSOCK
Hybrid VSOCK requires `root` privileges to access the sandbox-specific host-side AF_UNIX socket created by the hypervisor (CLH or FC). However, once the socket has been bound, privileges can be dropped, allowing the forwarder to run as user `nobody`. Fixes: #2905. Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com>
This commit is contained in:
parent
b67fa9e450
commit
6abccb92ce
32
src/trace-forwarder/Cargo.lock
generated
32
src/trace-forwarder/Cargo.lock
generated
@ -71,9 +71,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
@ -335,6 +335,7 @@ dependencies = [
|
||||
"nix 0.21.0",
|
||||
"opentelemetry",
|
||||
"opentelemetry-jaeger",
|
||||
"privdrop",
|
||||
"protobuf",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -354,9 +355,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.97"
|
||||
version = "0.2.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
|
||||
checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -433,6 +434,19 @@ dependencies = [
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.43"
|
||||
@ -546,6 +560,16 @@ version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
|
||||
|
||||
[[package]]
|
||||
name = "privdrop"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c02cf257b10e4b807bccadb19630d5dea7e0369c3c5e84673ee8e58dc8da6a5"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"nix 0.23.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
|
@ -29,6 +29,7 @@ tracing-subscriber = "0.2.18"
|
||||
|
||||
logging = { path = "../../pkg/logging" }
|
||||
slog = "2.5.2"
|
||||
privdrop = "0.5.1"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
|
@ -141,7 +141,8 @@ You can now proceed as normal to create the "foo" Kata container.
|
||||
> directory, and since that directory is owned by the `root` user, the trace
|
||||
> forwarder must also be run as `root`. This requirement is unique to
|
||||
> hypervisors that use hybrid VSOCK: QEMU does not require special privileges
|
||||
> to run the trace forwarder.
|
||||
> to run the trace forwarder. To reduce the impact of this, once the forwarder
|
||||
> is running it drops privileges to run as user `nobody`.
|
||||
|
||||
## Full details
|
||||
|
||||
|
@ -16,45 +16,6 @@ const DEFAULT_TRACE_NAME: &str = "kata-agent";
|
||||
|
||||
const ABOUT_TEXT: &str = "Kata Containers Trace Forwarder";
|
||||
|
||||
const DESCRIPTION_TEXT: &str = r#"
|
||||
DESCRIPTION:
|
||||
Kata Containers component that runs on the host and forwards
|
||||
trace data from the container to a trace collector on the host.
|
||||
|
||||
This tool requires agent tracing to be enabled in the Kata
|
||||
configuration file. It uses VSOCK to listen for trace data originating
|
||||
from the Kata agent running inside the Kata Container.
|
||||
|
||||
The variety of VSOCK used depends on the configuration hypervisor:
|
||||
|
||||
|------------------------|--------------------|----------------|
|
||||
| Hypervisor | Type of VSOCK | Run as user |
|
||||
|------------------------|--------------------|----------------|
|
||||
| Cloud Hypervisor (CLH) | Firecracker Hybrid | privileged |
|
||||
|------------------------|--------------------|----------------|
|
||||
| QEMU | Standard | non-privileged |
|
||||
|------------------------|--------------------|----------------|
|
||||
| Firecracker (FC) | Firecracker Hybrid | privileged |
|
||||
|------------------------|--------------------|----------------|
|
||||
|
||||
Key:
|
||||
|
||||
- Firecracker Hybrid VSOCK: See the Firecracker
|
||||
VSOCK documentation.
|
||||
- Standard VSOCK: see vsock(7).
|
||||
|
||||
The way this tool is run depends on the configured hypervisor.
|
||||
See EXAMPLES for further information.
|
||||
|
||||
Note that Hybrid VSOCK requries root privileges. Due to the way the
|
||||
hybrid protocol works, the specified "master socket" itself is not used: to
|
||||
communicate with the agent, this tool must generate a socket path using
|
||||
the specified socket path as a prefix. Since the master socket will be
|
||||
created in a root-owned directory when the Kata Containers VM (sandbox) is
|
||||
created, this tool must be run as root to allow it to create the second
|
||||
agent-specific socket.
|
||||
"#;
|
||||
|
||||
const DEFAULT_LOG_LEVEL: slog::Level = slog::Level::Info;
|
||||
|
||||
// VSOCK port this program listens to for trace data, sent by the agent.
|
||||
@ -84,6 +45,50 @@ fn announce(logger: &Logger, version: &str, dump_only: bool) {
|
||||
"dump-only" => dump_only);
|
||||
}
|
||||
|
||||
fn make_description_text() -> String {
|
||||
format!(
|
||||
r#" DESCRIPTION:
|
||||
Kata Containers component that runs on the host and forwards
|
||||
trace data from the container to a trace collector on the host.
|
||||
|
||||
This tool requires agent tracing to be enabled in the Kata
|
||||
configuration file. It uses VSOCK to listen for trace data originating
|
||||
from the Kata agent running inside the Kata Container.
|
||||
|
||||
The variety of VSOCK used depends on the configuration hypervisor:
|
||||
|
||||
|------------------------|--------------------|----------------|
|
||||
| Hypervisor | Type of VSOCK | Run as user |
|
||||
|------------------------|--------------------|----------------|
|
||||
| Cloud Hypervisor (CLH) | Firecracker Hybrid | privileged |
|
||||
|------------------------|--------------------|----------------|
|
||||
| QEMU | Standard | non-privileged |
|
||||
|------------------------|--------------------|----------------|
|
||||
| Firecracker (FC) | Firecracker Hybrid | privileged |
|
||||
|------------------------|--------------------|----------------|
|
||||
|
||||
Key:
|
||||
|
||||
- Firecracker Hybrid VSOCK: See the Firecracker
|
||||
VSOCK documentation.
|
||||
- Standard VSOCK: see vsock(7).
|
||||
|
||||
The way this tool is run depends on the configured hypervisor.
|
||||
See EXAMPLES for further information.
|
||||
|
||||
Note that Hybrid VSOCK requries root privileges initially. Due to the way the
|
||||
hybrid protocol works, the specified "master socket" itself is not used: to
|
||||
communicate with the agent, this tool must generate a socket path using
|
||||
the specified socket path as a prefix. Since the master socket will be
|
||||
created in a root-owned directory when the Kata Containers VM (sandbox) is
|
||||
created, this tool must be run as root to allow it to create the second
|
||||
agent-specific socket. However, once the forwarder has started running, it
|
||||
drops privileges and will continue running as user {user:?}.
|
||||
"#,
|
||||
user = server::NON_PRIV_USER
|
||||
)
|
||||
}
|
||||
|
||||
fn make_examples_text(program_name: &str) -> String {
|
||||
format!(
|
||||
r#"EXAMPLES:
|
||||
@ -135,7 +140,7 @@ fn real_main() -> Result<()> {
|
||||
.version(version)
|
||||
.version_short("v")
|
||||
.about(ABOUT_TEXT)
|
||||
.long_about(DESCRIPTION_TEXT)
|
||||
.long_about(&*make_description_text())
|
||||
.after_help(&*make_examples_text(name))
|
||||
.arg(
|
||||
Arg::with_name("dump-only")
|
||||
|
@ -6,6 +6,7 @@
|
||||
use crate::handler;
|
||||
use anyhow::{anyhow, Result};
|
||||
use opentelemetry::sdk::export::trace::SpanExporter;
|
||||
use privdrop::PrivDrop;
|
||||
use slog::{debug, o, Logger};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::os::unix::net::UnixListener;
|
||||
@ -13,6 +14,12 @@ use vsock::{SockAddr, VsockListener};
|
||||
|
||||
use crate::tracer;
|
||||
|
||||
// Username that is assumed to exist, used when dropping root privileges
|
||||
// when running with Hybrid VSOCK.
|
||||
pub const NON_PRIV_USER: &str = "nobody";
|
||||
|
||||
const ROOT_DIR: &str = "/";
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum VsockType {
|
||||
Standard { port: u32, cid: u32 },
|
||||
@ -79,12 +86,29 @@ impl VsockTraceServer {
|
||||
}
|
||||
}
|
||||
|
||||
fn drop_privs(logger: &Logger) -> Result<()> {
|
||||
debug!(logger, "Dropping privileges"; "new-user" => NON_PRIV_USER);
|
||||
|
||||
nix::unistd::chdir(ROOT_DIR)
|
||||
.map_err(|e| anyhow!("Unable to chdir to {:?}: {:?}", ROOT_DIR, e))?;
|
||||
|
||||
PrivDrop::default()
|
||||
.user(NON_PRIV_USER)
|
||||
.apply()
|
||||
.map_err(|e| anyhow!("Failed to drop privileges to user {}: {}", NON_PRIV_USER, e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_hybrid_vsock(
|
||||
logger: Logger,
|
||||
exporter: &mut dyn SpanExporter,
|
||||
socket_path: &str,
|
||||
dump_only: bool,
|
||||
) -> Result<()> {
|
||||
let logger =
|
||||
logger.new(o!("vsock-type" => "hybrid", "vsock-socket-path" => socket_path.to_string()));
|
||||
|
||||
let effective = nix::unistd::Uid::effective();
|
||||
|
||||
if !effective.is_root() {
|
||||
@ -96,9 +120,10 @@ fn start_hybrid_vsock(
|
||||
|
||||
let listener = UnixListener::bind(socket_path)?;
|
||||
|
||||
debug!(logger, "Waiting for connections";
|
||||
"vsock-type" => "hybrid",
|
||||
"vsock-socket-path" => socket_path);
|
||||
// Having bound to the socket, drop privileges
|
||||
drop_privs(&logger)?;
|
||||
|
||||
debug!(logger, "Waiting for connections");
|
||||
|
||||
for conn in listener.incoming() {
|
||||
let conn = conn?;
|
||||
|
Loading…
Reference in New Issue
Block a user