-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
runc-dmz does not play well with selinux #4057
Comments
I discussed this issue with Akihiro in the runc-dmz PR -- there isn't a way to detect whether the exec will fail early enough that we can do something about it ( My original idea was that distributions that ship with restrictive SELinux policies can build Now that I think about it -- is the label of a memfd determined with diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 35f4f5df390d..235b1509d6cb 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -17,6 +17,7 @@ import (
"time"
"github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/selinux/go-selinux"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/execabs"
@@ -514,6 +515,11 @@ func (c *Container) newParentProcess(p *Process) (parentProcess, error) {
if isDmzBinarySafe(c.config) {
dmzExe, err = dmz.Binary(c.stateDir)
if err == nil {
+ // Set the SELinux label on the memfd to make sure we can exec
+ // from the container's label.
+ if err := selinux.SetFileLabel(fmt.Sprintf("/proc/self/fd/%d", dmzExe.Fd()), c.config.ProcessLabel); err != nil {
+ return nil, fmt.Errorf("failed to set SELinux label on runc-dmz binary clone: %w", err)
+ }
// We can use our own executable without cloning if we are using
// runc-dmz.
exePath = "/proc/self/exe" |
Alas it's not working
|
So far the best workaround I came up with is this: diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 35f4f5df..805ac0a0 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -17,6 +17,7 @@ import (
"time"
"github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/selinux/go-selinux"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/execabs"
@@ -457,6 +458,13 @@ func slicesContains[S ~[]E, E comparable](slice S, needle E) bool {
}
func isDmzBinarySafe(c *configs.Config) bool {
+ // SELinux policy can prevent runc to execute the dmz binary. Do not
+ // use dmz in case SELinux is in enforcing mode and the selinux label
+ // is set.
+ if c.ProcessLabel != "" && selinux.EnforceMode() == selinux.Enforcing {
+ 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. Not that I like it (mostly because it looks like an overkill), but it fixes the issue. |
We can't assume users to use distros' packages. |
@kolyshkin Could you submit that patch as a PR? |
Currently I see the following version of container-selinux: I'm assuming the change will be backported to CentOS 9 and 8 and maybe Fedora (or will appear in the next Fedora). Not sure what to do with CentOS 7 though. Disable runc-dmz using a build flag? |
We are still figuring out how to fix this the best way. |
Why are you still supporting RHEL7/Centos7. It no longer gets updates. Only security fixes are backported. |
Users may still install the latest runc from a third party package (until EOL) |
CentOS Linux 7 will reach end of life (EOL) on June 30, 2024. We hope we will release runc 1.2 before that date. We can certainly say "if you're using runc on CentOS 7 with SELinux enabled, compile it with Otherwise it's too much hassle. |
Downstreams often want to provide a single “golden” binary that works on every distro. |
What do you propose? Something like this? Maybe this can be done, but together with a way to avoid this behavior ("selinux works with runc-dmz") which a distro vendor can set. |
SGTM |
Yes. The distro version (kernel version?) can be checked too. |
This code path is also used during |
(status update: still working on this, got distracted by CI failures and other stuff) |
Not entirely; runc is still widely used.
@AkihiroSuda see #4053. |
Fixed in #4053 |
Description
When
.process.selinuxLabel
is set, runc uses it to set the executable context (callsselinux.SetExecLabel
) before we execute the container binary.With the dmz feature (introduced in #3987), we now execute
runc-dmz
(which, in turn, executes the container binary), and we do it with the exec context of the container (selinux.SetExecLabel
call). Alas, the container context does not give us enough permissions to use runc-dmz (see e.g. containers/container-selinux#274).Steps to reproduce the issue
The issue is reproduced on CentOS and Fedora (which has SELinux enabled and in enforcing mode by default) using test cases added in #4053.
Describe the results you received and expected
The issue is reproduced with tests added in #4053. Here's the result:
For CentOS 7:
For CentOS 8/9 and Fedora:
What version of runc are you using?
v1.1.0-785-gd8d576ca
Host OS information
Any recent Fedora or CentOS with SELinux enabled and in enforced mode.
Host kernel information
No response
The text was updated successfully, but these errors were encountered: