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