diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index e10ca2332ff..ae5d4fb46b4 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -524,6 +524,7 @@ func (c *Container) newParentProcess(p *Process) (parentProcess, error) { // runc-dmz. exePath = "/proc/self/exe" p.clonedExes = append(p.clonedExes, dmzExe) + logrus.Debug("runc-dmz: using runc-dmz") // used for tests } else if errors.Is(err, dmz.ErrNoDmzBinary) { logrus.Debug("runc-dmz binary not embedded in runc binary, falling back to /proc/self/exe clone") } else if err != nil { @@ -542,6 +543,7 @@ func (c *Container) newParentProcess(p *Process) (parentProcess, error) { } exePath = "/proc/self/fd/" + strconv.Itoa(int(safeExe.Fd())) p.clonedExes = append(p.clonedExes, safeExe) + logrus.Debug("runc-dmz: using /proc/self/exe clone") // used for tests } // Just to make sure we don't run without protection. if dmzExe == nil && safeExe == nil { diff --git a/tests/integration/helpers.bash b/tests/integration/helpers.bash index cd08fb2459f..7e6399a47b8 100755 --- a/tests/integration/helpers.bash +++ b/tests/integration/helpers.bash @@ -646,12 +646,16 @@ function teardown_bundle() { remove_parent } -function requires_kernel() { +function is_kernel_gte() { local major_required minor_required major_required=$(echo "$1" | cut -d. -f1) minor_required=$(echo "$1" | cut -d. -f2) - if [[ "$KERNEL_MAJOR" -lt $major_required || ("$KERNEL_MAJOR" -eq $major_required && "$KERNEL_MINOR" -lt $minor_required) ]]; then - skip "requires kernel $1" + [[ "$KERNEL_MAJOR" -gt $major_required || ("$KERNEL_MAJOR" -eq $major_required && "$KERNEL_MINOR" -ge $minor_required) ]] +} + +function requires_kernel() { + if ! is_kernel_gte "$@"; then + skip "requires kernel >= $1" fi } diff --git a/tests/integration/run.bats b/tests/integration/run.bats index 9f1f1d8bc74..baf91fb00cd 100644 --- a/tests/integration/run.bats +++ b/tests/integration/run.bats @@ -126,3 +126,37 @@ function teardown() { [ "$status" -eq 0 ] [ "$output" = "410" ] } + +@test "runc run [runc-dmz]" { + runc --debug run test_hello + [ "$status" -eq 0 ] + [[ "$output" = *"Hello World"* ]] + # We use runc-dmz if we can. + [[ "$output" = *"runc-dmz: using runc-dmz"* ]] +} + +@test "runc run [cap_sys_ptrace -> /proc/self/exe clone]" { + # Add CAP_SYS_PTRACE to the bounding set, the minimum needed to indicate a + # container process _could_ get CAP_SYS_PTRACE. + update_config '.process.capabilities.bounding += ["CAP_SYS_PTRACE"]' + + runc --debug run test_hello + [ "$status" -eq 0 ] + [[ "$output" = *"Hello World"* ]] + if [ "$EUID" -ne 0 ] && is_kernel_gte 4.10; then + # For Linux 4.10 and later, rootless containers will use runc-dmz + # because they are running in a user namespace. See isDmzBinarySafe(). + [[ "$output" = *"runc-dmz: using runc-dmz"* ]] + else + # If the container has CAP_SYS_PTRACE and is not rootless, we use + # /proc/self/exe cloning. + [[ "$output" = *"runc-dmz: using /proc/self/exe clone"* ]] + fi +} + +@test "RUNC_DMZ=legacy runc run [/proc/self/exe clone]" { + RUNC_DMZ=legacy runc --debug run test_hello + [ "$status" -eq 0 ] + [[ "$output" = *"Hello World"* ]] + [[ "$output" = *"runc-dmz: using /proc/self/exe clone"* ]] +} diff --git a/tests/integration/seccomp-notify-compat.bats b/tests/integration/seccomp-notify-compat.bats index 8d663edda51..6ca3449bffa 100644 --- a/tests/integration/seccomp-notify-compat.bats +++ b/tests/integration/seccomp-notify-compat.bats @@ -3,8 +3,8 @@ load helpers function setup() { - if [[ "$KERNEL_MAJOR" -gt 5 || ("$KERNEL_MAJOR" -eq 5 && "$KERNEL_MINOR" -ge 6) ]]; then - skip "requires kernel less than 5.6" + if is_kernel_gte 5.6; then + skip "requires kernel < 5.6" fi requires arch_x86_64