From 4b5b788918b1d10ec644cbb23ec57de2f4e3f3d1 Mon Sep 17 00:00:00 2001 From: Antoine Gaillard <antoine.gaillard@datadoghq.com> Date: Wed, 5 Feb 2025 16:59:45 +0100 Subject: [PATCH] agent: Use init subcgroup for process attachment in DinD cgroups v2 enforces stricter delegation rules, preventing operations on cgroups outside our ownership boundary. When running Docker-in-Docker (DinD), processes must be attached to an "init" subcgroup within the systemd unit. This fix detects and uses the init subcgroup when proxying process attachment. Fixes #10733 Signed-off-by: Antoine Gaillard <antoine.gaillard@datadoghq.com> --- src/agent/rustjail/src/cgroups/fs/mod.rs | 17 +++++++++++++++++ .../rustjail/src/cgroups/systemd/dbus_client.rs | 7 +++---- .../rustjail/src/cgroups/systemd/manager.rs | 3 ++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/agent/rustjail/src/cgroups/fs/mod.rs b/src/agent/rustjail/src/cgroups/fs/mod.rs index 741c9ce2f6..bc9b2b090b 100644 --- a/src/agent/rustjail/src/cgroups/fs/mod.rs +++ b/src/agent/rustjail/src/cgroups/fs/mod.rs @@ -1170,6 +1170,23 @@ impl Manager { }) } + pub fn subcgroup(&self) -> &str { + // Check if we're in a Docker-in-Docker setup by verifying: + // 1. We're using cgroups v2 (which restricts direct process control) + // 2. An "init" subdirectory exists (used by DinD for process delegation) + let is_dind = cgroups::hierarchies::is_cgroup2_unified_mode() + && cgroups::hierarchies::auto() + .root() + .join(&self.cpath) + .join("init") + .exists(); + if is_dind { + "/init/" + } else { + "/" + } + } + fn get_paths_and_mounts( cpath: &str, ) -> Result<(HashMap<String, String>, HashMap<String, String>)> { diff --git a/src/agent/rustjail/src/cgroups/systemd/dbus_client.rs b/src/agent/rustjail/src/cgroups/systemd/dbus_client.rs index 3e1e3275c7..0c3294b444 100644 --- a/src/agent/rustjail/src/cgroups/systemd/dbus_client.rs +++ b/src/agent/rustjail/src/cgroups/systemd/dbus_client.rs @@ -19,7 +19,7 @@ pub trait SystemdInterface { fn kill_unit(&self) -> Result<()>; fn freeze_unit(&self) -> Result<()>; fn thaw_unit(&self) -> Result<()>; - fn add_process(&self, pid: i32) -> Result<()>; + fn add_process(&self, pid: i32, subcgroup: &str) -> Result<()>; fn get_version(&self) -> Result<String>; fn unit_exists(&self) -> Result<bool>; } @@ -151,11 +151,10 @@ impl SystemdInterface for DBusClient { } } - fn add_process(&self, pid: i32) -> Result<()> { + fn add_process(&self, pid: i32, subcgroup: &str) -> Result<()> { let proxy = self.build_proxy()?; - proxy - .attach_processes_to_unit(&self.unit_name, "/", &[pid as u32]) + .attach_processes_to_unit(&self.unit_name, subcgroup, &[pid as u32]) .context(format!( "failed to add process into unit {}", self.unit_name diff --git a/src/agent/rustjail/src/cgroups/systemd/manager.rs b/src/agent/rustjail/src/cgroups/systemd/manager.rs index c3158bdf61..6d0408c2ce 100644 --- a/src/agent/rustjail/src/cgroups/systemd/manager.rs +++ b/src/agent/rustjail/src/cgroups/systemd/manager.rs @@ -41,7 +41,8 @@ pub struct Manager { impl CgroupManager for Manager { fn apply(&self, pid: pid_t) -> Result<()> { if self.dbus_client.unit_exists()? { - self.dbus_client.add_process(pid)?; + let subcgroup = self.fs_manager.subcgroup(); + self.dbus_client.add_process(pid, subcgroup)?; } else { self.dbus_client.start_unit( (pid as u32).try_into().unwrap(),