integration: Handle user namespace restrictions

User namespace remapping rejects privileged containers and host network
or PID modes, disables containerd snapshotters, and leaves
ping_group_range unchanged in private user namespaces. Tests that assume
rootful daemon behavior therefore fail in userns integration mode.

Skip only the incompatible cases while retaining compatible subtests and
the ip_unprivileged_port_start assertion. Make the NRI writable bind
fixture independent of host and remapped UID ownership by restoring its
write bits after applying the process umask.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski
2026-07-16 13:17:02 +02:00
parent 608b9d32ca
commit 84dd0e86af
7 changed files with 23 additions and 8 deletions

View File

@@ -279,6 +279,7 @@ func TestCreateWithCustomMaskedPaths(t *testing.T) {
for i, tc := range testCases {
t.Run(tc.doc, func(t *testing.T) {
skip.If(t, tc.privileged && testEnv.IsUserNamespace(), "privileged mode is incompatible with user namespaces")
t.Parallel()
// Create the container.
@@ -352,6 +353,7 @@ func TestCreateWithCustomReadonlyPaths(t *testing.T) {
for i, tc := range testCases {
t.Run(tc.doc, func(t *testing.T) {
skip.If(t, tc.privileged && testEnv.IsUserNamespace(), "privileged mode is incompatible with user namespaces")
t.Parallel()
ctr, err := apiClient.ContainerCreate(ctx, client.ContainerCreateOptions{
Config: &container.Config{

View File

@@ -52,6 +52,7 @@ func TestNetworkAliasesAreEmpty(t *testing.T) {
for _, nwMode := range netModes {
t.Run(nwMode, func(t *testing.T) {
skip.If(t, nwMode == "host" && testEnv.IsUserNamespace(), "host network mode is incompatible with user namespaces")
ctr := container.Create(ctx, t, apiClient,
container.WithName("ctr-"+nwMode),
container.WithImage("busybox:latest"),

View File

@@ -15,6 +15,7 @@ import (
func TestPIDModeHost(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, testEnv.IsUserNamespace, "host PID mode is incompatible with user namespaces")
hostPid, err := os.Readlink("/proc/1/ns/pid")
assert.NilError(t, err)

View File

@@ -114,15 +114,17 @@ func TestUnprivilegedPortsAndPing(t *testing.T) {
c.Config.User = "1000:1000"
})
// Check net.ipv4.ping_group_range.
res, err := container.Exec(ctx, apiClient, cID, []string{"cat", "/proc/sys/net/ipv4/ping_group_range"})
assert.NilError(t, err)
assert.Assert(t, is.Len(res.Stderr(), 0))
assert.Equal(t, 0, res.ExitCode)
assert.Equal(t, `0 2147483647`, strings.TrimSpace(res.Stdout()))
if !testEnv.IsUserNamespace() {
// Check net.ipv4.ping_group_range.
res, err := container.Exec(ctx, apiClient, cID, []string{"cat", "/proc/sys/net/ipv4/ping_group_range"})
assert.NilError(t, err)
assert.Assert(t, is.Len(res.Stderr(), 0))
assert.Equal(t, 0, res.ExitCode)
assert.Equal(t, `0 2147483647`, strings.TrimSpace(res.Stdout()))
}
// Check net.ipv4.ip_unprivileged_port_start.
res, err = container.Exec(ctx, apiClient, cID, []string{"cat", "/proc/sys/net/ipv4/ip_unprivileged_port_start"})
res, err := container.Exec(ctx, apiClient, cID, []string{"cat", "/proc/sys/net/ipv4/ip_unprivileged_port_start"})
assert.NilError(t, err)
assert.Assert(t, is.Len(res.Stderr(), 0))
assert.Equal(t, 0, res.ExitCode)

View File

@@ -15,6 +15,7 @@ import (
func TestDefaultStorageDriver(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "Windows does not support running sub-daemons")
skip.If(t, testEnv.IsUserNamespace(), "containerd snapshotters are disabled with user namespace remapping")
t.Setenv("DOCKER_DRIVER", "")
t.Setenv("DOCKER_GRAPHDRIVER", "")
t.Setenv("TEST_INTEGRATION_USE_GRAPHDRIVER", "")
@@ -127,6 +128,8 @@ func TestInspectGraphDriverAPIBC(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
skip.If(t, tc.expContainerdSnapshotter && testEnv.IsUserNamespace(), "containerd snapshotters are disabled with user namespace remapping")
d := daemon.New(t)
defer d.Stop(t)
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false", "--storage-driver="+tc.storageDriver)

View File

@@ -25,6 +25,7 @@ func TestMigrateNativeSnapshotter(t *testing.T) {
func testMigrateSnapshotter(t *testing.T, graphdriver, snapshotter string) {
skip.If(t, runtime.GOOS != "linux")
skip.If(t, testEnv.IsUserNamespace(), "containerd snapshotters are disabled with user namespace remapping")
t.Setenv("DOCKER_MIGRATE_SNAPSHOTTER_THRESHOLD", "200M")
t.Setenv("DOCKER_DRIVER", "")

View File

@@ -158,7 +158,12 @@ func TestNRIContainerCreateAddMount(t *testing.T) {
// Create and populate a directory for containers to mount.
dirToMount := t.TempDir()
if err := os.WriteFile(filepath.Join(dirToMount, "testfile.txt"), []byte("hello\n"), 0o644); err != nil {
testFile := filepath.Join(dirToMount, "testfile.txt")
if err := os.WriteFile(testFile, []byte("hello\n"), 0o666); err != nil {
assert.NilError(t, err)
}
// The process umask may remove write bits needed by remapped container root.
if err := os.Chmod(testFile, 0o666); err != nil {
assert.NilError(t, err)
}
const (