Skip to content

Commit

Permalink
Add runc_dmz_selinux_compat build tag
Browse files Browse the repository at this point in the history
Add a new build tag, runc_dmz_selinux_compat, that enables a workaround
for dmz vs selinux. Document it in the top-level and libct/dmz READMEs.

Use the new tag in our CI builds for Fedora, CentOS 7, and CentOS
Stream 8.

Do not use it for CS9 since it already has container-selinux 2.224.0
available.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
  • Loading branch information
kolyshkin committed Oct 24, 2023
1 parent c9e8e66 commit fa1882c
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 1 deletion.
10 changes: 9 additions & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ task:
vagrant up --no-tty || vagrant up --no-tty
mkdir -p -m 0700 /root/.ssh
vagrant ssh-config >> /root/.ssh/config
# TODO: drop this once Fedora has container-selinux >= 2.224.0 (F39?)
echo 'EXTRA_BUILDTAGS=runc_dmz_selinux_compat' >> /root/.ssh/environment
guest_info_script: |
ssh default 'sh -exc "uname -a && systemctl --version && df -T && cat /etc/os-release && go version && sestatus"'
ssh default 'sh -exc "uname -a && systemctl --version && df -T && cat /etc/os-release && go version && sestatus && rpm -q container-selinux"'
check_config_script: |
ssh default /vagrant/script/check-config.sh
unit_tests_script: |
Expand Down Expand Up @@ -159,6 +161,12 @@ task:
echo -e "Host localhost\n\tStrictHostKeyChecking no\t\nIdentityFile /root/.ssh/id_ed25519\n" >> /root/.ssh/config
sed -e "s,PermitRootLogin.*,PermitRootLogin prohibit-password,g" -i /etc/ssh/sshd_config
systemctl restart sshd
# TODO: remove centos-stream-8 once it has container-selinux >= 2.224.0.
case $DISTRO in
centos-7|centos-stream-8)
echo 'EXTRA_BUILDTAGS=runc_dmz_selinux_compat' >> /root/.ssh/environment
;;
esac
host_info_script: |
uname -a
# -----
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,15 @@ make BUILDTAGS=""
|---------------|---------------------------------------|--------------------|---------------------|
| `seccomp` | Syscall filtering using `libseccomp`. | yes | `libseccomp` |
| `!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 ||
| `runc_dmz_selinux_compat` | Enables a SELinux workaround for older distributions. See [dmz README] for details. | no ||

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

[contrib-memfd-bind]: /contrib/cmd/memfd-bind/README.md
[dmz README]: /libcontainer/dmz/README.md

### Running the test suite

Expand Down
4 changes: 4 additions & 0 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,10 @@ func slicesContains[S ~[]E, E comparable](slice S, needle E) bool {
}

func isDmzBinarySafe(c *configs.Config) bool {
if !dmz.WorksWithSELinux(c) {
return false
}

// Because we set the dumpable flag in nsexec, the only time when it is
// unsafe to use runc-dmz is when the container process would be able to
// race against "runc init" and bypass the ptrace_may_access() checks.
Expand Down
15 changes: 15 additions & 0 deletions libcontainer/dmz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,19 @@ It also support all the architectures we support in runc.

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

## SELinux compatibility issue and a workaround

Older SELinux policy can prevent runc to execute the dmz binary. The issue is
fixed in [container-selinux v2.224.0].

Distributions that do not have the above fix have to build runc with the
`runc_dmz_selinux_compat` build flag. If built with this flag, runc disables
dmz during runtime if SELinux is in enforced mode and the container SELinux
label is set.

The alternative is to use [memfd-bind].
>>>>>>> 4a472aeb (Workaround for dmz-vs-selinux issue)
[nolibc-upstream]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/include/nolibc?h=v6.6-rc3
[container-selinux v2.224.0]: https://github.com/containers/container-selinux/releases/tag/v2.224.0
[memfd-bind]: /contrib/cmd/memfd-bind/README.md
10 changes: 10 additions & 0 deletions libcontainer/dmz/selinux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//go:build !runc_dmz_selinux_compat || !linux

package dmz

import "github.com/opencontainers/runc/libcontainer/configs"

// WorksWithSELinux tells whether runc-dmz can work with SELinux.
func WorksWithSELinux(*configs.Config) bool {
return true
}
25 changes: 25 additions & 0 deletions libcontainer/dmz/selinux_compat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//go:build linux && runc_dmz_selinux_compat

package dmz

import (
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/selinux/go-selinux"
)

// WorksWithSELinux tells whether runc-dmz can work with SELinux.
//
// Older SELinux policy can prevent runc to execute the dmz binary. The issue is
// fixed in container-selinux >= 2.224.0:
//
// - https://github.com/containers/container-selinux/issues/274
// - https://github.com/containers/container-selinux/pull/280
//
// Alas, there is is no easy way to do a runtime check if dmz works with
// SELinux, so distributions that do not have the above fix have to build runc
// with runc_dmz_selinux_compat build flag. If the flag is set, the code below
// is used, which results in disabling dmz in case container SELinux label is
// set and the selinux is in enforced mode.
func WorksWithSELinux(c *configs.Config) bool {
return c.ProcessLabel == "" || selinux.EnforceMode() != selinux.Enforcing
}

0 comments on commit fa1882c

Please sign in to comment.