gopkg.in/moby/moby.v1@v1.13.1/integration-cli/docker_cli_run_unix_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "bufio" 7 "encoding/json" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "regexp" 14 "strconv" 15 "strings" 16 "syscall" 17 "time" 18 19 "github.com/docker/docker/pkg/homedir" 20 "github.com/docker/docker/pkg/integration/checker" 21 "github.com/docker/docker/pkg/mount" 22 "github.com/docker/docker/pkg/parsers" 23 "github.com/docker/docker/pkg/sysinfo" 24 "github.com/go-check/check" 25 "github.com/kr/pty" 26 ) 27 28 // #6509 29 func (s *DockerSuite) TestRunRedirectStdout(c *check.C) { 30 checkRedirect := func(command string) { 31 _, tty, err := pty.Open() 32 c.Assert(err, checker.IsNil, check.Commentf("Could not open pty")) 33 cmd := exec.Command("sh", "-c", command) 34 cmd.Stdin = tty 35 cmd.Stdout = tty 36 cmd.Stderr = tty 37 c.Assert(cmd.Start(), checker.IsNil) 38 ch := make(chan error) 39 go func() { 40 ch <- cmd.Wait() 41 close(ch) 42 }() 43 44 select { 45 case <-time.After(10 * time.Second): 46 c.Fatal("command timeout") 47 case err := <-ch: 48 c.Assert(err, checker.IsNil, check.Commentf("wait err")) 49 } 50 } 51 52 checkRedirect(dockerBinary + " run -i busybox cat /etc/passwd | grep -q root") 53 checkRedirect(dockerBinary + " run busybox cat /etc/passwd | grep -q root") 54 } 55 56 // Test recursive bind mount works by default 57 func (s *DockerSuite) TestRunWithVolumesIsRecursive(c *check.C) { 58 // /tmp gets permission denied 59 testRequires(c, NotUserNamespace, SameHostDaemon) 60 tmpDir, err := ioutil.TempDir("", "docker_recursive_mount_test") 61 c.Assert(err, checker.IsNil) 62 63 defer os.RemoveAll(tmpDir) 64 65 // Create a temporary tmpfs mount. 66 tmpfsDir := filepath.Join(tmpDir, "tmpfs") 67 c.Assert(os.MkdirAll(tmpfsDir, 0777), checker.IsNil, check.Commentf("failed to mkdir at %s", tmpfsDir)) 68 c.Assert(mount.Mount("tmpfs", tmpfsDir, "tmpfs", ""), checker.IsNil, check.Commentf("failed to create a tmpfs mount at %s", tmpfsDir)) 69 70 f, err := ioutil.TempFile(tmpfsDir, "touch-me") 71 c.Assert(err, checker.IsNil) 72 defer f.Close() 73 74 runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox:latest", "ls", "/tmp/tmpfs") 75 out, _, _, err := runCommandWithStdoutStderr(runCmd) 76 c.Assert(err, checker.IsNil) 77 c.Assert(out, checker.Contains, filepath.Base(f.Name()), check.Commentf("Recursive bind mount test failed. Expected file not found")) 78 } 79 80 func (s *DockerSuite) TestRunDeviceDirectory(c *check.C) { 81 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 82 if _, err := os.Stat("/dev/snd"); err != nil { 83 c.Skip("Host does not have /dev/snd") 84 } 85 86 out, _ := dockerCmd(c, "run", "--device", "/dev/snd:/dev/snd", "busybox", "sh", "-c", "ls /dev/snd/") 87 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "timer", check.Commentf("expected output /dev/snd/timer")) 88 89 out, _ = dockerCmd(c, "run", "--device", "/dev/snd:/dev/othersnd", "busybox", "sh", "-c", "ls /dev/othersnd/") 90 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "seq", check.Commentf("expected output /dev/othersnd/seq")) 91 } 92 93 // TestRunDetach checks attaching and detaching with the default escape sequence. 94 func (s *DockerSuite) TestRunAttachDetach(c *check.C) { 95 name := "attach-detach" 96 97 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat") 98 99 cmd := exec.Command(dockerBinary, "attach", name) 100 stdout, err := cmd.StdoutPipe() 101 c.Assert(err, checker.IsNil) 102 cpty, tty, err := pty.Open() 103 c.Assert(err, checker.IsNil) 104 defer cpty.Close() 105 cmd.Stdin = tty 106 c.Assert(cmd.Start(), checker.IsNil) 107 c.Assert(waitRun(name), check.IsNil) 108 109 _, err = cpty.Write([]byte("hello\n")) 110 c.Assert(err, checker.IsNil) 111 112 out, err := bufio.NewReader(stdout).ReadString('\n') 113 c.Assert(err, checker.IsNil) 114 c.Assert(strings.TrimSpace(out), checker.Equals, "hello") 115 116 // escape sequence 117 _, err = cpty.Write([]byte{16}) 118 c.Assert(err, checker.IsNil) 119 time.Sleep(100 * time.Millisecond) 120 _, err = cpty.Write([]byte{17}) 121 c.Assert(err, checker.IsNil) 122 123 ch := make(chan struct{}) 124 go func() { 125 cmd.Wait() 126 ch <- struct{}{} 127 }() 128 129 select { 130 case <-ch: 131 case <-time.After(10 * time.Second): 132 c.Fatal("timed out waiting for container to exit") 133 } 134 135 running := inspectField(c, name, "State.Running") 136 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 137 138 out, _ = dockerCmd(c, "events", "--since=0", "--until", daemonUnixTime(c), "-f", "container="+name) 139 // attach and detach event should be monitored 140 c.Assert(out, checker.Contains, "attach") 141 c.Assert(out, checker.Contains, "detach") 142 } 143 144 // TestRunDetach checks attaching and detaching with the escape sequence specified via flags. 145 func (s *DockerSuite) TestRunAttachDetachFromFlag(c *check.C) { 146 name := "attach-detach" 147 keyCtrlA := []byte{1} 148 keyA := []byte{97} 149 150 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat") 151 152 cmd := exec.Command(dockerBinary, "attach", "--detach-keys=ctrl-a,a", name) 153 stdout, err := cmd.StdoutPipe() 154 if err != nil { 155 c.Fatal(err) 156 } 157 cpty, tty, err := pty.Open() 158 if err != nil { 159 c.Fatal(err) 160 } 161 defer cpty.Close() 162 cmd.Stdin = tty 163 if err := cmd.Start(); err != nil { 164 c.Fatal(err) 165 } 166 c.Assert(waitRun(name), check.IsNil) 167 168 if _, err := cpty.Write([]byte("hello\n")); err != nil { 169 c.Fatal(err) 170 } 171 172 out, err := bufio.NewReader(stdout).ReadString('\n') 173 if err != nil { 174 c.Fatal(err) 175 } 176 if strings.TrimSpace(out) != "hello" { 177 c.Fatalf("expected 'hello', got %q", out) 178 } 179 180 // escape sequence 181 if _, err := cpty.Write(keyCtrlA); err != nil { 182 c.Fatal(err) 183 } 184 time.Sleep(100 * time.Millisecond) 185 if _, err := cpty.Write(keyA); err != nil { 186 c.Fatal(err) 187 } 188 189 ch := make(chan struct{}) 190 go func() { 191 cmd.Wait() 192 ch <- struct{}{} 193 }() 194 195 select { 196 case <-ch: 197 case <-time.After(10 * time.Second): 198 c.Fatal("timed out waiting for container to exit") 199 } 200 201 running := inspectField(c, name, "State.Running") 202 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 203 } 204 205 // TestRunDetach checks attaching and detaching with the escape sequence specified via flags. 206 func (s *DockerSuite) TestRunAttachDetachFromInvalidFlag(c *check.C) { 207 name := "attach-detach" 208 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "top") 209 c.Assert(waitRun(name), check.IsNil) 210 211 // specify an invalid detach key, container will ignore it and use default 212 cmd := exec.Command(dockerBinary, "attach", "--detach-keys=ctrl-A,a", name) 213 stdout, err := cmd.StdoutPipe() 214 if err != nil { 215 c.Fatal(err) 216 } 217 cpty, tty, err := pty.Open() 218 if err != nil { 219 c.Fatal(err) 220 } 221 defer cpty.Close() 222 cmd.Stdin = tty 223 if err := cmd.Start(); err != nil { 224 c.Fatal(err) 225 } 226 227 bufReader := bufio.NewReader(stdout) 228 out, err := bufReader.ReadString('\n') 229 if err != nil { 230 c.Fatal(err) 231 } 232 // it should print a warning to indicate the detach key flag is invalid 233 errStr := "Invalid escape keys (ctrl-A,a) provided" 234 c.Assert(strings.TrimSpace(out), checker.Equals, errStr) 235 } 236 237 // TestRunDetach checks attaching and detaching with the escape sequence specified via config file. 238 func (s *DockerSuite) TestRunAttachDetachFromConfig(c *check.C) { 239 keyCtrlA := []byte{1} 240 keyA := []byte{97} 241 242 // Setup config 243 homeKey := homedir.Key() 244 homeVal := homedir.Get() 245 tmpDir, err := ioutil.TempDir("", "fake-home") 246 c.Assert(err, checker.IsNil) 247 defer os.RemoveAll(tmpDir) 248 249 dotDocker := filepath.Join(tmpDir, ".docker") 250 os.Mkdir(dotDocker, 0600) 251 tmpCfg := filepath.Join(dotDocker, "config.json") 252 253 defer func() { os.Setenv(homeKey, homeVal) }() 254 os.Setenv(homeKey, tmpDir) 255 256 data := `{ 257 "detachKeys": "ctrl-a,a" 258 }` 259 260 err = ioutil.WriteFile(tmpCfg, []byte(data), 0600) 261 c.Assert(err, checker.IsNil) 262 263 // Then do the work 264 name := "attach-detach" 265 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat") 266 267 cmd := exec.Command(dockerBinary, "attach", name) 268 stdout, err := cmd.StdoutPipe() 269 if err != nil { 270 c.Fatal(err) 271 } 272 cpty, tty, err := pty.Open() 273 if err != nil { 274 c.Fatal(err) 275 } 276 defer cpty.Close() 277 cmd.Stdin = tty 278 if err := cmd.Start(); err != nil { 279 c.Fatal(err) 280 } 281 c.Assert(waitRun(name), check.IsNil) 282 283 if _, err := cpty.Write([]byte("hello\n")); err != nil { 284 c.Fatal(err) 285 } 286 287 out, err := bufio.NewReader(stdout).ReadString('\n') 288 if err != nil { 289 c.Fatal(err) 290 } 291 if strings.TrimSpace(out) != "hello" { 292 c.Fatalf("expected 'hello', got %q", out) 293 } 294 295 // escape sequence 296 if _, err := cpty.Write(keyCtrlA); err != nil { 297 c.Fatal(err) 298 } 299 time.Sleep(100 * time.Millisecond) 300 if _, err := cpty.Write(keyA); err != nil { 301 c.Fatal(err) 302 } 303 304 ch := make(chan struct{}) 305 go func() { 306 cmd.Wait() 307 ch <- struct{}{} 308 }() 309 310 select { 311 case <-ch: 312 case <-time.After(10 * time.Second): 313 c.Fatal("timed out waiting for container to exit") 314 } 315 316 running := inspectField(c, name, "State.Running") 317 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 318 } 319 320 // TestRunDetach checks attaching and detaching with the detach flags, making sure it overrides config file 321 func (s *DockerSuite) TestRunAttachDetachKeysOverrideConfig(c *check.C) { 322 keyCtrlA := []byte{1} 323 keyA := []byte{97} 324 325 // Setup config 326 homeKey := homedir.Key() 327 homeVal := homedir.Get() 328 tmpDir, err := ioutil.TempDir("", "fake-home") 329 c.Assert(err, checker.IsNil) 330 defer os.RemoveAll(tmpDir) 331 332 dotDocker := filepath.Join(tmpDir, ".docker") 333 os.Mkdir(dotDocker, 0600) 334 tmpCfg := filepath.Join(dotDocker, "config.json") 335 336 defer func() { os.Setenv(homeKey, homeVal) }() 337 os.Setenv(homeKey, tmpDir) 338 339 data := `{ 340 "detachKeys": "ctrl-e,e" 341 }` 342 343 err = ioutil.WriteFile(tmpCfg, []byte(data), 0600) 344 c.Assert(err, checker.IsNil) 345 346 // Then do the work 347 name := "attach-detach" 348 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat") 349 350 cmd := exec.Command(dockerBinary, "attach", "--detach-keys=ctrl-a,a", name) 351 stdout, err := cmd.StdoutPipe() 352 if err != nil { 353 c.Fatal(err) 354 } 355 cpty, tty, err := pty.Open() 356 if err != nil { 357 c.Fatal(err) 358 } 359 defer cpty.Close() 360 cmd.Stdin = tty 361 if err := cmd.Start(); err != nil { 362 c.Fatal(err) 363 } 364 c.Assert(waitRun(name), check.IsNil) 365 366 if _, err := cpty.Write([]byte("hello\n")); err != nil { 367 c.Fatal(err) 368 } 369 370 out, err := bufio.NewReader(stdout).ReadString('\n') 371 if err != nil { 372 c.Fatal(err) 373 } 374 if strings.TrimSpace(out) != "hello" { 375 c.Fatalf("expected 'hello', got %q", out) 376 } 377 378 // escape sequence 379 if _, err := cpty.Write(keyCtrlA); err != nil { 380 c.Fatal(err) 381 } 382 time.Sleep(100 * time.Millisecond) 383 if _, err := cpty.Write(keyA); err != nil { 384 c.Fatal(err) 385 } 386 387 ch := make(chan struct{}) 388 go func() { 389 cmd.Wait() 390 ch <- struct{}{} 391 }() 392 393 select { 394 case <-ch: 395 case <-time.After(10 * time.Second): 396 c.Fatal("timed out waiting for container to exit") 397 } 398 399 running := inspectField(c, name, "State.Running") 400 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 401 } 402 403 func (s *DockerSuite) TestRunAttachInvalidDetachKeySequencePreserved(c *check.C) { 404 name := "attach-detach" 405 keyA := []byte{97} 406 keyB := []byte{98} 407 408 dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat") 409 410 cmd := exec.Command(dockerBinary, "attach", "--detach-keys=a,b,c", name) 411 stdout, err := cmd.StdoutPipe() 412 if err != nil { 413 c.Fatal(err) 414 } 415 cpty, tty, err := pty.Open() 416 if err != nil { 417 c.Fatal(err) 418 } 419 defer cpty.Close() 420 cmd.Stdin = tty 421 if err := cmd.Start(); err != nil { 422 c.Fatal(err) 423 } 424 c.Assert(waitRun(name), check.IsNil) 425 426 // Invalid escape sequence aba, should print aba in output 427 if _, err := cpty.Write(keyA); err != nil { 428 c.Fatal(err) 429 } 430 time.Sleep(100 * time.Millisecond) 431 if _, err := cpty.Write(keyB); err != nil { 432 c.Fatal(err) 433 } 434 time.Sleep(100 * time.Millisecond) 435 if _, err := cpty.Write(keyA); err != nil { 436 c.Fatal(err) 437 } 438 time.Sleep(100 * time.Millisecond) 439 if _, err := cpty.Write([]byte("\n")); err != nil { 440 c.Fatal(err) 441 } 442 443 out, err := bufio.NewReader(stdout).ReadString('\n') 444 if err != nil { 445 c.Fatal(err) 446 } 447 if strings.TrimSpace(out) != "aba" { 448 c.Fatalf("expected 'aba', got %q", out) 449 } 450 } 451 452 // "test" should be printed 453 func (s *DockerSuite) TestRunWithCPUQuota(c *check.C) { 454 testRequires(c, cpuCfsQuota) 455 456 file := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us" 457 out, _ := dockerCmd(c, "run", "--cpu-quota", "8000", "--name", "test", "busybox", "cat", file) 458 c.Assert(strings.TrimSpace(out), checker.Equals, "8000") 459 460 out = inspectField(c, "test", "HostConfig.CpuQuota") 461 c.Assert(out, checker.Equals, "8000", check.Commentf("setting the CPU CFS quota failed")) 462 } 463 464 func (s *DockerSuite) TestRunWithCpuPeriod(c *check.C) { 465 testRequires(c, cpuCfsPeriod) 466 467 file := "/sys/fs/cgroup/cpu/cpu.cfs_period_us" 468 out, _ := dockerCmd(c, "run", "--cpu-period", "50000", "--name", "test", "busybox", "cat", file) 469 c.Assert(strings.TrimSpace(out), checker.Equals, "50000") 470 471 out, _ = dockerCmd(c, "run", "--cpu-period", "0", "busybox", "cat", file) 472 c.Assert(strings.TrimSpace(out), checker.Equals, "100000") 473 474 out = inspectField(c, "test", "HostConfig.CpuPeriod") 475 c.Assert(out, checker.Equals, "50000", check.Commentf("setting the CPU CFS period failed")) 476 } 477 478 func (s *DockerSuite) TestRunWithInvalidCpuPeriod(c *check.C) { 479 testRequires(c, cpuCfsPeriod) 480 out, _, err := dockerCmdWithError("run", "--cpu-period", "900", "busybox", "true") 481 c.Assert(err, check.NotNil) 482 expected := "CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)" 483 c.Assert(out, checker.Contains, expected) 484 485 out, _, err = dockerCmdWithError("run", "--cpu-period", "2000000", "busybox", "true") 486 c.Assert(err, check.NotNil) 487 c.Assert(out, checker.Contains, expected) 488 489 out, _, err = dockerCmdWithError("run", "--cpu-period", "-3", "busybox", "true") 490 c.Assert(err, check.NotNil) 491 c.Assert(out, checker.Contains, expected) 492 } 493 494 func (s *DockerSuite) TestRunWithKernelMemory(c *check.C) { 495 testRequires(c, kernelMemorySupport) 496 497 file := "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes" 498 stdout, _, _ := dockerCmdWithStdoutStderr(c, "run", "--kernel-memory", "50M", "--name", "test1", "busybox", "cat", file) 499 c.Assert(strings.TrimSpace(stdout), checker.Equals, "52428800") 500 501 out := inspectField(c, "test1", "HostConfig.KernelMemory") 502 c.Assert(out, check.Equals, "52428800") 503 } 504 505 func (s *DockerSuite) TestRunWithInvalidKernelMemory(c *check.C) { 506 testRequires(c, kernelMemorySupport) 507 508 out, _, err := dockerCmdWithError("run", "--kernel-memory", "2M", "busybox", "true") 509 c.Assert(err, check.NotNil) 510 expected := "Minimum kernel memory limit allowed is 4MB" 511 c.Assert(out, checker.Contains, expected) 512 513 out, _, err = dockerCmdWithError("run", "--kernel-memory", "-16m", "--name", "test2", "busybox", "echo", "test") 514 c.Assert(err, check.NotNil) 515 expected = "invalid size" 516 c.Assert(out, checker.Contains, expected) 517 } 518 519 func (s *DockerSuite) TestRunWithCPUShares(c *check.C) { 520 testRequires(c, cpuShare) 521 522 file := "/sys/fs/cgroup/cpu/cpu.shares" 523 out, _ := dockerCmd(c, "run", "--cpu-shares", "1000", "--name", "test", "busybox", "cat", file) 524 c.Assert(strings.TrimSpace(out), checker.Equals, "1000") 525 526 out = inspectField(c, "test", "HostConfig.CPUShares") 527 c.Assert(out, check.Equals, "1000") 528 } 529 530 // "test" should be printed 531 func (s *DockerSuite) TestRunEchoStdoutWithCPUSharesAndMemoryLimit(c *check.C) { 532 testRequires(c, cpuShare) 533 testRequires(c, memoryLimitSupport) 534 out, _, _ := dockerCmdWithStdoutStderr(c, "run", "--cpu-shares", "1000", "-m", "32m", "busybox", "echo", "test") 535 c.Assert(out, checker.Equals, "test\n", check.Commentf("container should've printed 'test'")) 536 } 537 538 func (s *DockerSuite) TestRunWithCpusetCpus(c *check.C) { 539 testRequires(c, cgroupCpuset) 540 541 file := "/sys/fs/cgroup/cpuset/cpuset.cpus" 542 out, _ := dockerCmd(c, "run", "--cpuset-cpus", "0", "--name", "test", "busybox", "cat", file) 543 c.Assert(strings.TrimSpace(out), checker.Equals, "0") 544 545 out = inspectField(c, "test", "HostConfig.CpusetCpus") 546 c.Assert(out, check.Equals, "0") 547 } 548 549 func (s *DockerSuite) TestRunWithCpusetMems(c *check.C) { 550 testRequires(c, cgroupCpuset) 551 552 file := "/sys/fs/cgroup/cpuset/cpuset.mems" 553 out, _ := dockerCmd(c, "run", "--cpuset-mems", "0", "--name", "test", "busybox", "cat", file) 554 c.Assert(strings.TrimSpace(out), checker.Equals, "0") 555 556 out = inspectField(c, "test", "HostConfig.CpusetMems") 557 c.Assert(out, check.Equals, "0") 558 } 559 560 func (s *DockerSuite) TestRunWithBlkioWeight(c *check.C) { 561 testRequires(c, blkioWeight) 562 563 file := "/sys/fs/cgroup/blkio/blkio.weight" 564 out, _ := dockerCmd(c, "run", "--blkio-weight", "300", "--name", "test", "busybox", "cat", file) 565 c.Assert(strings.TrimSpace(out), checker.Equals, "300") 566 567 out = inspectField(c, "test", "HostConfig.BlkioWeight") 568 c.Assert(out, check.Equals, "300") 569 } 570 571 func (s *DockerSuite) TestRunWithInvalidBlkioWeight(c *check.C) { 572 testRequires(c, blkioWeight) 573 out, _, err := dockerCmdWithError("run", "--blkio-weight", "5", "busybox", "true") 574 c.Assert(err, check.NotNil, check.Commentf(out)) 575 expected := "Range of blkio weight is from 10 to 1000" 576 c.Assert(out, checker.Contains, expected) 577 } 578 579 func (s *DockerSuite) TestRunWithInvalidPathforBlkioWeightDevice(c *check.C) { 580 testRequires(c, blkioWeight) 581 out, _, err := dockerCmdWithError("run", "--blkio-weight-device", "/dev/sdX:100", "busybox", "true") 582 c.Assert(err, check.NotNil, check.Commentf(out)) 583 } 584 585 func (s *DockerSuite) TestRunWithInvalidPathforBlkioDeviceReadBps(c *check.C) { 586 testRequires(c, blkioWeight) 587 out, _, err := dockerCmdWithError("run", "--device-read-bps", "/dev/sdX:500", "busybox", "true") 588 c.Assert(err, check.NotNil, check.Commentf(out)) 589 } 590 591 func (s *DockerSuite) TestRunWithInvalidPathforBlkioDeviceWriteBps(c *check.C) { 592 testRequires(c, blkioWeight) 593 out, _, err := dockerCmdWithError("run", "--device-write-bps", "/dev/sdX:500", "busybox", "true") 594 c.Assert(err, check.NotNil, check.Commentf(out)) 595 } 596 597 func (s *DockerSuite) TestRunWithInvalidPathforBlkioDeviceReadIOps(c *check.C) { 598 testRequires(c, blkioWeight) 599 out, _, err := dockerCmdWithError("run", "--device-read-iops", "/dev/sdX:500", "busybox", "true") 600 c.Assert(err, check.NotNil, check.Commentf(out)) 601 } 602 603 func (s *DockerSuite) TestRunWithInvalidPathforBlkioDeviceWriteIOps(c *check.C) { 604 testRequires(c, blkioWeight) 605 out, _, err := dockerCmdWithError("run", "--device-write-iops", "/dev/sdX:500", "busybox", "true") 606 c.Assert(err, check.NotNil, check.Commentf(out)) 607 } 608 609 func (s *DockerSuite) TestRunOOMExitCode(c *check.C) { 610 testRequires(c, memoryLimitSupport, swapMemorySupport) 611 errChan := make(chan error) 612 go func() { 613 defer close(errChan) 614 out, exitCode, _ := dockerCmdWithError("run", "-m", "4MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done") 615 if expected := 137; exitCode != expected { 616 errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out) 617 } 618 }() 619 620 select { 621 case err := <-errChan: 622 c.Assert(err, check.IsNil) 623 case <-time.After(600 * time.Second): 624 c.Fatal("Timeout waiting for container to die on OOM") 625 } 626 } 627 628 func (s *DockerSuite) TestRunWithMemoryLimit(c *check.C) { 629 testRequires(c, memoryLimitSupport) 630 631 file := "/sys/fs/cgroup/memory/memory.limit_in_bytes" 632 stdout, _, _ := dockerCmdWithStdoutStderr(c, "run", "-m", "32M", "--name", "test", "busybox", "cat", file) 633 c.Assert(strings.TrimSpace(stdout), checker.Equals, "33554432") 634 635 out := inspectField(c, "test", "HostConfig.Memory") 636 c.Assert(out, check.Equals, "33554432") 637 } 638 639 // TestRunWithoutMemoryswapLimit sets memory limit and disables swap 640 // memory limit, this means the processes in the container can use 641 // 16M memory and as much swap memory as they need (if the host 642 // supports swap memory). 643 func (s *DockerSuite) TestRunWithoutMemoryswapLimit(c *check.C) { 644 testRequires(c, DaemonIsLinux) 645 testRequires(c, memoryLimitSupport) 646 testRequires(c, swapMemorySupport) 647 dockerCmd(c, "run", "-m", "32m", "--memory-swap", "-1", "busybox", "true") 648 } 649 650 func (s *DockerSuite) TestRunWithSwappiness(c *check.C) { 651 testRequires(c, memorySwappinessSupport) 652 file := "/sys/fs/cgroup/memory/memory.swappiness" 653 out, _ := dockerCmd(c, "run", "--memory-swappiness", "0", "--name", "test", "busybox", "cat", file) 654 c.Assert(strings.TrimSpace(out), checker.Equals, "0") 655 656 out = inspectField(c, "test", "HostConfig.MemorySwappiness") 657 c.Assert(out, check.Equals, "0") 658 } 659 660 func (s *DockerSuite) TestRunWithSwappinessInvalid(c *check.C) { 661 testRequires(c, memorySwappinessSupport) 662 out, _, err := dockerCmdWithError("run", "--memory-swappiness", "101", "busybox", "true") 663 c.Assert(err, check.NotNil) 664 expected := "Valid memory swappiness range is 0-100" 665 c.Assert(out, checker.Contains, expected, check.Commentf("Expected output to contain %q, not %q", out, expected)) 666 667 out, _, err = dockerCmdWithError("run", "--memory-swappiness", "-10", "busybox", "true") 668 c.Assert(err, check.NotNil) 669 c.Assert(out, checker.Contains, expected, check.Commentf("Expected output to contain %q, not %q", out, expected)) 670 } 671 672 func (s *DockerSuite) TestRunWithMemoryReservation(c *check.C) { 673 testRequires(c, memoryReservationSupport) 674 675 file := "/sys/fs/cgroup/memory/memory.soft_limit_in_bytes" 676 out, _ := dockerCmd(c, "run", "--memory-reservation", "200M", "--name", "test", "busybox", "cat", file) 677 c.Assert(strings.TrimSpace(out), checker.Equals, "209715200") 678 679 out = inspectField(c, "test", "HostConfig.MemoryReservation") 680 c.Assert(out, check.Equals, "209715200") 681 } 682 683 func (s *DockerSuite) TestRunWithMemoryReservationInvalid(c *check.C) { 684 testRequires(c, memoryLimitSupport) 685 testRequires(c, memoryReservationSupport) 686 out, _, err := dockerCmdWithError("run", "-m", "500M", "--memory-reservation", "800M", "busybox", "true") 687 c.Assert(err, check.NotNil) 688 expected := "Minimum memory limit can not be less than memory reservation limit" 689 c.Assert(strings.TrimSpace(out), checker.Contains, expected, check.Commentf("run container should fail with invalid memory reservation")) 690 691 out, _, err = dockerCmdWithError("run", "--memory-reservation", "1k", "busybox", "true") 692 c.Assert(err, check.NotNil) 693 expected = "Minimum memory reservation allowed is 4MB" 694 c.Assert(strings.TrimSpace(out), checker.Contains, expected, check.Commentf("run container should fail with invalid memory reservation")) 695 } 696 697 func (s *DockerSuite) TestStopContainerSignal(c *check.C) { 698 out, _ := dockerCmd(c, "run", "--stop-signal", "SIGUSR1", "-d", "busybox", "/bin/sh", "-c", `trap 'echo "exit trapped"; exit 0' USR1; while true; do sleep 1; done`) 699 containerID := strings.TrimSpace(out) 700 701 c.Assert(waitRun(containerID), checker.IsNil) 702 703 dockerCmd(c, "stop", containerID) 704 out, _ = dockerCmd(c, "logs", containerID) 705 706 c.Assert(out, checker.Contains, "exit trapped", check.Commentf("Expected `exit trapped` in the log")) 707 } 708 709 func (s *DockerSuite) TestRunSwapLessThanMemoryLimit(c *check.C) { 710 testRequires(c, memoryLimitSupport) 711 testRequires(c, swapMemorySupport) 712 out, _, err := dockerCmdWithError("run", "-m", "16m", "--memory-swap", "15m", "busybox", "echo", "test") 713 expected := "Minimum memoryswap limit should be larger than memory limit" 714 c.Assert(err, check.NotNil) 715 716 c.Assert(out, checker.Contains, expected) 717 } 718 719 func (s *DockerSuite) TestRunInvalidCpusetCpusFlagValue(c *check.C) { 720 testRequires(c, cgroupCpuset, SameHostDaemon) 721 722 sysInfo := sysinfo.New(true) 723 cpus, err := parsers.ParseUintList(sysInfo.Cpus) 724 c.Assert(err, check.IsNil) 725 var invalid int 726 for i := 0; i <= len(cpus)+1; i++ { 727 if !cpus[i] { 728 invalid = i 729 break 730 } 731 } 732 out, _, err := dockerCmdWithError("run", "--cpuset-cpus", strconv.Itoa(invalid), "busybox", "true") 733 c.Assert(err, check.NotNil) 734 expected := fmt.Sprintf("Error response from daemon: Requested CPUs are not available - requested %s, available: %s", strconv.Itoa(invalid), sysInfo.Cpus) 735 c.Assert(out, checker.Contains, expected) 736 } 737 738 func (s *DockerSuite) TestRunInvalidCpusetMemsFlagValue(c *check.C) { 739 testRequires(c, cgroupCpuset) 740 741 sysInfo := sysinfo.New(true) 742 mems, err := parsers.ParseUintList(sysInfo.Mems) 743 c.Assert(err, check.IsNil) 744 var invalid int 745 for i := 0; i <= len(mems)+1; i++ { 746 if !mems[i] { 747 invalid = i 748 break 749 } 750 } 751 out, _, err := dockerCmdWithError("run", "--cpuset-mems", strconv.Itoa(invalid), "busybox", "true") 752 c.Assert(err, check.NotNil) 753 expected := fmt.Sprintf("Error response from daemon: Requested memory nodes are not available - requested %s, available: %s", strconv.Itoa(invalid), sysInfo.Mems) 754 c.Assert(out, checker.Contains, expected) 755 } 756 757 func (s *DockerSuite) TestRunInvalidCPUShares(c *check.C) { 758 testRequires(c, cpuShare, DaemonIsLinux) 759 out, _, err := dockerCmdWithError("run", "--cpu-shares", "1", "busybox", "echo", "test") 760 c.Assert(err, check.NotNil, check.Commentf(out)) 761 expected := "The minimum allowed cpu-shares is 2" 762 c.Assert(out, checker.Contains, expected) 763 764 out, _, err = dockerCmdWithError("run", "--cpu-shares", "-1", "busybox", "echo", "test") 765 c.Assert(err, check.NotNil, check.Commentf(out)) 766 expected = "shares: invalid argument" 767 c.Assert(out, checker.Contains, expected) 768 769 out, _, err = dockerCmdWithError("run", "--cpu-shares", "99999999", "busybox", "echo", "test") 770 c.Assert(err, check.NotNil, check.Commentf(out)) 771 expected = "The maximum allowed cpu-shares is" 772 c.Assert(out, checker.Contains, expected) 773 } 774 775 func (s *DockerSuite) TestRunWithDefaultShmSize(c *check.C) { 776 testRequires(c, DaemonIsLinux) 777 778 name := "shm-default" 779 out, _ := dockerCmd(c, "run", "--name", name, "busybox", "mount") 780 shmRegex := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`) 781 if !shmRegex.MatchString(out) { 782 c.Fatalf("Expected shm of 64MB in mount command, got %v", out) 783 } 784 shmSize := inspectField(c, name, "HostConfig.ShmSize") 785 c.Assert(shmSize, check.Equals, "67108864") 786 } 787 788 func (s *DockerSuite) TestRunWithShmSize(c *check.C) { 789 testRequires(c, DaemonIsLinux) 790 791 name := "shm" 792 out, _ := dockerCmd(c, "run", "--name", name, "--shm-size=1G", "busybox", "mount") 793 shmRegex := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=1048576k`) 794 if !shmRegex.MatchString(out) { 795 c.Fatalf("Expected shm of 1GB in mount command, got %v", out) 796 } 797 shmSize := inspectField(c, name, "HostConfig.ShmSize") 798 c.Assert(shmSize, check.Equals, "1073741824") 799 } 800 801 func (s *DockerSuite) TestRunTmpfsMountsEnsureOrdered(c *check.C) { 802 tmpFile, err := ioutil.TempFile("", "test") 803 c.Assert(err, check.IsNil) 804 defer tmpFile.Close() 805 out, _ := dockerCmd(c, "run", "--tmpfs", "/run", "-v", tmpFile.Name()+":/run/test", "busybox", "ls", "/run") 806 c.Assert(out, checker.Contains, "test") 807 } 808 809 func (s *DockerSuite) TestRunTmpfsMounts(c *check.C) { 810 // TODO Windows (Post TP5): This test cannot run on a Windows daemon as 811 // Windows does not support tmpfs mounts. 812 testRequires(c, DaemonIsLinux) 813 if out, _, err := dockerCmdWithError("run", "--tmpfs", "/run", "busybox", "touch", "/run/somefile"); err != nil { 814 c.Fatalf("/run directory not mounted on tmpfs %q %s", err, out) 815 } 816 if out, _, err := dockerCmdWithError("run", "--tmpfs", "/run:noexec", "busybox", "touch", "/run/somefile"); err != nil { 817 c.Fatalf("/run directory not mounted on tmpfs %q %s", err, out) 818 } 819 if out, _, err := dockerCmdWithError("run", "--tmpfs", "/run:noexec,nosuid,rw,size=5k,mode=700", "busybox", "touch", "/run/somefile"); err != nil { 820 c.Fatalf("/run failed to mount on tmpfs with valid options %q %s", err, out) 821 } 822 if _, _, err := dockerCmdWithError("run", "--tmpfs", "/run:foobar", "busybox", "touch", "/run/somefile"); err == nil { 823 c.Fatalf("/run mounted on tmpfs when it should have vailed within invalid mount option") 824 } 825 if _, _, err := dockerCmdWithError("run", "--tmpfs", "/run", "-v", "/run:/run", "busybox", "touch", "/run/somefile"); err == nil { 826 c.Fatalf("Should have generated an error saying Duplicate mount points") 827 } 828 } 829 830 func (s *DockerSuite) TestRunTmpfsMountsOverrideImageVolumes(c *check.C) { 831 name := "img-with-volumes" 832 _, err := buildImage( 833 name, 834 ` 835 FROM busybox 836 VOLUME /run 837 RUN touch /run/stuff 838 `, 839 true) 840 if err != nil { 841 c.Fatal(err) 842 } 843 out, _ := dockerCmd(c, "run", "--tmpfs", "/run", name, "ls", "/run") 844 c.Assert(out, checker.Not(checker.Contains), "stuff") 845 } 846 847 // Test case for #22420 848 func (s *DockerSuite) TestRunTmpfsMountsWithOptions(c *check.C) { 849 testRequires(c, DaemonIsLinux) 850 851 expectedOptions := []string{"rw", "nosuid", "nodev", "noexec", "relatime"} 852 out, _ := dockerCmd(c, "run", "--tmpfs", "/tmp", "busybox", "sh", "-c", "mount | grep 'tmpfs on /tmp'") 853 for _, option := range expectedOptions { 854 c.Assert(out, checker.Contains, option) 855 } 856 c.Assert(out, checker.Not(checker.Contains), "size=") 857 858 expectedOptions = []string{"rw", "nosuid", "nodev", "noexec", "relatime"} 859 out, _ = dockerCmd(c, "run", "--tmpfs", "/tmp:rw", "busybox", "sh", "-c", "mount | grep 'tmpfs on /tmp'") 860 for _, option := range expectedOptions { 861 c.Assert(out, checker.Contains, option) 862 } 863 c.Assert(out, checker.Not(checker.Contains), "size=") 864 865 expectedOptions = []string{"rw", "nosuid", "nodev", "relatime", "size=8192k"} 866 out, _ = dockerCmd(c, "run", "--tmpfs", "/tmp:rw,exec,size=8192k", "busybox", "sh", "-c", "mount | grep 'tmpfs on /tmp'") 867 for _, option := range expectedOptions { 868 c.Assert(out, checker.Contains, option) 869 } 870 871 expectedOptions = []string{"rw", "nosuid", "nodev", "noexec", "relatime", "size=4096k"} 872 out, _ = dockerCmd(c, "run", "--tmpfs", "/tmp:rw,size=8192k,exec,size=4096k,noexec", "busybox", "sh", "-c", "mount | grep 'tmpfs on /tmp'") 873 for _, option := range expectedOptions { 874 c.Assert(out, checker.Contains, option) 875 } 876 877 // We use debian:jessie as there is no findmnt in busybox. Also the output will be in the format of 878 // TARGET PROPAGATION 879 // /tmp shared 880 // so we only capture `shared` here. 881 expectedOptions = []string{"shared"} 882 out, _ = dockerCmd(c, "run", "--tmpfs", "/tmp:shared", "debian:jessie", "findmnt", "-o", "TARGET,PROPAGATION", "/tmp") 883 for _, option := range expectedOptions { 884 c.Assert(out, checker.Contains, option) 885 } 886 } 887 888 func (s *DockerSuite) TestRunSysctls(c *check.C) { 889 890 testRequires(c, DaemonIsLinux) 891 var err error 892 893 out, _ := dockerCmd(c, "run", "--sysctl", "net.ipv4.ip_forward=1", "--name", "test", "busybox", "cat", "/proc/sys/net/ipv4/ip_forward") 894 c.Assert(strings.TrimSpace(out), check.Equals, "1") 895 896 out = inspectFieldJSON(c, "test", "HostConfig.Sysctls") 897 898 sysctls := make(map[string]string) 899 err = json.Unmarshal([]byte(out), &sysctls) 900 c.Assert(err, check.IsNil) 901 c.Assert(sysctls["net.ipv4.ip_forward"], check.Equals, "1") 902 903 out, _ = dockerCmd(c, "run", "--sysctl", "net.ipv4.ip_forward=0", "--name", "test1", "busybox", "cat", "/proc/sys/net/ipv4/ip_forward") 904 c.Assert(strings.TrimSpace(out), check.Equals, "0") 905 906 out = inspectFieldJSON(c, "test1", "HostConfig.Sysctls") 907 908 err = json.Unmarshal([]byte(out), &sysctls) 909 c.Assert(err, check.IsNil) 910 c.Assert(sysctls["net.ipv4.ip_forward"], check.Equals, "0") 911 912 runCmd := exec.Command(dockerBinary, "run", "--sysctl", "kernel.foobar=1", "--name", "test2", "busybox", "cat", "/proc/sys/kernel/foobar") 913 out, _, _ = runCommandWithOutput(runCmd) 914 if !strings.Contains(out, "invalid argument") { 915 c.Fatalf("expected --sysctl to fail, got %s", out) 916 } 917 } 918 919 // TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp=/tmp/profile.json debian:jessie unshare' exits with operation not permitted. 920 func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) { 921 testRequires(c, SameHostDaemon, seccompEnabled, NotArm, Apparmor) 922 jsonData := `{ 923 "defaultAction": "SCMP_ACT_ALLOW", 924 "syscalls": [ 925 { 926 "name": "unshare", 927 "action": "SCMP_ACT_ERRNO" 928 } 929 ] 930 }` 931 tmpFile, err := ioutil.TempFile("", "profile.json") 932 if err != nil { 933 c.Fatal(err) 934 } 935 defer tmpFile.Close() 936 937 if _, err := tmpFile.Write([]byte(jsonData)); err != nil { 938 c.Fatal(err) 939 } 940 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor=unconfined", "--security-opt", "seccomp="+tmpFile.Name(), "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc") 941 out, _, _ := runCommandWithOutput(runCmd) 942 if !strings.Contains(out, "Operation not permitted") { 943 c.Fatalf("expected unshare with seccomp profile denied to fail, got %s", out) 944 } 945 } 946 947 // TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp=/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted. 948 func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) { 949 testRequires(c, SameHostDaemon, seccompEnabled) 950 jsonData := `{ 951 "defaultAction": "SCMP_ACT_ALLOW", 952 "syscalls": [ 953 { 954 "name": "chmod", 955 "action": "SCMP_ACT_ERRNO" 956 }, 957 { 958 "name":"fchmod", 959 "action": "SCMP_ACT_ERRNO" 960 }, 961 { 962 "name": "fchmodat", 963 "action":"SCMP_ACT_ERRNO" 964 } 965 ] 966 }` 967 tmpFile, err := ioutil.TempFile("", "profile.json") 968 c.Assert(err, check.IsNil) 969 defer tmpFile.Close() 970 971 if _, err := tmpFile.Write([]byte(jsonData)); err != nil { 972 c.Fatal(err) 973 } 974 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "400", "/etc/hostname") 975 out, _, _ := runCommandWithOutput(runCmd) 976 if !strings.Contains(out, "Operation not permitted") { 977 c.Fatalf("expected chmod with seccomp profile denied to fail, got %s", out) 978 } 979 } 980 981 // TestRunSeccompProfileDenyUnshareUserns checks that 'docker run debian:jessie unshare --map-root-user --user sh -c whoami' with a specific profile to 982 // deny unhare of a userns exits with operation not permitted. 983 func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) { 984 testRequires(c, SameHostDaemon, seccompEnabled, NotArm, Apparmor) 985 // from sched.h 986 jsonData := fmt.Sprintf(`{ 987 "defaultAction": "SCMP_ACT_ALLOW", 988 "syscalls": [ 989 { 990 "name": "unshare", 991 "action": "SCMP_ACT_ERRNO", 992 "args": [ 993 { 994 "index": 0, 995 "value": %d, 996 "op": "SCMP_CMP_EQ" 997 } 998 ] 999 } 1000 ] 1001 }`, uint64(0x10000000)) 1002 tmpFile, err := ioutil.TempFile("", "profile.json") 1003 if err != nil { 1004 c.Fatal(err) 1005 } 1006 defer tmpFile.Close() 1007 1008 if _, err := tmpFile.Write([]byte(jsonData)); err != nil { 1009 c.Fatal(err) 1010 } 1011 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor=unconfined", "--security-opt", "seccomp="+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami") 1012 out, _, _ := runCommandWithOutput(runCmd) 1013 if !strings.Contains(out, "Operation not permitted") { 1014 c.Fatalf("expected unshare userns with seccomp profile denied to fail, got %s", out) 1015 } 1016 } 1017 1018 // TestRunSeccompProfileDenyCloneUserns checks that 'docker run syscall-test' 1019 // with a the default seccomp profile exits with operation not permitted. 1020 func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) { 1021 testRequires(c, SameHostDaemon, seccompEnabled) 1022 ensureSyscallTest(c) 1023 1024 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "userns-test", "id") 1025 out, _, err := runCommandWithOutput(runCmd) 1026 if err == nil || !strings.Contains(out, "clone failed: Operation not permitted") { 1027 c.Fatalf("expected clone userns with default seccomp profile denied to fail, got %s: %v", out, err) 1028 } 1029 } 1030 1031 // TestRunSeccompUnconfinedCloneUserns checks that 1032 // 'docker run --security-opt seccomp=unconfined syscall-test' allows creating a userns. 1033 func (s *DockerSuite) TestRunSeccompUnconfinedCloneUserns(c *check.C) { 1034 testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace, unprivilegedUsernsClone) 1035 ensureSyscallTest(c) 1036 1037 // make sure running w privileged is ok 1038 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "syscall-test", "userns-test", "id") 1039 if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") { 1040 c.Fatalf("expected clone userns with --security-opt seccomp=unconfined to succeed, got %s: %v", out, err) 1041 } 1042 } 1043 1044 // TestRunSeccompAllowPrivCloneUserns checks that 'docker run --privileged syscall-test' 1045 // allows creating a userns. 1046 func (s *DockerSuite) TestRunSeccompAllowPrivCloneUserns(c *check.C) { 1047 testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace) 1048 ensureSyscallTest(c) 1049 1050 // make sure running w privileged is ok 1051 runCmd := exec.Command(dockerBinary, "run", "--privileged", "syscall-test", "userns-test", "id") 1052 if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") { 1053 c.Fatalf("expected clone userns with --privileged to succeed, got %s: %v", out, err) 1054 } 1055 } 1056 1057 // TestRunSeccompProfileAllow32Bit checks that 32 bit code can run on x86_64 1058 // with the default seccomp profile. 1059 func (s *DockerSuite) TestRunSeccompProfileAllow32Bit(c *check.C) { 1060 testRequires(c, SameHostDaemon, seccompEnabled, IsAmd64) 1061 ensureSyscallTest(c) 1062 1063 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "exit32-test", "id") 1064 if out, _, err := runCommandWithOutput(runCmd); err != nil { 1065 c.Fatalf("expected to be able to run 32 bit code, got %s: %v", out, err) 1066 } 1067 } 1068 1069 // TestRunSeccompAllowSetrlimit checks that 'docker run debian:jessie ulimit -v 1048510' succeeds. 1070 func (s *DockerSuite) TestRunSeccompAllowSetrlimit(c *check.C) { 1071 testRequires(c, SameHostDaemon, seccompEnabled) 1072 1073 // ulimit uses setrlimit, so we want to make sure we don't break it 1074 runCmd := exec.Command(dockerBinary, "run", "debian:jessie", "bash", "-c", "ulimit -v 1048510") 1075 if out, _, err := runCommandWithOutput(runCmd); err != nil { 1076 c.Fatalf("expected ulimit with seccomp to succeed, got %s: %v", out, err) 1077 } 1078 } 1079 1080 func (s *DockerSuite) TestRunSeccompDefaultProfileAcct(c *check.C) { 1081 testRequires(c, SameHostDaemon, seccompEnabled, NotUserNamespace) 1082 ensureSyscallTest(c) 1083 1084 out, _, err := dockerCmdWithError("run", "syscall-test", "acct-test") 1085 if err == nil || !strings.Contains(out, "Operation not permitted") { 1086 c.Fatalf("test 0: expected Operation not permitted, got: %s", out) 1087 } 1088 1089 out, _, err = dockerCmdWithError("run", "--cap-add", "sys_admin", "syscall-test", "acct-test") 1090 if err == nil || !strings.Contains(out, "Operation not permitted") { 1091 c.Fatalf("test 1: expected Operation not permitted, got: %s", out) 1092 } 1093 1094 out, _, err = dockerCmdWithError("run", "--cap-add", "sys_pacct", "syscall-test", "acct-test") 1095 if err == nil || !strings.Contains(out, "No such file or directory") { 1096 c.Fatalf("test 2: expected No such file or directory, got: %s", out) 1097 } 1098 1099 out, _, err = dockerCmdWithError("run", "--cap-add", "ALL", "syscall-test", "acct-test") 1100 if err == nil || !strings.Contains(out, "No such file or directory") { 1101 c.Fatalf("test 3: expected No such file or directory, got: %s", out) 1102 } 1103 1104 out, _, err = dockerCmdWithError("run", "--cap-drop", "ALL", "--cap-add", "sys_pacct", "syscall-test", "acct-test") 1105 if err == nil || !strings.Contains(out, "No such file or directory") { 1106 c.Fatalf("test 4: expected No such file or directory, got: %s", out) 1107 } 1108 } 1109 1110 func (s *DockerSuite) TestRunSeccompDefaultProfileNS(c *check.C) { 1111 testRequires(c, SameHostDaemon, seccompEnabled, NotUserNamespace) 1112 ensureSyscallTest(c) 1113 1114 out, _, err := dockerCmdWithError("run", "syscall-test", "ns-test", "echo", "hello0") 1115 if err == nil || !strings.Contains(out, "Operation not permitted") { 1116 c.Fatalf("test 0: expected Operation not permitted, got: %s", out) 1117 } 1118 1119 out, _, err = dockerCmdWithError("run", "--cap-add", "sys_admin", "syscall-test", "ns-test", "echo", "hello1") 1120 if err != nil || !strings.Contains(out, "hello1") { 1121 c.Fatalf("test 1: expected hello1, got: %s, %v", out, err) 1122 } 1123 1124 out, _, err = dockerCmdWithError("run", "--cap-drop", "all", "--cap-add", "sys_admin", "syscall-test", "ns-test", "echo", "hello2") 1125 if err != nil || !strings.Contains(out, "hello2") { 1126 c.Fatalf("test 2: expected hello2, got: %s, %v", out, err) 1127 } 1128 1129 out, _, err = dockerCmdWithError("run", "--cap-add", "ALL", "syscall-test", "ns-test", "echo", "hello3") 1130 if err != nil || !strings.Contains(out, "hello3") { 1131 c.Fatalf("test 3: expected hello3, got: %s, %v", out, err) 1132 } 1133 1134 out, _, err = dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "acct-test") 1135 if err == nil || !strings.Contains(out, "No such file or directory") { 1136 c.Fatalf("test 4: expected No such file or directory, got: %s", out) 1137 } 1138 1139 out, _, err = dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "ns-test", "echo", "hello4") 1140 if err != nil || !strings.Contains(out, "hello4") { 1141 c.Fatalf("test 5: expected hello4, got: %s, %v", out, err) 1142 } 1143 } 1144 1145 // TestRunNoNewPrivSetuid checks that --security-opt=no-new-privileges prevents 1146 // effective uid transtions on executing setuid binaries. 1147 func (s *DockerSuite) TestRunNoNewPrivSetuid(c *check.C) { 1148 testRequires(c, DaemonIsLinux, NotUserNamespace, SameHostDaemon) 1149 ensureNNPTest(c) 1150 1151 // test that running a setuid binary results in no effective uid transition 1152 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "no-new-privileges", "--user", "1000", "nnp-test", "/usr/bin/nnp-test") 1153 if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "EUID=1000") { 1154 c.Fatalf("expected output to contain EUID=1000, got %s: %v", out, err) 1155 } 1156 } 1157 1158 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesChown(c *check.C) { 1159 testRequires(c, DaemonIsLinux) 1160 ensureSyscallTest(c) 1161 1162 // test that a root user has default capability CAP_CHOWN 1163 runCmd := exec.Command(dockerBinary, "run", "busybox", "chown", "100", "/tmp") 1164 _, _, err := runCommandWithOutput(runCmd) 1165 c.Assert(err, check.IsNil) 1166 // test that non root user does not have default capability CAP_CHOWN 1167 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "chown", "100", "/tmp") 1168 out, _, err := runCommandWithOutput(runCmd) 1169 c.Assert(err, checker.NotNil, check.Commentf(out)) 1170 c.Assert(out, checker.Contains, "Operation not permitted") 1171 // test that root user can drop default capability CAP_CHOWN 1172 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "chown", "busybox", "chown", "100", "/tmp") 1173 out, _, err = runCommandWithOutput(runCmd) 1174 c.Assert(err, checker.NotNil, check.Commentf(out)) 1175 c.Assert(out, checker.Contains, "Operation not permitted") 1176 } 1177 1178 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesDacOverride(c *check.C) { 1179 testRequires(c, DaemonIsLinux) 1180 ensureSyscallTest(c) 1181 1182 // test that a root user has default capability CAP_DAC_OVERRIDE 1183 runCmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo test > /etc/passwd") 1184 _, _, err := runCommandWithOutput(runCmd) 1185 c.Assert(err, check.IsNil) 1186 // test that non root user does not have default capability CAP_DAC_OVERRIDE 1187 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "sh", "-c", "echo test > /etc/passwd") 1188 out, _, err := runCommandWithOutput(runCmd) 1189 c.Assert(err, checker.NotNil, check.Commentf(out)) 1190 c.Assert(out, checker.Contains, "Permission denied") 1191 // TODO test that root user can drop default capability CAP_DAC_OVERRIDE 1192 } 1193 1194 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesFowner(c *check.C) { 1195 testRequires(c, DaemonIsLinux) 1196 ensureSyscallTest(c) 1197 1198 // test that a root user has default capability CAP_FOWNER 1199 runCmd := exec.Command(dockerBinary, "run", "busybox", "chmod", "777", "/etc/passwd") 1200 _, _, err := runCommandWithOutput(runCmd) 1201 c.Assert(err, check.IsNil) 1202 // test that non root user does not have default capability CAP_FOWNER 1203 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "chmod", "777", "/etc/passwd") 1204 out, _, err := runCommandWithOutput(runCmd) 1205 c.Assert(err, checker.NotNil, check.Commentf(out)) 1206 c.Assert(out, checker.Contains, "Operation not permitted") 1207 // TODO test that root user can drop default capability CAP_FOWNER 1208 } 1209 1210 // TODO CAP_KILL 1211 1212 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesSetuid(c *check.C) { 1213 testRequires(c, DaemonIsLinux) 1214 ensureSyscallTest(c) 1215 1216 // test that a root user has default capability CAP_SETUID 1217 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "setuid-test") 1218 _, _, err := runCommandWithOutput(runCmd) 1219 c.Assert(err, check.IsNil) 1220 // test that non root user does not have default capability CAP_SETUID 1221 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "setuid-test") 1222 out, _, err := runCommandWithOutput(runCmd) 1223 c.Assert(err, checker.NotNil, check.Commentf(out)) 1224 c.Assert(out, checker.Contains, "Operation not permitted") 1225 // test that root user can drop default capability CAP_SETUID 1226 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "setuid", "syscall-test", "setuid-test") 1227 out, _, err = runCommandWithOutput(runCmd) 1228 c.Assert(err, checker.NotNil, check.Commentf(out)) 1229 c.Assert(out, checker.Contains, "Operation not permitted") 1230 } 1231 1232 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesSetgid(c *check.C) { 1233 testRequires(c, DaemonIsLinux) 1234 ensureSyscallTest(c) 1235 1236 // test that a root user has default capability CAP_SETGID 1237 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "setgid-test") 1238 _, _, err := runCommandWithOutput(runCmd) 1239 c.Assert(err, check.IsNil) 1240 // test that non root user does not have default capability CAP_SETGID 1241 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "setgid-test") 1242 out, _, err := runCommandWithOutput(runCmd) 1243 c.Assert(err, checker.NotNil, check.Commentf(out)) 1244 c.Assert(out, checker.Contains, "Operation not permitted") 1245 // test that root user can drop default capability CAP_SETGID 1246 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "setgid", "syscall-test", "setgid-test") 1247 out, _, err = runCommandWithOutput(runCmd) 1248 c.Assert(err, checker.NotNil, check.Commentf(out)) 1249 c.Assert(out, checker.Contains, "Operation not permitted") 1250 } 1251 1252 // TODO CAP_SETPCAP 1253 1254 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesNetBindService(c *check.C) { 1255 testRequires(c, DaemonIsLinux) 1256 ensureSyscallTest(c) 1257 1258 // test that a root user has default capability CAP_NET_BIND_SERVICE 1259 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "socket-test") 1260 _, _, err := runCommandWithOutput(runCmd) 1261 c.Assert(err, check.IsNil) 1262 // test that non root user does not have default capability CAP_NET_BIND_SERVICE 1263 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "socket-test") 1264 out, _, err := runCommandWithOutput(runCmd) 1265 c.Assert(err, checker.NotNil, check.Commentf(out)) 1266 c.Assert(out, checker.Contains, "Permission denied") 1267 // test that root user can drop default capability CAP_NET_BIND_SERVICE 1268 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "net_bind_service", "syscall-test", "socket-test") 1269 out, _, err = runCommandWithOutput(runCmd) 1270 c.Assert(err, checker.NotNil, check.Commentf(out)) 1271 c.Assert(out, checker.Contains, "Permission denied") 1272 } 1273 1274 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesNetRaw(c *check.C) { 1275 testRequires(c, DaemonIsLinux) 1276 ensureSyscallTest(c) 1277 1278 // test that a root user has default capability CAP_NET_RAW 1279 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "raw-test") 1280 _, _, err := runCommandWithOutput(runCmd) 1281 c.Assert(err, check.IsNil) 1282 // test that non root user does not have default capability CAP_NET_RAW 1283 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "raw-test") 1284 out, _, err := runCommandWithOutput(runCmd) 1285 c.Assert(err, checker.NotNil, check.Commentf(out)) 1286 c.Assert(out, checker.Contains, "Operation not permitted") 1287 // test that root user can drop default capability CAP_NET_RAW 1288 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "net_raw", "syscall-test", "raw-test") 1289 out, _, err = runCommandWithOutput(runCmd) 1290 c.Assert(err, checker.NotNil, check.Commentf(out)) 1291 c.Assert(out, checker.Contains, "Operation not permitted") 1292 } 1293 1294 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesChroot(c *check.C) { 1295 testRequires(c, DaemonIsLinux) 1296 ensureSyscallTest(c) 1297 1298 // test that a root user has default capability CAP_SYS_CHROOT 1299 runCmd := exec.Command(dockerBinary, "run", "busybox", "chroot", "/", "/bin/true") 1300 _, _, err := runCommandWithOutput(runCmd) 1301 c.Assert(err, check.IsNil) 1302 // test that non root user does not have default capability CAP_SYS_CHROOT 1303 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "chroot", "/", "/bin/true") 1304 out, _, err := runCommandWithOutput(runCmd) 1305 c.Assert(err, checker.NotNil, check.Commentf(out)) 1306 c.Assert(out, checker.Contains, "Operation not permitted") 1307 // test that root user can drop default capability CAP_SYS_CHROOT 1308 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "sys_chroot", "busybox", "chroot", "/", "/bin/true") 1309 out, _, err = runCommandWithOutput(runCmd) 1310 c.Assert(err, checker.NotNil, check.Commentf(out)) 1311 c.Assert(out, checker.Contains, "Operation not permitted") 1312 } 1313 1314 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesMknod(c *check.C) { 1315 testRequires(c, DaemonIsLinux, NotUserNamespace) 1316 ensureSyscallTest(c) 1317 1318 // test that a root user has default capability CAP_MKNOD 1319 runCmd := exec.Command(dockerBinary, "run", "busybox", "mknod", "/tmp/node", "b", "1", "2") 1320 _, _, err := runCommandWithOutput(runCmd) 1321 c.Assert(err, check.IsNil) 1322 // test that non root user does not have default capability CAP_MKNOD 1323 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "mknod", "/tmp/node", "b", "1", "2") 1324 out, _, err := runCommandWithOutput(runCmd) 1325 c.Assert(err, checker.NotNil, check.Commentf(out)) 1326 c.Assert(out, checker.Contains, "Operation not permitted") 1327 // test that root user can drop default capability CAP_MKNOD 1328 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "mknod", "busybox", "mknod", "/tmp/node", "b", "1", "2") 1329 out, _, err = runCommandWithOutput(runCmd) 1330 c.Assert(err, checker.NotNil, check.Commentf(out)) 1331 c.Assert(out, checker.Contains, "Operation not permitted") 1332 } 1333 1334 // TODO CAP_AUDIT_WRITE 1335 // TODO CAP_SETFCAP 1336 1337 func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) { 1338 testRequires(c, SameHostDaemon, Apparmor) 1339 1340 // running w seccomp unconfined tests the apparmor profile 1341 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/cgroup") 1342 if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) { 1343 c.Fatalf("expected chmod 777 /proc/1/cgroup to fail, got %s: %v", out, err) 1344 } 1345 1346 runCmd = exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/attr/current") 1347 if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) { 1348 c.Fatalf("expected chmod 777 /proc/1/attr/current to fail, got %s: %v", out, err) 1349 } 1350 } 1351 1352 // make sure the default profile can be successfully parsed (using unshare as it is 1353 // something which we know is blocked in the default profile) 1354 func (s *DockerSuite) TestRunSeccompWithDefaultProfile(c *check.C) { 1355 testRequires(c, SameHostDaemon, seccompEnabled) 1356 1357 out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp=../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami") 1358 c.Assert(err, checker.NotNil, check.Commentf(out)) 1359 c.Assert(strings.TrimSpace(out), checker.Equals, "unshare: unshare failed: Operation not permitted") 1360 } 1361 1362 // TestRunDeviceSymlink checks run with device that follows symlink (#13840 and #22271) 1363 func (s *DockerSuite) TestRunDeviceSymlink(c *check.C) { 1364 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm, SameHostDaemon) 1365 if _, err := os.Stat("/dev/zero"); err != nil { 1366 c.Skip("Host does not have /dev/zero") 1367 } 1368 1369 // Create a temporary directory to create symlink 1370 tmpDir, err := ioutil.TempDir("", "docker_device_follow_symlink_tests") 1371 c.Assert(err, checker.IsNil) 1372 1373 defer os.RemoveAll(tmpDir) 1374 1375 // Create a symbolic link to /dev/zero 1376 symZero := filepath.Join(tmpDir, "zero") 1377 err = os.Symlink("/dev/zero", symZero) 1378 c.Assert(err, checker.IsNil) 1379 1380 // Create a temporary file "temp" inside tmpDir, write some data to "tmpDir/temp", 1381 // then create a symlink "tmpDir/file" to the temporary file "tmpDir/temp". 1382 tmpFile := filepath.Join(tmpDir, "temp") 1383 err = ioutil.WriteFile(tmpFile, []byte("temp"), 0666) 1384 c.Assert(err, checker.IsNil) 1385 symFile := filepath.Join(tmpDir, "file") 1386 err = os.Symlink(tmpFile, symFile) 1387 c.Assert(err, checker.IsNil) 1388 1389 // Create a symbolic link to /dev/zero, this time with a relative path (#22271) 1390 err = os.Symlink("zero", "/dev/symzero") 1391 if err != nil { 1392 c.Fatal("/dev/symzero creation failed") 1393 } 1394 // We need to remove this symbolic link here as it is created in /dev/, not temporary directory as above 1395 defer os.Remove("/dev/symzero") 1396 1397 // md5sum of 'dd if=/dev/zero bs=4K count=8' is bb7df04e1b0a2570657527a7e108ae23 1398 out, _ := dockerCmd(c, "run", "--device", symZero+":/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum") 1399 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "bb7df04e1b0a2570657527a7e108ae23", check.Commentf("expected output bb7df04e1b0a2570657527a7e108ae23")) 1400 1401 // symlink "tmpDir/file" to a file "tmpDir/temp" will result in an error as it is not a device. 1402 out, _, err = dockerCmdWithError("run", "--device", symFile+":/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum") 1403 c.Assert(err, check.NotNil) 1404 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "not a device node", check.Commentf("expected output 'not a device node'")) 1405 1406 // md5sum of 'dd if=/dev/zero bs=4K count=8' is bb7df04e1b0a2570657527a7e108ae23 (this time check with relative path backed, see #22271) 1407 out, _ = dockerCmd(c, "run", "--device", "/dev/symzero:/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum") 1408 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "bb7df04e1b0a2570657527a7e108ae23", check.Commentf("expected output bb7df04e1b0a2570657527a7e108ae23")) 1409 } 1410 1411 // TestRunPIDsLimit makes sure the pids cgroup is set with --pids-limit 1412 func (s *DockerSuite) TestRunPIDsLimit(c *check.C) { 1413 testRequires(c, pidsLimit) 1414 1415 file := "/sys/fs/cgroup/pids/pids.max" 1416 out, _ := dockerCmd(c, "run", "--name", "skittles", "--pids-limit", "4", "busybox", "cat", file) 1417 c.Assert(strings.TrimSpace(out), checker.Equals, "4") 1418 1419 out = inspectField(c, "skittles", "HostConfig.PidsLimit") 1420 c.Assert(out, checker.Equals, "4", check.Commentf("setting the pids limit failed")) 1421 } 1422 1423 func (s *DockerSuite) TestRunPrivilegedAllowedDevices(c *check.C) { 1424 testRequires(c, DaemonIsLinux, NotUserNamespace) 1425 1426 file := "/sys/fs/cgroup/devices/devices.list" 1427 out, _ := dockerCmd(c, "run", "--privileged", "busybox", "cat", file) 1428 c.Logf("out: %q", out) 1429 c.Assert(strings.TrimSpace(out), checker.Equals, "a *:* rwm") 1430 } 1431 1432 func (s *DockerSuite) TestRunUserDeviceAllowed(c *check.C) { 1433 testRequires(c, DaemonIsLinux) 1434 1435 fi, err := os.Stat("/dev/snd/timer") 1436 if err != nil { 1437 c.Skip("Host does not have /dev/snd/timer") 1438 } 1439 stat, ok := fi.Sys().(*syscall.Stat_t) 1440 if !ok { 1441 c.Skip("Could not stat /dev/snd/timer") 1442 } 1443 1444 file := "/sys/fs/cgroup/devices/devices.list" 1445 out, _ := dockerCmd(c, "run", "--device", "/dev/snd/timer:w", "busybox", "cat", file) 1446 c.Assert(out, checker.Contains, fmt.Sprintf("c %d:%d w", stat.Rdev/256, stat.Rdev%256)) 1447 } 1448 1449 func (s *DockerDaemonSuite) TestRunSeccompJSONNewFormat(c *check.C) { 1450 testRequires(c, SameHostDaemon, seccompEnabled) 1451 1452 err := s.d.StartWithBusybox() 1453 c.Assert(err, check.IsNil) 1454 1455 jsonData := `{ 1456 "defaultAction": "SCMP_ACT_ALLOW", 1457 "syscalls": [ 1458 { 1459 "names": ["chmod", "fchmod", "fchmodat"], 1460 "action": "SCMP_ACT_ERRNO" 1461 } 1462 ] 1463 }` 1464 tmpFile, err := ioutil.TempFile("", "profile.json") 1465 c.Assert(err, check.IsNil) 1466 defer tmpFile.Close() 1467 _, err = tmpFile.Write([]byte(jsonData)) 1468 c.Assert(err, check.IsNil) 1469 1470 out, err := s.d.Cmd("run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "777", ".") 1471 c.Assert(err, check.NotNil) 1472 c.Assert(out, checker.Contains, "Operation not permitted") 1473 } 1474 1475 func (s *DockerDaemonSuite) TestRunSeccompJSONNoNameAndNames(c *check.C) { 1476 testRequires(c, SameHostDaemon, seccompEnabled) 1477 1478 err := s.d.StartWithBusybox() 1479 c.Assert(err, check.IsNil) 1480 1481 jsonData := `{ 1482 "defaultAction": "SCMP_ACT_ALLOW", 1483 "syscalls": [ 1484 { 1485 "name": "chmod", 1486 "names": ["fchmod", "fchmodat"], 1487 "action": "SCMP_ACT_ERRNO" 1488 } 1489 ] 1490 }` 1491 tmpFile, err := ioutil.TempFile("", "profile.json") 1492 c.Assert(err, check.IsNil) 1493 defer tmpFile.Close() 1494 _, err = tmpFile.Write([]byte(jsonData)) 1495 c.Assert(err, check.IsNil) 1496 1497 out, err := s.d.Cmd("run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "777", ".") 1498 c.Assert(err, check.NotNil) 1499 c.Assert(out, checker.Contains, "'name' and 'names' were specified in the seccomp profile, use either 'name' or 'names'") 1500 } 1501 1502 func (s *DockerDaemonSuite) TestRunSeccompJSONNoArchAndArchMap(c *check.C) { 1503 testRequires(c, SameHostDaemon, seccompEnabled) 1504 1505 err := s.d.StartWithBusybox() 1506 c.Assert(err, check.IsNil) 1507 1508 jsonData := `{ 1509 "archMap": [ 1510 { 1511 "architecture": "SCMP_ARCH_X86_64", 1512 "subArchitectures": [ 1513 "SCMP_ARCH_X86", 1514 "SCMP_ARCH_X32" 1515 ] 1516 } 1517 ], 1518 "architectures": [ 1519 "SCMP_ARCH_X32" 1520 ], 1521 "defaultAction": "SCMP_ACT_ALLOW", 1522 "syscalls": [ 1523 { 1524 "names": ["chmod", "fchmod", "fchmodat"], 1525 "action": "SCMP_ACT_ERRNO" 1526 } 1527 ] 1528 }` 1529 tmpFile, err := ioutil.TempFile("", "profile.json") 1530 c.Assert(err, check.IsNil) 1531 defer tmpFile.Close() 1532 _, err = tmpFile.Write([]byte(jsonData)) 1533 c.Assert(err, check.IsNil) 1534 1535 out, err := s.d.Cmd("run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "777", ".") 1536 c.Assert(err, check.NotNil) 1537 c.Assert(out, checker.Contains, "'architectures' and 'archMap' were specified in the seccomp profile, use either 'architectures' or 'archMap'") 1538 } 1539 1540 func (s *DockerDaemonSuite) TestRunWithDaemonDefaultSeccompProfile(c *check.C) { 1541 testRequires(c, SameHostDaemon, seccompEnabled) 1542 1543 err := s.d.StartWithBusybox() 1544 c.Assert(err, check.IsNil) 1545 1546 // 1) verify I can run containers with the Docker default shipped profile which allows chmod 1547 _, err = s.d.Cmd("run", "busybox", "chmod", "777", ".") 1548 c.Assert(err, check.IsNil) 1549 1550 jsonData := `{ 1551 "defaultAction": "SCMP_ACT_ALLOW", 1552 "syscalls": [ 1553 { 1554 "name": "chmod", 1555 "action": "SCMP_ACT_ERRNO" 1556 } 1557 ] 1558 }` 1559 tmpFile, err := ioutil.TempFile("", "profile.json") 1560 c.Assert(err, check.IsNil) 1561 defer tmpFile.Close() 1562 _, err = tmpFile.Write([]byte(jsonData)) 1563 c.Assert(err, check.IsNil) 1564 1565 // 2) restart the daemon and add a custom seccomp profile in which we deny chmod 1566 err = s.d.Restart("--seccomp-profile=" + tmpFile.Name()) 1567 c.Assert(err, check.IsNil) 1568 1569 out, err := s.d.Cmd("run", "busybox", "chmod", "777", ".") 1570 c.Assert(err, check.NotNil) 1571 c.Assert(out, checker.Contains, "Operation not permitted") 1572 } 1573 1574 func (s *DockerSuite) TestRunWithNanoCPUs(c *check.C) { 1575 testRequires(c, cpuCfsQuota, cpuCfsPeriod) 1576 1577 file1 := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us" 1578 file2 := "/sys/fs/cgroup/cpu/cpu.cfs_period_us" 1579 out, _ := dockerCmd(c, "run", "--cpus", "0.5", "--name", "test", "busybox", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2)) 1580 c.Assert(strings.TrimSpace(out), checker.Equals, "50000\n100000") 1581 1582 out = inspectField(c, "test", "HostConfig.NanoCpus") 1583 c.Assert(out, checker.Equals, "5e+08", check.Commentf("setting the Nano CPUs failed")) 1584 out = inspectField(c, "test", "HostConfig.CpuQuota") 1585 c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS quota should be 0")) 1586 out = inspectField(c, "test", "HostConfig.CpuPeriod") 1587 c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS period should be 0")) 1588 1589 out, _, err := dockerCmdWithError("run", "--cpus", "0.5", "--cpu-quota", "50000", "--cpu-period", "100000", "busybox", "sh") 1590 c.Assert(err, check.NotNil) 1591 c.Assert(out, checker.Contains, "Conflicting options: Nano CPUs and CPU Period cannot both be set") 1592 }