a2db2f
From 204c673cced91b03aa337c804ab8b31a452c6777 Mon Sep 17 00:00:00 2001
a2db2f
From: Kir Kolyshkin <kolyshkin@gmail.com>
a2db2f
Date: Wed, 10 Aug 2022 17:09:23 -0700
a2db2f
Subject: [PATCH] [1.1] fix failed exec after systemctl daemon-reload
a2db2f
a2db2f
A regression reported for runc v1.1.3 says that "runc exec -t" fails
a2db2f
after doing "systemctl daemon-reload":
a2db2f
a2db2f
> exec failed: unable to start container process: open /dev/pts/0: operation not permitted: unknown
a2db2f
a2db2f
Apparently, with commit 7219387eb7db69b we are no longer adding
a2db2f
"DeviceAllow=char-pts rwm" rule (because os.Stat("char-pts") returns
a2db2f
ENOENT).
a2db2f
a2db2f
The bug can only be seen after "systemctl daemon-reload" because runc
a2db2f
also applies the same rules manually (by writing to devices.allow for
a2db2f
cgroup v1), and apparently reloading systemd leads to re-applying the
a2db2f
rules that systemd has (thus removing the char-pts access).
a2db2f
a2db2f
The fix is to do os.Stat only for "/dev" paths.
a2db2f
a2db2f
Also, emit a warning that the path was skipped. Since the original idea
a2db2f
was to emit less warnings, demote the level to debug.
a2db2f
a2db2f
Note this also fixes the issue of not adding "m" permission for block-*
a2db2f
and char-* devices.
a2db2f
a2db2f
A test case is added, which reliably fails before the fix
a2db2f
on both cgroup v1 and v2.
a2db2f
a2db2f
This is a backport of commit 58b1374f0ad98cc9390adc43dc22ddbb4f84d72e
a2db2f
to release-1.1 branch.
a2db2f
a2db2f
Fixes: https://github.com/opencontainers/runc/issues/3551
a2db2f
Fixes: 7219387eb7db69b4dae740c9d37d973d9a735801
a2db2f
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
a2db2f
---
a2db2f
 libcontainer/cgroups/systemd/common.go | 16 +++++++++-------
a2db2f
 tests/integration/dev.bats             | 16 ++++++++++++++++
a2db2f
 2 files changed, 25 insertions(+), 7 deletions(-)
a2db2f
a2db2f
diff --git a/libcontainer/cgroups/systemd/common.go b/libcontainer/cgroups/systemd/common.go
a2db2f
index 5a68a3cf39..45744c15c0 100644
a2db2f
--- a/libcontainer/cgroups/systemd/common.go
a2db2f
+++ b/libcontainer/cgroups/systemd/common.go
a2db2f
@@ -288,14 +288,16 @@ func generateDeviceProperties(r *configs.Resources) ([]systemdDbus.Property, err
a2db2f
 			case devices.CharDevice:
a2db2f
 				entry.Path = fmt.Sprintf("/dev/char/%d:%d", rule.Major, rule.Minor)
a2db2f
 			}
a2db2f
+			// systemd will issue a warning if the path we give here doesn't exist.
a2db2f
+			// Since all of this logic is best-effort anyway (we manually set these
a2db2f
+			// rules separately to systemd) we can safely skip entries that don't
a2db2f
+			// have a corresponding path.
a2db2f
+			if _, err := os.Stat(entry.Path); err != nil {
a2db2f
+				logrus.Debugf("skipping device %s for systemd: %s", entry.Path, err)
a2db2f
+				continue
a2db2f
+			}
a2db2f
 		}
a2db2f
-		// systemd will issue a warning if the path we give here doesn't exist.
a2db2f
-		// Since all of this logic is best-effort anyway (we manually set these
a2db2f
-		// rules separately to systemd) we can safely skip entries that don't
a2db2f
-		// have a corresponding path.
a2db2f
-		if _, err := os.Stat(entry.Path); err == nil {
a2db2f
-			deviceAllowList = append(deviceAllowList, entry)
a2db2f
-		}
a2db2f
+		deviceAllowList = append(deviceAllowList, entry)
a2db2f
 	}
a2db2f
 
a2db2f
 	properties = append(properties, newProp("DeviceAllow", deviceAllowList))
a2db2f
diff --git a/tests/integration/dev.bats b/tests/integration/dev.bats
a2db2f
index 01f6778598..243315717a 100644
a2db2f
--- a/tests/integration/dev.bats
a2db2f
+++ b/tests/integration/dev.bats
a2db2f
@@ -128,3 +128,19 @@ function teardown() {
a2db2f
 	runc exec test_allow_block sh -c 'fdisk -l '"$device"''
a2db2f
 	[ "$status" -eq 0 ]
a2db2f
 }
a2db2f
+
a2db2f
+# https://github.com/opencontainers/runc/issues/3551
a2db2f
+@test "runc exec vs systemctl daemon-reload" {
a2db2f
+	requires systemd root
a2db2f
+
a2db2f
+	runc run -d --console-socket "$CONSOLE_SOCKET" test_exec
a2db2f
+	[ "$status" -eq 0 ]
a2db2f
+
a2db2f
+	runc exec -t test_exec sh -c "ls -l /proc/self/fd/0; echo 123"
a2db2f
+	[ "$status" -eq 0 ]
a2db2f
+
a2db2f
+	systemctl daemon-reload
a2db2f
+
a2db2f
+	runc exec -t test_exec sh -c "ls -l /proc/self/fd/0; echo 123"
a2db2f
+	[ "$status" -eq 0 ]
a2db2f
+}