Browse code

Add --uts=host to allow sharing the UTS namespace

Signed-off-by: Darren Shepherd <darren@rancher.com>

Darren Shepherd authored on 2015/05/06 07:32:36
Showing 10 changed files
... ...
@@ -337,6 +337,10 @@ func populateCommand(c *Container, env []string) error {
337 337
 	pid := &execdriver.Pid{}
338 338
 	pid.HostPid = c.hostConfig.PidMode.IsHost()
339 339
 
340
+	uts := &execdriver.UTS{
341
+		HostUTS: c.hostConfig.UTSMode.IsHost(),
342
+	}
343
+
340 344
 	// Build lists of devices allowed and created within the container.
341 345
 	var userSpecifiedDevices []*configs.Device
342 346
 	for _, deviceMapping := range c.hostConfig.Devices {
... ...
@@ -412,6 +416,7 @@ func populateCommand(c *Container, env []string) error {
412 412
 		Network:            en,
413 413
 		Ipc:                ipc,
414 414
 		Pid:                pid,
415
+		UTS:                uts,
415 416
 		Resources:          resources,
416 417
 		AllowedDevices:     allowedDevices,
417 418
 		AutoCreatedDevices: autoCreatedDevices,
... ...
@@ -86,6 +86,11 @@ type Pid struct {
86 86
 	HostPid bool `json:"host_pid"`
87 87
 }
88 88
 
89
+// UTS settings of the container
90
+type UTS struct {
91
+	HostUTS bool `json:"host_uts"`
92
+}
93
+
89 94
 type NetworkInterface struct {
90 95
 	Gateway              string `json:"gateway"`
91 96
 	IPAddress            string `json:"ip"`
... ...
@@ -155,6 +160,7 @@ type Command struct {
155 155
 	Network            *Network          `json:"network"`
156 156
 	Ipc                *Ipc              `json:"ipc"`
157 157
 	Pid                *Pid              `json:"pid"`
158
+	UTS                *UTS              `json:"uts"`
158 159
 	Resources          *Resources        `json:"resources"`
159 160
 	Mounts             []Mount           `json:"mounts"`
160 161
 	AllowedDevices     []*configs.Device `json:"allowed_devices"`
... ...
@@ -29,6 +29,10 @@ func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error)
29 29
 		return nil, err
30 30
 	}
31 31
 
32
+	if err := d.createUTS(container, c); err != nil {
33
+		return nil, err
34
+	}
35
+
32 36
 	if err := d.createNetwork(container, c); err != nil {
33 37
 		return nil, err
34 38
 	}
... ...
@@ -173,6 +177,16 @@ func (d *driver) createPid(container *configs.Config, c *execdriver.Command) err
173 173
 	return nil
174 174
 }
175 175
 
176
+func (d *driver) createUTS(container *configs.Config, c *execdriver.Command) error {
177
+	if c.UTS.HostUTS {
178
+		container.Namespaces.Remove(configs.NEWUTS)
179
+		container.Hostname = ""
180
+		return nil
181
+	}
182
+
183
+	return nil
184
+}
185
+
176 186
 func (d *driver) setPrivileged(container *configs.Config) (err error) {
177 187
 	container.Capabilities = execdriver.GetAllCapabilities()
178 188
 	container.Cgroups.AllowAllDevices = true
... ...
@@ -42,6 +42,7 @@ docker-create - Create a new container
42 42
 [**-P**|**--publish-all**[=*false*]]
43 43
 [**-p**|**--publish**[=*[]*]]
44 44
 [**--pid**[=*[]*]]
45
+[**--uts**[=*[]*]]
45 46
 [**--privileged**[=*false*]]
46 47
 [**--read-only**[=*false*]]
47 48
 [**--restart**[=*RESTART*]]
... ...
@@ -193,6 +194,11 @@ This value should always larger than **-m**, so you should alway use this with *
193 193
      **host**: use the host's PID namespace inside the container.
194 194
      Note: the host mode gives the container full access to local PID and is therefore considered insecure.
195 195
 
196
+**--uts**=host
197
+   Set the UTS mode for the container
198
+     **host**: use the host's UTS namespace inside the container.
199
+     Note: the host mode gives the container access to changing the host's hostname and is therefore considered insecure.
200
+
196 201
 **--privileged**=*true*|*false*
197 202
    Give extended privileges to this container. The default is *false*.
198 203
 
... ...
@@ -43,6 +43,7 @@ docker-run - Run a command in a new container
43 43
 [**-P**|**--publish-all**[=*false*]]
44 44
 [**-p**|**--publish**[=*[]*]]
45 45
 [**--pid**[=*[]*]]
46
+[**--uts**[=*[]*]]
46 47
 [**--privileged**[=*false*]]
47 48
 [**--read-only**[=*false*]]
48 49
 [**--restart**[=*RESTART*]]
... ...
@@ -323,6 +324,11 @@ ports and the exposed ports, use `docker port`.
323 323
      **host**: use the host's PID namespace inside the container.
324 324
      Note: the host mode gives the container full access to local PID and is therefore considered insecure.
325 325
 
326
+**--uts**=host
327
+   Set the UTS mode for the container
328
+     **host**: use the host's UTS namespace inside the container.
329
+     Note: the host mode gives the container access to changing the host's hostname and is therefore considered insecure.
330
+
326 331
 **--privileged**=*true*|*false*
327 332
    Give extended privileges to this container. The default is *false*.
328 333
 
... ...
@@ -991,6 +991,8 @@ Creates a new container.
991 991
       --oom-kill-disable=false   Whether to disable OOM Killer for the container or not
992 992
       -P, --publish-all=false    Publish all exposed ports to random ports
993 993
       -p, --publish=[]           Publish a container's port(s) to the host
994
+      --pid=""                   PID namespace to use
995
+      --uts=""                   UTS namespace to use
994 996
       --privileged=false         Give extended privileges to this container
995 997
       --read-only=false          Mount the container's root filesystem as read only
996 998
       --restart="no"             Restart policy (no, on-failure[:max-retry], always)
... ...
@@ -1958,6 +1960,7 @@ To remove an image using its digest:
1958 1958
       -P, --publish-all=false    Publish all exposed ports to random ports
1959 1959
       -p, --publish=[]           Publish a container's port(s) to the host
1960 1960
       --pid=""                   PID namespace to use
1961
+      --uts=""                   UTS namespace to use
1961 1962
       --privileged=false         Give extended privileges to this container
1962 1963
       --read-only=false          Mount the container's root filesystem as read only
1963 1964
       --restart="no"             Restart policy (no, on-failure[:max-retry], always)
... ...
@@ -157,6 +157,7 @@ called a digest. As long as the input used to generate the image is unchanged,
157 157
 the digest value is predictable and referenceable.
158 158
 
159 159
 ## PID settings (--pid)
160
+
160 161
     --pid=""  : Set the PID (Process) Namespace mode for the container,
161 162
            'host': use the host's PID namespace inside the container
162 163
 
... ...
@@ -177,6 +178,23 @@ within the container.
177 177
 This command would allow you to use `strace` inside the container on pid 1234 on
178 178
 the host.
179 179
 
180
+## UTS settings (--uts)
181
+
182
+    --uts=""  : Set the UTS namespace mode for the container,
183
+           'host': use the host's UTS namespace inside the container
184
+
185
+The UTS namespace is for setting the hostname and the domain that is visible
186
+to running processes in that namespace.  By default, all containers, including
187
+those with `--net=host`, have their own UTS namespace.  The `host` setting will
188
+result in the container using the same UTS namespace as the host.
189
+
190
+You may wish to share the UTS namespace with the host if you would like the
191
+hostname of the container to change as the hostname of the host changes.  A
192
+more advanced use case would be changing the host's hostname from a container.
193
+
194
+> **Note**: `--uts="host"` gives the container full access to change the
195
+> hostname of the host and is therefore considered insecure.
196
+
180 197
 ## IPC settings (--ipc)
181 198
 
182 199
     --ipc=""  : Set the IPC mode for the container,
... ...
@@ -2765,6 +2765,38 @@ func (s *DockerSuite) TestRunModePidHost(c *check.C) {
2765 2765
 	}
2766 2766
 }
2767 2767
 
2768
+func (s *DockerSuite) TestRunModeUTSHost(c *check.C) {
2769
+	testRequires(c, NativeExecDriver, SameHostDaemon)
2770
+	defer deleteAllContainers()
2771
+
2772
+	hostUTS, err := os.Readlink("/proc/1/ns/uts")
2773
+	if err != nil {
2774
+		c.Fatal(err)
2775
+	}
2776
+
2777
+	cmd := exec.Command(dockerBinary, "run", "--uts=host", "busybox", "readlink", "/proc/self/ns/uts")
2778
+	out2, _, err := runCommandWithOutput(cmd)
2779
+	if err != nil {
2780
+		c.Fatal(err, out2)
2781
+	}
2782
+
2783
+	out2 = strings.Trim(out2, "\n")
2784
+	if hostUTS != out2 {
2785
+		c.Fatalf("UTS different with --uts=host %s != %s\n", hostUTS, out2)
2786
+	}
2787
+
2788
+	cmd = exec.Command(dockerBinary, "run", "busybox", "readlink", "/proc/self/ns/uts")
2789
+	out2, _, err = runCommandWithOutput(cmd)
2790
+	if err != nil {
2791
+		c.Fatal(err, out2)
2792
+	}
2793
+
2794
+	out2 = strings.Trim(out2, "\n")
2795
+	if hostUTS == out2 {
2796
+		c.Fatalf("UTS should be different without --uts=host %s == %s\n", hostUTS, out2)
2797
+	}
2798
+}
2799
+
2768 2800
 func (s *DockerSuite) TestRunTLSverify(c *check.C) {
2769 2801
 	cmd := exec.Command(dockerBinary, "ps")
2770 2802
 	out, ec, err := runCommandWithOutput(cmd)
... ...
@@ -76,6 +76,27 @@ func (n IpcMode) Container() string {
76 76
 	return ""
77 77
 }
78 78
 
79
+type UTSMode string
80
+
81
+// IsPrivate indicates whether container use it's private UTS namespace
82
+func (n UTSMode) IsPrivate() bool {
83
+	return !(n.IsHost())
84
+}
85
+
86
+func (n UTSMode) IsHost() bool {
87
+	return n == "host"
88
+}
89
+
90
+func (n UTSMode) Valid() bool {
91
+	parts := strings.Split(string(n), ":")
92
+	switch mode := parts[0]; mode {
93
+	case "", "host":
94
+	default:
95
+		return false
96
+	}
97
+	return true
98
+}
99
+
79 100
 type PidMode string
80 101
 
81 102
 // IsPrivate indicates whether container use it's private pid stack
... ...
@@ -187,6 +208,7 @@ type HostConfig struct {
187 187
 	NetworkMode     NetworkMode
188 188
 	IpcMode         IpcMode
189 189
 	PidMode         PidMode
190
+	UTSMode         UTSMode
190 191
 	CapAdd          []string
191 192
 	CapDrop         []string
192 193
 	RestartPolicy   RestartPolicy
... ...
@@ -52,6 +52,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
52 52
 		flNetwork         = cmd.Bool([]string{"#n", "#-networking"}, true, "Enable networking for this container")
53 53
 		flPrivileged      = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
54 54
 		flPidMode         = cmd.String([]string{"-pid"}, "", "PID namespace to use")
55
+		flUTSMode         = cmd.String([]string{"-uts"}, "", "UTS namespace to use")
55 56
 		flPublishAll      = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to random ports")
56 57
 		flStdin           = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
57 58
 		flTty             = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
... ...
@@ -281,6 +282,11 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
281 281
 		return nil, nil, cmd, fmt.Errorf("--pid: invalid PID mode")
282 282
 	}
283 283
 
284
+	utsMode := UTSMode(*flUTSMode)
285
+	if !utsMode.Valid() {
286
+		return nil, nil, cmd, fmt.Errorf("--uts: invalid UTS mode")
287
+	}
288
+
284 289
 	restartPolicy, err := ParseRestartPolicy(*flRestartPolicy)
285 290
 	if err != nil {
286 291
 		return nil, nil, cmd, err
... ...
@@ -337,6 +343,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
337 337
 		NetworkMode:     netMode,
338 338
 		IpcMode:         ipcMode,
339 339
 		PidMode:         pidMode,
340
+		UTSMode:         utsMode,
340 341
 		Devices:         deviceMappings,
341 342
 		CapAdd:          flCapAdd.GetAll(),
342 343
 		CapDrop:         flCapDrop.GetAll(),