Skip to content

Commit a826ca3

Browse files
committed
daemon.WithCommonOptions() fix detection of user-namespaces
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 <[email protected]>
1 parent 8684f48 commit a826ca3

3 files changed

Lines changed: 45 additions & 3 deletions

File tree

daemon/oci_linux.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,8 @@ func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts {
770770
// joining an existing namespace, only if we create a new net namespace.
771771
if c.HostConfig.NetworkMode.IsPrivate() {
772772
// We cannot set up ping socket support in a user namespace
773-
if !c.HostConfig.UsernsMode.IsPrivate() && sysctlExists("net.ipv4.ping_group_range") {
773+
userNS := daemon.configStore.RemappedRoot != "" && c.HostConfig.UsernsMode.IsPrivate()
774+
if !userNS && !userns.RunningInUserNS() && sysctlExists("net.ipv4.ping_group_range") {
774775
// allow unprivileged ICMP echo sockets without CAP_NET_RAW
775776
s.Linux.Sysctl["net.ipv4.ping_group_range"] = "0 2147483647"
776777
}

daemon/oci_linux_test.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ func TestSysctlOverride(t *testing.T) {
119119
HostConfig: &containertypes.HostConfig{
120120
NetworkMode: "bridge",
121121
Sysctls: map[string]string{},
122-
UsernsMode: "host",
123122
},
124123
}
125124
d := setupFakeDaemon(t, c)
@@ -147,6 +146,20 @@ func TestSysctlOverride(t *testing.T) {
147146
assert.Equal(t, s.Hostname, "foobar")
148147
assert.Equal(t, s.Linux.Sysctl["kernel.domainname"], c.HostConfig.Sysctls["kernel.domainname"])
149148
assert.Equal(t, s.Linux.Sysctl["net.ipv4.ip_unprivileged_port_start"], c.HostConfig.Sysctls["net.ipv4.ip_unprivileged_port_start"])
149+
150+
// Ensure the ping_group_range is not set on a daemon with user-namespaces enabled
151+
d.configStore.RemappedRoot = "dummy:dummy"
152+
s, err = d.createSpec(c)
153+
assert.NilError(t, err)
154+
_, ok := s.Linux.Sysctl["net.ipv4.ping_group_range"]
155+
assert.Assert(t, !ok)
156+
157+
// Ensure the ping_group_range is set on a container in "host" userns mode
158+
// on a daemon with user-namespaces enabled
159+
c.HostConfig.UsernsMode = "host"
160+
s, err = d.createSpec(c)
161+
assert.NilError(t, err)
162+
assert.Equal(t, s.Linux.Sysctl["net.ipv4.ping_group_range"], "0 2147483647")
150163
}
151164

152165
// TestSysctlOverrideHost ensures that any implicit network sysctls are not set
@@ -158,7 +171,6 @@ func TestSysctlOverrideHost(t *testing.T) {
158171
HostConfig: &containertypes.HostConfig{
159172
NetworkMode: "host",
160173
Sysctls: map[string]string{},
161-
UsernsMode: "host",
162174
},
163175
}
164176
d := setupFakeDaemon(t, c)

integration/container/run_linux_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,32 @@ func TestHostnameDnsResolution(t *testing.T) {
9999
assert.Check(t, is.Equal("", res.Stderr()))
100100
assert.Equal(t, 0, res.ExitCode)
101101
}
102+
103+
func TestUnprivilegedPortsAndPing(t *testing.T) {
104+
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
105+
skip.If(t, testEnv.IsRootless, "rootless mode doesn't support setting net.ipv4.ping_group_range and net.ipv4.ip_unprivileged_port_start")
106+
107+
defer setupTest(t)()
108+
client := testEnv.APIClient()
109+
ctx := context.Background()
110+
111+
cID := container.Run(ctx, t, client, func(c *container.TestContainerConfig) {
112+
c.Config.User = "1000:1000"
113+
})
114+
115+
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
116+
117+
// Check net.ipv4.ping_group_range.
118+
res, err := container.Exec(ctx, client, cID, []string{"cat", "/proc/sys/net/ipv4/ping_group_range"})
119+
assert.NilError(t, err)
120+
assert.Assert(t, is.Len(res.Stderr(), 0))
121+
assert.Equal(t, 0, res.ExitCode)
122+
assert.Equal(t, `0 2147483647`, strings.TrimSpace(res.Stdout()))
123+
124+
// Check net.ipv4.ip_unprivileged_port_start.
125+
res, err = container.Exec(ctx, client, cID, []string{"cat", "/proc/sys/net/ipv4/ip_unprivileged_port_start"})
126+
assert.NilError(t, err)
127+
assert.Assert(t, is.Len(res.Stderr(), 0))
128+
assert.Equal(t, 0, res.ExitCode)
129+
assert.Equal(t, "0", strings.TrimSpace(res.Stdout()))
130+
}

0 commit comments

Comments
 (0)