overlay2: Allow rootless mode with SELinux enabled

Rootless dockerd refused to use overlay2 whenever SELinux was enabled
on the host, forcing users onto fuse-overlayfs:

```
overlay is not supported for Rootless with SELinux
```

The check was added for Fedora 34, where rootless overlayfs on kernel
5.11 hit SELinux denials.
That no longer happens on current hosts such as Fedora 41.
The containerd overlayfs snapshotter never had an equivalent check and
already runs natively in rootless mode with SELinux enforcing.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski committed 2026-10-28 13:03:45 +01:00
1 parent a7580523ff
commit 1b1e60de6a
5 files changed
+4 -47

No files matched your search

@@ -38,16 +38,6 @@ func ErrDTypeNotSupported(driver, backingFs string) error {
// checkMultipleLowers parameter enables check for multiple lowerdirs,
// which is required for the overlay2 driver.
func SupportsOverlay(d string, checkMultipleLowers bool) error {
// We can't rely on go-selinux.GetEnabled() to detect whether SELinux is enabled,
// because RootlessKit doesn't mount /sys/fs/selinux in the child: https://github.com/rootless-containers/rootlesskit/issues/94
// So we check $_DOCKERD_ROOTLESS_SELINUX, which is set by dockerd-rootless.sh .
if os.Getenv("_DOCKERD_ROOTLESS_SELINUX") == "1" {
// Kernel 5.11 introduced support for rootless overlayfs, but incompatible with SELinux,
// so fallback to fuse-overlayfs.
// https://github.com/moby/moby/issues/42333
return errors.New("overlay is not supported for Rootless with SELinux")
}
td, err := os.MkdirTemp(d, "check-overlayfs-support")
if err != nil {
return err
+1 -1
View File
@@ -241,7 +241,7 @@ additional daemons and modify host networking and other system configuration.
For rootless coverage, add `DOCKER_ROOTLESS=1` to the command. The test runner
still runs as root and starts the rootless daemons as `unprivilegeduser`, which
the provisioning script creates. Use `DOCKER_GRAPHDRIVER=fuse-overlayfs` when
SELinux is enabled or the kernel predates 5.11. Reports and daemon logs are
the kernel predates 5.11. Reports and daemon logs are
written under `bundles/test-integration/`.
## Test the Windows binary against a Linux daemon
+2 -7
View File
@@ -40,12 +40,6 @@ func TestGraphDriverPersistence(t *testing.T) {
t.Setenv("DOCKER_GRAPHDRIVER", "")
t.Setenv("TEST_INTEGRATION_USE_GRAPHDRIVER", "")
graphdriver := "overlay2"
// overlay2 doesn't work rootless with SELinux enforcing; use fuse-overlayfs instead.
if testEnv.IsRootless() && testEnv.IsSELinuxEnforcing() {
graphdriver = "fuse-overlayfs"
}
ctx := testutil.StartSpan(baseContext, t)
// Phase 1: Start daemon with explicit graphdriver (overlay2)
@@ -55,7 +49,8 @@ func TestGraphDriverPersistence(t *testing.T) {
})
const testImage = "busybox:latest"
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false", "--storage-driver="+graphdriver)
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false", "--storage-driver=overlay2")
c := d.NewClientT(t)
// Verify we're using graphdriver
+1 -14
View File
@@ -16,14 +16,7 @@ import (
)
func TestMigrateOverlaySnapshotter(t *testing.T) {
graphdriver := "overlay2"
snapshotter := "overlayfs"
// overlay2 doesn't work rootless with SELinux enforcing; use fuse-overlayfs instead.
if testEnv.IsRootless() && testEnv.IsSELinuxEnforcing() {
graphdriver = "fuse-overlayfs"
snapshotter = "fuse-overlayfs"
}
testMigrateSnapshotter(t, graphdriver, snapshotter)
testMigrateSnapshotter(t, "overlay2", "overlayfs")
}
func TestMigrateNativeSnapshotter(t *testing.T) {
@@ -109,12 +102,6 @@ func TestMigrateSaveLoad(t *testing.T) {
)
defer d.Stop(t)
// overlay2 doesn't work rootless with SELinux enforcing; use fuse-overlayfs instead.
if testEnv.IsRootless() && testEnv.IsSELinuxEnforcing() {
graphdriver = "fuse-overlayfs"
snapshotter = "fuse-overlayfs"
}
d.Start(t, "--iptables=false", "--ip6tables=false", "-s", graphdriver)
info := d.Info(t)
id := info.ID
@@ -221,21 +221,6 @@ func (e *Execution) HasExistingImage(t testing.TB, reference string) bool {
return len(imageList.Items) > 0
}
// IsSELinuxEnforcing returns true if SELinux is enabled and running in enforcing mode.
// Returns false on non-Linux systems or if SELinux is not available or not enabled.
func (e *Execution) IsSELinuxEnforcing() bool {
if runtime.GOOS != "linux" {
return false
}
data, err := os.ReadFile("/sys/fs/selinux/enforce")
if err != nil {
return false
}
return strings.TrimSpace(string(data)) == "1"
}
// IsKernelModuleLoadable returns whether the given kernel module is loadable.
// Returns true when the module is already loaded or built-in into the kernel.
func (e *Execution) IsKernelModuleLoadable(module string) bool {