Skip to content

Commit 1f9d9a3

Browse files
committed
merge #4053 into opencontainers/runc:main
Kir Kolyshkin (3): Add dmz-vs-selinux kludge and a way to disable it README: fix reference to memfd-bind tests/int: add selinux test case LGTMs: AkihiroSuda cyphar
2 parents da44f69 + 87bd784 commit 1f9d9a3

File tree

8 files changed

+134
-4
lines changed

8 files changed

+134
-4
lines changed

.cirrus.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ task:
5757
mkdir -p -m 0700 /root/.ssh
5858
vagrant ssh-config >> /root/.ssh/config
5959
guest_info_script: |
60-
ssh default 'sh -exc "uname -a && systemctl --version && df -T && cat /etc/os-release && go version"'
60+
ssh default 'sh -exc "uname -a && systemctl --version && df -T && cat /etc/os-release && go version && sestatus && rpm -q container-selinux"'
6161
check_config_script: |
6262
ssh default /vagrant/script/check-config.sh
6363
unit_tests_script: |
@@ -79,7 +79,7 @@ task:
7979
CIRRUS_WORKING_DIR: /home/runc
8080
GO_VERSION: "1.20"
8181
BATS_VERSION: "v1.9.0"
82-
RPMS: gcc git iptables jq glibc-static libseccomp-devel make criu fuse-sshfs
82+
RPMS: gcc git iptables jq glibc-static libseccomp-devel make criu fuse-sshfs container-selinux
8383
# yamllint disable rule:key-duplicates
8484
matrix:
8585
DISTRO: centos-7
@@ -159,6 +159,17 @@ task:
159159
echo -e "Host localhost\n\tStrictHostKeyChecking no\t\nIdentityFile /root/.ssh/id_ed25519\n" >> /root/.ssh/config
160160
sed -e "s,PermitRootLogin.*,PermitRootLogin prohibit-password,g" -i /etc/ssh/sshd_config
161161
systemctl restart sshd
162+
163+
# Disable the dmz-vs-selinux workaround for distros that have container-selinux >= 2.224.0.
164+
case $DISTRO in
165+
# TODO: remove centos-stream-8.
166+
centos-7|centos-stream-8)
167+
# Do nothing.
168+
;;
169+
*)
170+
echo 'export EXTRA_BUILDTAGS=runc_dmz_selinux_nocompat' >> /root/.bashrc
171+
;;
172+
esac
162173
host_info_script: |
163174
uname -a
164175
# -----
@@ -170,6 +181,8 @@ task:
170181
# -----
171182
df -T
172183
# -----
184+
sestatus
185+
# -----
173186
cat /proc/cpuinfo
174187
check_config_script: |
175188
/home/runc/script/check-config.sh

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,15 @@ make BUILDTAGS=""
6969
|---------------|---------------------------------------|--------------------|---------------------|
7070
| `seccomp` | Syscall filtering using `libseccomp`. | yes | `libseccomp` |
7171
| `!runc_nodmz` | Reduce memory usage for CVE-2019-5736 protection by using a small C binary, [see `memfd-bind` for more details][contrib-memfd-bind]. `runc_nodmz` disables this feature and causes runc to use a different protection mechanism which will further increases memory usage temporarily during container startup. This feature can also be disabled at runtime by setting the `RUNC_DMZ=legacy` environment variable. | yes ||
72+
| `runc_dmz_selinux_nocompat` | Disables a SELinux DMZ workaround (new distros should set this). See [dmz README] for details. | no ||
7273

7374
The following build tags were used earlier, but are now obsoleted:
7475
- **nokmem** (since runc v1.0.0-rc94 kernel memory settings are ignored)
7576
- **apparmor** (since runc v1.0.0-rc93 the feature is always enabled)
7677
- **selinux** (since runc v1.0.0-rc93 the feature is always enabled)
7778

78-
[contrib-memfd-bind]: /contrib/memfd-bind/README.md
79+
[contrib-memfd-bind]: /contrib/cmd/memfd-bind/README.md
80+
[dmz README]: /libcontainer/dmz/README.md
7981

8082
### Running the test suite
8183

Vagrantfile.fedora

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,18 @@ Vagrant.configure("2") do |config|
2323
cat << EOF | dnf -y --exclude=kernel,kernel-core shell && break
2424
config install_weak_deps false
2525
update
26-
install iptables gcc golang-go make glibc-static libseccomp-devel bats jq git-core criu fuse-sshfs
26+
install iptables gcc golang-go make glibc-static libseccomp-devel bats jq git-core criu fuse-sshfs container-selinux
2727
ts run
2828
EOF
2929
done
3030
dnf clean all
3131
32+
# To avoid "avc: denied { nosuid_transition }" from SELinux as we run tests on /tmp.
33+
mount -o remount,suid /tmp
34+
35+
# Disable selinux-vs-dmz workaround as Fedora doesn't need it.
36+
echo 'export EXTRA_BUILDTAGS=runc_dmz_selinux_nocompat' >> /root/.bashrc
37+
3238
# Prevent the "fatal: unsafe repository" git complain during build.
3339
git config --global --add safe.directory /vagrant
3440

libcontainer/container_linux.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,10 @@ func slicesContains[S ~[]E, E comparable](slice S, needle E) bool {
457457
}
458458

