Skip to content

Commit 10a3061

Browse files
committed
Fix regression in parsing capabilities list when a single string is given
Signed-off-by: Antonio Murdaca <[email protected]>
1 parent 53b897c commit 10a3061

6 files changed

Lines changed: 116 additions & 10 deletions

File tree

daemon/container_linux.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ func populateCommand(c *Container, env []string) error {
297297
Resources: resources,
298298
AllowedDevices: allowedDevices,
299299
AutoCreatedDevices: autoCreatedDevices,
300-
CapAdd: c.hostConfig.CapAdd,
301-
CapDrop: c.hostConfig.CapDrop,
300+
CapAdd: c.hostConfig.CapAdd.Slice(),
301+
CapDrop: c.hostConfig.CapDrop.Slice(),
302302
ProcessConfig: processConfig,
303303
ProcessLabel: c.GetProcessLabel(),
304304
MountLabel: c.GetMountLabel(),

daemon/container_windows.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ func populateCommand(c *Container, env []string) error {
111111
Network: en,
112112
Pid: pid,
113113
Resources: resources,
114-
CapAdd: c.hostConfig.CapAdd,
115-
CapDrop: c.hostConfig.CapDrop,
114+
CapAdd: c.hostConfig.CapAdd.Slice(),
115+
CapDrop: c.hostConfig.CapDrop.Slice(),
116116
ProcessConfig: processConfig,
117117
ProcessLabel: c.GetProcessLabel(),
118118
MountLabel: c.GetMountLabel(),

integration-cli/docker_api_containers_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,3 +1705,24 @@ func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *check.C) {
17051705
out, _ = dockerCmd(c, "start", "-a", "echotest2")
17061706
c.Assert(strings.TrimSpace(out), check.Equals, "hello world")
17071707
}
1708+
1709+
// regression #14318
1710+
func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *check.C) {
1711+
config := struct {
1712+
Image string
1713+
CapAdd string
1714+
CapDrop string
1715+
}{"busybox", "NET_ADMIN", "SYS_ADMIN"}
1716+
status, _, err := sockRequest("POST", "/containers/create?name=capaddtest0", config)
1717+
c.Assert(err, check.IsNil)
1718+
c.Assert(status, check.Equals, http.StatusCreated)
1719+
1720+
config2 := struct {
1721+
Image string
1722+
CapAdd []string
1723+
CapDrop []string
1724+
}{"busybox", []string{"NET_ADMIN", "SYS_ADMIN"}, []string{"SETGID"}}
1725+
status, _, err = sockRequest("POST", "/containers/create?name=capaddtest1", config2)
1726+
c.Assert(err, check.IsNil)
1727+
c.Assert(status, check.Equals, http.StatusCreated)
1728+
}

runconfig/hostconfig.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,53 @@ func NewLxcConfig(values []KeyValuePair) *LxcConfig {
173173
return &LxcConfig{values}
174174
}
175175

176+
type CapList struct {
177+
caps []string
178+
}
179+
180+
func (c *CapList) MarshalJSON() ([]byte, error) {
181+
if c == nil {
182+
return []byte{}, nil
183+
}
184+
return json.Marshal(c.Slice())
185+
}
186+
187+
func (c *CapList) UnmarshalJSON(b []byte) error {
188+
if len(b) == 0 {
189+
return nil
190+
}
191+
192+
var caps []string
193+
if err := json.Unmarshal(b, &caps); err != nil {
194+
var s string
195+
if err := json.Unmarshal(b, &s); err != nil {
196+
return err
197+
}
198+
caps = append(caps, s)
199+
}
200+
c.caps = caps
201+
202+
return nil
203+
}
204+
205+
func (c *CapList) Len() int {
206+
if c == nil {
207+
return 0
208+
}
209+
return len(c.caps)
210+
}
211+
212+
func (c *CapList) Slice() []string {
213+
if c == nil {
214+
return nil
215+
}
216+
return c.caps
217+
}
218+
219+
func NewCapList(caps []string) *CapList {
220+
return &CapList{caps}
221+
}
222+
176223
type HostConfig struct {
177224
Binds []string
178225
ContainerIDFile string
@@ -199,8 +246,8 @@ type HostConfig struct {
199246
IpcMode IpcMode
200247
PidMode PidMode
201248
UTSMode UTSMode
202-
CapAdd []string
203-
CapDrop []string
249+
CapAdd *CapList
250+
CapDrop *CapList
204251
RestartPolicy RestartPolicy
205252
SecurityOpt []string
206253
ReadonlyRootfs bool

runconfig/hostconfig_test.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package runconfig
22

33
import (
44
"bytes"
5+
"encoding/json"
56
"fmt"
67
"io/ioutil"
78
"testing"
@@ -254,12 +255,49 @@ func TestDecodeHostConfig(t *testing.T) {
254255
t.Fatalf("Expected 1 bind, found %v\n", c.Binds)
255256
}
256257

257-
if len(c.CapAdd) != 1 && c.CapAdd[0] != "NET_ADMIN" {
258+
if c.CapAdd.Len() != 1 && c.CapAdd.Slice()[0] != "NET_ADMIN" {
258259
t.Fatalf("Expected CapAdd NET_ADMIN, got %v", c.CapAdd)
259260
}
260261

261-
if len(c.CapDrop) != 1 && c.CapDrop[0] != "NET_ADMIN" {
262+
if c.CapDrop.Len() != 1 && c.CapDrop.Slice()[0] != "NET_ADMIN" {
262263
t.Fatalf("Expected CapDrop MKNOD, got %v", c.CapDrop)
263264
}
264265
}
265266
}
267+
268+
func TestCapListUnmarshalSliceAndString(t *testing.T) {
269+
var cl *CapList
270+
cap0, err := json.Marshal([]string{"CAP_SOMETHING"})
271+
if err != nil {
272+
t.Fatal(err)
273+
}
274+
if err := json.Unmarshal(cap0, &cl); err != nil {
275+
t.Fatal(err)
276+
}
277+
278+
slice := cl.Slice()
279+
if len(slice) != 1 {
280+
t.Fatalf("expected 1 element after unmarshal: %q", slice)
281+
}
282+
283+
if slice[0] != "CAP_SOMETHING" {
284+
t.Fatalf("expected `CAP_SOMETHING`, got: %q", slice[0])
285+
}
286+
287+
cap1, err := json.Marshal("CAP_SOMETHING")
288+
if err != nil {
289+
t.Fatal(err)
290+
}
291+
if err := json.Unmarshal(cap1, &cl); err != nil {
292+
t.Fatal(err)
293+
}
294+
295+
slice = cl.Slice()
296+
if len(slice) != 1 {
297+
t.Fatalf("expected 1 element after unmarshal: %q", slice)
298+
}
299+
300+
if slice[0] != "CAP_SOMETHING" {
301+
t.Fatalf("expected `CAP_SOMETHING`, got: %q", slice[0])
302+
}
303+
}

runconfig/parse.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
353353
PidMode: pidMode,
354354
UTSMode: utsMode,
355355
Devices: deviceMappings,
356-
CapAdd: flCapAdd.GetAll(),
357-
CapDrop: flCapDrop.GetAll(),
356+
CapAdd: NewCapList(flCapAdd.GetAll()),
357+
CapDrop: NewCapList(flCapDrop.GetAll()),
358358
RestartPolicy: restartPolicy,
359359
SecurityOpt: flSecurityOpt.GetAll(),
360360
ReadonlyRootfs: *flReadonlyRootfs,

0 commit comments

Comments
 (0)