diff --git a/daemon/oci_linux.go b/daemon/oci_linux.go index f5883ef699..5136b4097c 100644 --- a/daemon/oci_linux.go +++ b/daemon/oci_linux.go @@ -770,7 +770,8 @@ func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts { // joining an existing namespace, only if we create a new net namespace. if c.HostConfig.NetworkMode.IsPrivate() { // We cannot set up ping socket support in a user namespace - if !c.HostConfig.UsernsMode.IsPrivate() && sysctlExists("net.ipv4.ping_group_range") { + userNS := daemon.configStore.RemappedRoot != "" && c.HostConfig.UsernsMode.IsPrivate() + if !userNS && !userns.RunningInUserNS() && sysctlExists("net.ipv4.ping_group_range") { // allow unprivileged ICMP echo sockets without CAP_NET_RAW s.Linux.Sysctl["net.ipv4.ping_group_range"] = "0 2147483647" } diff --git a/daemon/oci_linux_test.go b/daemon/oci_linux_test.go index 8e0d7c77a7..6e60d07f7c 100644 --- a/daemon/oci_linux_test.go +++ b/daemon/oci_linux_test.go @@ -119,7 +119,6 @@ func TestSysctlOverride(t *testing.T) { HostConfig: &containertypes.HostConfig{ NetworkMode: "bridge", Sysctls: map[string]string{}, - UsernsMode: "host", }, } d := setupFakeDaemon(t, c) @@ -147,6 +146,20 @@ func TestSysctlOverride(t *testing.T) { assert.Equal(t, s.Hostname, "foobar") assert.Equal(t, s.Linux.Sysctl["kernel.domainname"], c.HostConfig.Sysctls["kernel.domainname"]) assert.Equal(t, s.Linux.Sysctl["net.ipv4.ip_unprivileged_port_start"], c.HostConfig.Sysctls["net.ipv4.ip_unprivileged_port_start"]) + + // Ensure the ping_group_range is not set on a daemon with user-namespaces enabled + d.configStore.RemappedRoot = "dummy:dummy" + s, err = d.createSpec(c) + assert.NilError(t, err) + _, ok := s.Linux.Sysctl["net.ipv4.ping_group_range"] + assert.Assert(t, !ok) + + // Ensure the ping_group_range is set on a container in "host" userns mode + // on a daemon with user-namespaces enabled + c.HostConfig.UsernsMode = "host" + s, err = d.createSpec(c) + assert.NilError(t, err) + assert.Equal(t, s.Linux.Sysctl["net.ipv4.ping_group_range"], "0 2147483647") } // TestSysctlOverrideHost ensures that any implicit network sysctls are not set @@ -158,7 +171,6 @@ func TestSysctlOverrideHost(t *testing.T) { HostConfig: &containertypes.HostConfig{ NetworkMode: "host", Sysctls: map[string]string{}, - UsernsMode: "host", }, } d := setupFakeDaemon(t, c) diff --git a/integration/container/run_linux_test.go b/integration/container/run_linux_test.go index 9bff9b5a8e..a8e47e9f9e 100644 --- a/integration/container/run_linux_test.go +++ b/integration/container/run_linux_test.go @@ -99,3 +99,32 @@ func TestHostnameDnsResolution(t *testing.T) { assert.Check(t, is.Equal("", res.Stderr())) assert.Equal(t, 0, res.ExitCode) } + +func TestUnprivilegedPortsAndPing(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + skip.If(t, testEnv.IsRootless, "rootless mode doesn't support setting net.ipv4.ping_group_range and net.ipv4.ip_unprivileged_port_start") + + defer setupTest(t)() + client := testEnv.APIClient() + ctx := context.Background() + + cID := container.Run(ctx, t, client, func(c *container.TestContainerConfig) { + c.Config.User = "1000:1000" + }) + + poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond)) + + // Check net.ipv4.ping_group_range. + res, err := container.Exec(ctx, client, 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, client, 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) + assert.Equal(t, "0", strings.TrimSpace(res.Stdout())) +}