Skip to content

Commit

Permalink
daemon.WithCommonOptions() fix detection of user-namespaces
Browse files Browse the repository at this point in the history
Commit dae652e added support for non-privileged
containers to use ICMP_PROTO (used for `ping`). This option cannot be set for
containers that have user-namespaces enabled.

However, the detection looks to be incorrect; HostConfig.UsernsMode was added
in 6993e89 / ee21838,
and the property only has meaning if the daemon is running with user namespaces
enabled. In other situations, the property has no meaning.
As a result of the above, the sysctl would only be set for containers running
with UsernsMode=host on a daemon running with user-namespaces enabled.

This patch adds a check if the daemon has user-namespaces enabled (RemappedRoot
having a non-empty value), or if the daemon is running inside a user namespace
(e.g. rootless mode) to fix the detection.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit a826ca3)

---
The cherry-pick was almost clean but `userns.RunningInUserNS()` -> `sys.RunningInUserNS()`.

Fix docker/buildx issue 561
---

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
  • Loading branch information
thaJeztah authored and AkihiroSuda committed Dec 15, 2021
1 parent 459d0df commit 660b996
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 3 deletions.
3 changes: 2 additions & 1 deletion daemon/oci_linux.go
Expand Up @@ -767,7 +767,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 && !sys.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"
}
Expand Down
16 changes: 14 additions & 2 deletions daemon/oci_linux_test.go
Expand Up @@ -120,7 +120,6 @@ func TestSysctlOverride(t *testing.T) {
HostConfig: &containertypes.HostConfig{
NetworkMode: "bridge",
Sysctls: map[string]string{},
UsernsMode: "host",
},
}
d := setupFakeDaemon(t, c)
Expand Down Expand Up @@ -148,6 +147,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
Expand All @@ -159,7 +172,6 @@ func TestSysctlOverrideHost(t *testing.T) {
HostConfig: &containertypes.HostConfig{
NetworkMode: "host",
Sysctls: map[string]string{},
UsernsMode: "host",
},
}
d := setupFakeDaemon(t, c)
Expand Down
29 changes: 29 additions & 0 deletions integration/container/run_linux_test.go
Expand Up @@ -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()))
}

0 comments on commit 660b996

Please sign in to comment.