459459
func isDmzBinarySafe(c *configs.Config) bool {
460+
if !dmz.WorksWithSELinux(c) {
461+
return false
462+
}
463+
460464
// Because we set the dumpable flag in nsexec, the only time when it is
461465
// unsafe to use runc-dmz is when the container process would be able to
462466
// race against "runc init" and bypass the ptrace_may_access() checks.

libcontainer/dmz/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,16 @@ It also support all the architectures we support in runc.
1515

1616
If the GOARCH we use for compiling doesn't support nolibc, it fallbacks to using the C stdlib.
1717

18+
## SELinux compatibility issue and a workaround
19+
20+
Older SELinux policy can prevent runc to execute the dmz binary. The issue is
21+
fixed in [container-selinux v2.224.0]. Yet, some older distributions may not
22+
have the fix, so runc has a runtime workaround of disabling dmz if it finds
23+
that SELinux is in enforced mode and the container SELinux label is set.
24+
25+
Distributions that have a sufficiently new container-selinux can disable the
26+
workaround by building runc with the `runc_dmz_selinux_nocompat` build flag,
27+
essentially allowing dmz to be used together with SELinux.
28+
1829
[nolibc-upstream]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/include/nolibc?h=v6.6-rc3
30+
[container-selinux v2.224.0]: https://github.com/containers/container-selinux/releases/tag/v2.224.0

libcontainer/dmz/selinux.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//go:build runc_dmz_selinux_nocompat || !linux
2+
3+
package dmz
4+
5+
import "github.com/opencontainers/runc/libcontainer/configs"
6+
7+
// WorksWithSELinux tells whether runc-dmz can work with SELinux.
8+
func WorksWithSELinux(*configs.Config) bool {
9+
return true
10+
}

libcontainer/dmz/selinux_compat.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//go:build linux && !runc_dmz_selinux_nocompat
2+
3+
package dmz
4+
5+
import (
6+
"github.com/opencontainers/runc/libcontainer/configs"
7+
"github.com/opencontainers/selinux/go-selinux"
8+
)
9+
10+
// WorksWithSELinux tells whether runc-dmz can work with SELinux.
11+
//
12+
// Older SELinux policy can prevent runc to execute the dmz binary. The issue is
13+
// fixed in container-selinux >= 2.224.0:
14+
//
15+
// - https://github.com/containers/container-selinux/issues/274
16+
// - https://github.com/containers/container-selinux/pull/280
17+
//
18+
// Alas, there is is no easy way to do a runtime check if dmz works with
19+
// SELinux, so the below workaround is enabled by default. It results in
20+
// disabling dmz in case container SELinux label is set and the selinux is in
21+
// enforced mode.
22+
//
23+
// Newer distributions that have the sufficiently new container-selinux version
24+
// can build runc with runc_dmz_selinux_nocompat build flag to disable this
25+
// workaround (essentially allowing dmz to be used together with SELinux).
26+
func WorksWithSELinux(c *configs.Config) bool {
27+
return c.ProcessLabel == "" || selinux.EnforceMode() != selinux.Enforcing
28+
}

tests/integration/selinux.bats

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env bats
2+
3+
load helpers
4+
5+
function setup() {
6+
requires root # for chcon
7+
if ! selinuxenabled; then
8+
skip "requires SELinux enabled and in enforcing mode"
9+
fi
10+
11+
setup_busybox
12+
13+
# Use a copy of runc binary with proper selinux label set.
14+
cp "$RUNC" .
15+
export RUNC="$PWD/runc"
16+
chcon -u system_u -r object_r -t container_runtime_exec_t "$RUNC"
17+
18+
# Label container fs.
19+
chcon -u system_u -r object_r -t container_file_t -R rootfs
20+
21+
# Save the start date and time for ausearch.
22+
AU_DD="$(date +%x)"
23+
AU_TT="$(date +%H:%M:%S)"
24+
}
25+
26+
function teardown() {
27+
teardown_bundle
28+
# Show any avc denials.
29+
if [[ -v AU_DD && -v AU_TT ]] && command -v ausearch &>/dev/null; then
30+
ausearch -ts "$AU_DD" "$AU_TT" -i -m avc || true
31+
fi
32+
}
33+
34+
# Baseline test, to check that runc works with selinux enabled.
35+
@test "runc run (no selinux label)" {
36+
update_config ' .process.args = ["/bin/true"]'
37+
runc run tst
38+
[ "$status" -eq 0 ]
39+
}
40+
41+
# https://github.com/opencontainers/runc/issues/4057
42+
@test "runc run (custom selinux label)" {
43+
update_config ' .process.selinuxLabel |= "system_u:system_r:container_t:s0:c4,c5"
44+
| .process.args = ["/bin/true"]'
45+
runc run tst
46+
[ "$status" -eq 0 ]
47+
}
48+
49+
@test "runc run (custom selinux label, RUNC_DMZ=legacy)" {
50+
export RUNC_DMZ=legacy
51+
update_config ' .process.selinuxLabel |= "system_u:system_r:container_t:s0:c4,c5"
52+
| .process.args = ["/bin/true"]'
53+
runc run tst
54+
[ "$status" -eq 0 ]
55+
}

0 commit comments

Comments
 (0)