github.com/sld880311/docker@v0.0.0-20200524143708-d5593973a475/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 unshare 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 // TestRunSeccompProfileDenyUnusualSocketFamilies checks that rarely used socket families such as Appletalk are blocked by the default profile 1019 func (s *DockerSuite) TestRunSeccompProfileDenyUnusualSocketFamilies(c *check.C) { 1020 testRequires(c, SameHostDaemon, seccompEnabled) 1021 ensureSyscallTest(c) 1022 1023 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "appletalk-test") 1024 _, _, err := runCommandWithOutput(runCmd) 1025 if err != nil { 1026 c.Fatal("expected opening appletalk socket family to fail") 1027 } 1028 } 1029 1030 // TestRunSeccompProfileDenyCloneUserns checks that 'docker run syscall-test' 1031 // with a the default seccomp profile exits with operation not permitted. 1032 func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) { 1033 testRequires(c, SameHostDaemon, seccompEnabled) 1034 ensureSyscallTest(c) 1035 1036 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "userns-test", "id") 1037 out, _, err := runCommandWithOutput(runCmd) 1038 if err == nil || !strings.Contains(out, "clone failed: Operation not permitted") { 1039 c.Fatalf("expected clone userns with default seccomp profile denied to fail, got %s: %v", out, err) 1040 } 1041 } 1042 1043 // TestRunSeccompUnconfinedCloneUserns checks that 1044 // 'docker run --security-opt seccomp=unconfined syscall-test' allows creating a userns. 1045 func (s *DockerSuite) TestRunSeccompUnconfinedCloneUserns(c *check.C) { 1046 testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace, unprivilegedUsernsClone) 1047 ensureSyscallTest(c) 1048 1049 // make sure running w privileged is ok 1050 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "syscall-test", "userns-test", "id") 1051 if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") { 1052 c.Fatalf("expected clone userns with --security-opt seccomp=unconfined to succeed, got %s: %v", out, err) 1053 } 1054 } 1055 1056 // TestRunSeccompAllowPrivCloneUserns checks that 'docker run --privileged syscall-test' 1057 // allows creating a userns. 1058 func (s *DockerSuite) TestRunSeccompAllowPrivCloneUserns(c *check.C) { 1059 testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace) 1060 ensureSyscallTest(c) 1061 1062 // make sure running w privileged is ok 1063 runCmd := exec.Command(dockerBinary, "run", "--privileged", "syscall-test", "userns-test", "id") 1064 if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") { 1065 c.Fatalf("expected clone userns with --privileged to succeed, got %s: %v", out, err) 1066 } 1067 } 1068 1069 // TestRunSeccompProfileAllow32Bit checks that 32 bit code can run on x86_64 1070 // with the default seccomp profile. 1071 func (s *DockerSuite) TestRunSeccompProfileAllow32Bit(c *check.C) { 1072 testRequires(c, SameHostDaemon, seccompEnabled, IsAmd64) 1073 ensureSyscallTest(c) 1074 1075 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "exit32-test", "id") 1076 if out, _, err := runCommandWithOutput(runCmd); err != nil { 1077 c.Fatalf("expected to be able to run 32 bit code, got %s: %v", out, err) 1078 } 1079 } 1080 1081 // TestRunSeccompAllowSetrlimit checks that 'docker run debian:jessie ulimit -v 1048510' succeeds. 1082 func (s *DockerSuite) TestRunSeccompAllowSetrlimit(c *check.C) { 1083 testRequires(c, SameHostDaemon, seccompEnabled) 1084 1085 // ulimit uses setrlimit, so we want to make sure we don't break it 1086 runCmd := exec.Command(dockerBinary, "run", "debian:jessie", "bash", "-c", "ulimit -v 1048510") 1087 if out, _, err := runCommandWithOutput(runCmd); err != nil { 1088 c.Fatalf("expected ulimit with seccomp to succeed, got %s: %v", out, err) 1089 } 1090 } 1091 1092 func (s *DockerSuite) TestRunSeccompDefaultProfileAcct(c *check.C) { 1093 testRequires(c, SameHostDaemon, seccompEnabled, NotUserNamespace) 1094 ensureSyscallTest(c) 1095 1096 out, _, err := dockerCmdWithError("run", "syscall-test", "acct-test") 1097 if err == nil || !strings.Contains(out, "Operation not permitted") { 1098 c.Fatalf("test 0: expected Operation not permitted, got: %s", out) 1099 } 1100 1101 out, _, err = dockerCmdWithError("run", "--cap-add", "sys_admin", "syscall-test", "acct-test") 1102 if err == nil || !strings.Contains(out, "Operation not permitted") { 1103 c.Fatalf("test 1: expected Operation not permitted, got: %s", out) 1104 } 1105 1106 out, _, err = dockerCmdWithError("run", "--cap-add", "sys_pacct", "syscall-test", "acct-test") 1107 if err == nil || !strings.Contains(out, "No such file or directory") { 1108 c.Fatalf("test 2: expected No such file or directory, got: %s", out) 1109 } 1110 1111 out, _, err = dockerCmdWithError("run", "--cap-add", "ALL", "syscall-test", "acct-test") 1112 if err == nil || !strings.Contains(out, "No such file or directory") { 1113 c.Fatalf("test 3: expected No such file or directory, got: %s", out) 1114 } 1115 1116 out, _, err = dockerCmdWithError("run", "--cap-drop", "ALL", "--cap-add", "sys_pacct", "syscall-test", "acct-test") 1117 if err == nil || !strings.Contains(out, "No such file or directory") { 1118 c.Fatalf("test 4: expected No such file or directory, got: %s", out) 1119 } 1120 } 1121 1122 func (s *DockerSuite) TestRunSeccompDefaultProfileNS(c *check.C) { 1123 testRequires(c, SameHostDaemon, seccompEnabled, NotUserNamespace) 1124 ensureSyscallTest(c) 1125 1126 out, _, err := dockerCmdWithError("run", "syscall-test", "ns-test", "echo", "hello0") 1127 if err == nil || !strings.Contains(out, "Operation not permitted") { 1128 c.Fatalf("test 0: expected Operation not permitted, got: %s", out) 1129 } 1130 1131 out, _, err = dockerCmdWithError("run", "--cap-add", "sys_admin", "syscall-test", "ns-test", "echo", "hello1") 1132 if err != nil || !strings.Contains(out, "hello1") { 1133 c.Fatalf("test 1: expected hello1, got: %s, %v", out, err) 1134 } 1135 1136 out, _, err = dockerCmdWithError("run", "--cap-drop", "all", "--cap-add", "sys_admin", "syscall-test", "ns-test", "echo", "hello2") 1137 if err != nil || !strings.Contains(out, "hello2") { 1138 c.Fatalf("test 2: expected hello2, got: %s, %v", out, err) 1139 } 1140 1141 out, _, err = dockerCmdWithError("run", "--cap-add", "ALL", "syscall-test", "ns-test", "echo", "hello3") 1142 if err != nil || !strings.Contains(out, "hello3") { 1143 c.Fatalf("test 3: expected hello3, got: %s, %v", out, err) 1144 } 1145 1146 out, _, err = dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "acct-test") 1147 if err == nil || !strings.Contains(out, "No such file or directory") { 1148 c.Fatalf("test 4: expected No such file or directory, got: %s", out) 1149 } 1150 1151 out, _, err = dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "ns-test", "echo", "hello4") 1152 if err != nil || !strings.Contains(out, "hello4") { 1153 c.Fatalf("test 5: expected hello4, got: %s, %v", out, err) 1154 } 1155 } 1156 1157 // TestRunNoNewPrivSetuid checks that --security-opt=no-new-privileges prevents 1158 // effective uid transtions on executing setuid binaries. 1159 func (s *DockerSuite) TestRunNoNewPrivSetuid(c *check.C) { 1160 testRequires(c, DaemonIsLinux, NotUserNamespace, SameHostDaemon) 1161 ensureNNPTest(c) 1162 1163 // test that running a setuid binary results in no effective uid transition 1164 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "no-new-privileges", "--user", "1000", "nnp-test", "/usr/bin/nnp-test") 1165 if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "EUID=1000") { 1166 c.Fatalf("expected output to contain EUID=1000, got %s: %v", out, err) 1167 } 1168 } 1169 1170 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesChown(c *check.C) { 1171 testRequires(c, DaemonIsLinux) 1172 ensureSyscallTest(c) 1173 1174 // test that a root user has default capability CAP_CHOWN 1175 runCmd := exec.Command(dockerBinary, "run", "busybox", "chown", "100", "/tmp") 1176 _, _, err := runCommandWithOutput(runCmd) 1177 c.Assert(err, check.IsNil) 1178 // test that non root user does not have default capability CAP_CHOWN 1179 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "chown", "100", "/tmp") 1180 out, _, err := runCommandWithOutput(runCmd) 1181 c.Assert(err, checker.NotNil, check.Commentf(out)) 1182 c.Assert(out, checker.Contains, "Operation not permitted") 1183 // test that root user can drop default capability CAP_CHOWN 1184 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "chown", "busybox", "chown", "100", "/tmp") 1185 out, _, err = runCommandWithOutput(runCmd) 1186 c.Assert(err, checker.NotNil, check.Commentf(out)) 1187 c.Assert(out, checker.Contains, "Operation not permitted") 1188 } 1189 1190 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesDacOverride(c *check.C) { 1191 testRequires(c, DaemonIsLinux) 1192 ensureSyscallTest(c) 1193 1194 // test that a root user has default capability CAP_DAC_OVERRIDE 1195 runCmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo test > /etc/passwd") 1196 _, _, err := runCommandWithOutput(runCmd) 1197 c.Assert(err, check.IsNil) 1198 // test that non root user does not have default capability CAP_DAC_OVERRIDE 1199 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "sh", "-c", "echo test > /etc/passwd") 1200 out, _, err := runCommandWithOutput(runCmd) 1201 c.Assert(err, checker.NotNil, check.Commentf(out)) 1202 c.Assert(out, checker.Contains, "Permission denied") 1203 // TODO test that root user can drop default capability CAP_DAC_OVERRIDE 1204 } 1205 1206 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesFowner(c *check.C) { 1207 testRequires(c, DaemonIsLinux) 1208 ensureSyscallTest(c) 1209 1210 // test that a root user has default capability CAP_FOWNER 1211 runCmd := exec.Command(dockerBinary, "run", "busybox", "chmod", "777", "/etc/passwd") 1212 _, _, err := runCommandWithOutput(runCmd) 1213 c.Assert(err, check.IsNil) 1214 // test that non root user does not have default capability CAP_FOWNER 1215 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "chmod", "777", "/etc/passwd") 1216 out, _, err := runCommandWithOutput(runCmd) 1217 c.Assert(err, checker.NotNil, check.Commentf(out)) 1218 c.Assert(out, checker.Contains, "Operation not permitted") 1219 // TODO test that root user can drop default capability CAP_FOWNER 1220 } 1221 1222 // TODO CAP_KILL 1223 1224 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesSetuid(c *check.C) { 1225 testRequires(c, DaemonIsLinux) 1226 ensureSyscallTest(c) 1227 1228 // test that a root user has default capability CAP_SETUID 1229 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "setuid-test") 1230 _, _, err := runCommandWithOutput(runCmd) 1231 c.Assert(err, check.IsNil) 1232 // test that non root user does not have default capability CAP_SETUID 1233 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "setuid-test") 1234 out, _, err := runCommandWithOutput(runCmd) 1235 c.Assert(err, checker.NotNil, check.Commentf(out)) 1236 c.Assert(out, checker.Contains, "Operation not permitted") 1237 // test that root user can drop default capability CAP_SETUID 1238 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "setuid", "syscall-test", "setuid-test") 1239 out, _, err = runCommandWithOutput(runCmd) 1240 c.Assert(err, checker.NotNil, check.Commentf(out)) 1241 c.Assert(out, checker.Contains, "Operation not permitted") 1242 } 1243 1244 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesSetgid(c *check.C) { 1245 testRequires(c, DaemonIsLinux) 1246 ensureSyscallTest(c) 1247 1248 // test that a root user has default capability CAP_SETGID 1249 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "setgid-test") 1250 _, _, err := runCommandWithOutput(runCmd) 1251 c.Assert(err, check.IsNil) 1252 // test that non root user does not have default capability CAP_SETGID 1253 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "setgid-test") 1254 out, _, err := runCommandWithOutput(runCmd) 1255 c.Assert(err, checker.NotNil, check.Commentf(out)) 1256 c.Assert(out, checker.Contains, "Operation not permitted") 1257 // test that root user can drop default capability CAP_SETGID 1258 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "setgid", "syscall-test", "setgid-test") 1259 out, _, err = runCommandWithOutput(runCmd) 1260 c.Assert(err, checker.NotNil, check.Commentf(out)) 1261 c.Assert(out, checker.Contains, "Operation not permitted") 1262 } 1263 1264 // TODO CAP_SETPCAP 1265 1266 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesNetBindService(c *check.C) { 1267 testRequires(c, DaemonIsLinux) 1268 ensureSyscallTest(c) 1269 1270 // test that a root user has default capability CAP_NET_BIND_SERVICE 1271 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "socket-test") 1272 _, _, err := runCommandWithOutput(runCmd) 1273 c.Assert(err, check.IsNil) 1274 // test that non root user does not have default capability CAP_NET_BIND_SERVICE 1275 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "socket-test") 1276 out, _, err := runCommandWithOutput(runCmd) 1277 c.Assert(err, checker.NotNil, check.Commentf(out)) 1278 c.Assert(out, checker.Contains, "Permission denied") 1279 // test that root user can drop default capability CAP_NET_BIND_SERVICE 1280 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "net_bind_service", "syscall-test", "socket-test") 1281 out, _, err = runCommandWithOutput(runCmd) 1282 c.Assert(err, checker.NotNil, check.Commentf(out)) 1283 c.Assert(out, checker.Contains, "Permission denied") 1284 } 1285 1286 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesNetRaw(c *check.C) { 1287 testRequires(c, DaemonIsLinux) 1288 ensureSyscallTest(c) 1289 1290 // test that a root user has default capability CAP_NET_RAW 1291 runCmd := exec.Command(dockerBinary, "run", "syscall-test", "raw-test") 1292 _, _, err := runCommandWithOutput(runCmd) 1293 c.Assert(err, check.IsNil) 1294 // test that non root user does not have default capability CAP_NET_RAW 1295 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "raw-test") 1296 out, _, err := runCommandWithOutput(runCmd) 1297 c.Assert(err, checker.NotNil, check.Commentf(out)) 1298 c.Assert(out, checker.Contains, "Operation not permitted") 1299 // test that root user can drop default capability CAP_NET_RAW 1300 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "net_raw", "syscall-test", "raw-test") 1301 out, _, err = runCommandWithOutput(runCmd) 1302 c.Assert(err, checker.NotNil, check.Commentf(out)) 1303 c.Assert(out, checker.Contains, "Operation not permitted") 1304 } 1305 1306 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesChroot(c *check.C) { 1307 testRequires(c, DaemonIsLinux) 1308 ensureSyscallTest(c) 1309 1310 // test that a root user has default capability CAP_SYS_CHROOT 1311 runCmd := exec.Command(dockerBinary, "run", "busybox", "chroot", "/", "/bin/true") 1312 _, _, err := runCommandWithOutput(runCmd) 1313 c.Assert(err, check.IsNil) 1314 // test that non root user does not have default capability CAP_SYS_CHROOT 1315 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "chroot", "/", "/bin/true") 1316 out, _, err := runCommandWithOutput(runCmd) 1317 c.Assert(err, checker.NotNil, check.Commentf(out)) 1318 c.Assert(out, checker.Contains, "Operation not permitted") 1319 // test that root user can drop default capability CAP_SYS_CHROOT 1320 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "sys_chroot", "busybox", "chroot", "/", "/bin/true") 1321 out, _, err = runCommandWithOutput(runCmd) 1322 c.Assert(err, checker.NotNil, check.Commentf(out)) 1323 c.Assert(out, checker.Contains, "Operation not permitted") 1324 } 1325 1326 func (s *DockerSuite) TestUserNoEffectiveCapabilitiesMknod(c *check.C) { 1327 testRequires(c, DaemonIsLinux, NotUserNamespace) 1328 ensureSyscallTest(c) 1329 1330 // test that a root user has default capability CAP_MKNOD 1331 runCmd := exec.Command(dockerBinary, "run", "busybox", "mknod", "/tmp/node", "b", "1", "2") 1332 _, _, err := runCommandWithOutput(runCmd) 1333 c.Assert(err, check.IsNil) 1334 // test that non root user does not have default capability CAP_MKNOD 1335 runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "mknod", "/tmp/node", "b", "1", "2") 1336 out, _, err := runCommandWithOutput(runCmd) 1337 c.Assert(err, checker.NotNil, check.Commentf(out)) 1338 c.Assert(out, checker.Contains, "Operation not permitted") 1339 // test that root user can drop default capability CAP_MKNOD 1340 runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "mknod", "busybox", "mknod", "/tmp/node", "b", "1", "2") 1341 out, _, err = runCommandWithOutput(runCmd) 1342 c.Assert(err, checker.NotNil, check.Commentf(out)) 1343 c.Assert(out, checker.Contains, "Operation not permitted") 1344 } 1345 1346 // TODO CAP_AUDIT_WRITE 1347 // TODO CAP_SETFCAP 1348 1349 func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) { 1350 testRequires(c, SameHostDaemon, Apparmor) 1351 1352 // running w seccomp unconfined tests the apparmor profile 1353 runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/cgroup") 1354 if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) { 1355 c.Fatalf("expected chmod 777 /proc/1/cgroup to fail, got %s: %v", out, err) 1356 } 1357 1358 runCmd = exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/attr/current") 1359 if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) { 1360 c.Fatalf("expected chmod 777 /proc/1/attr/current to fail, got %s: %v", out, err) 1361 } 1362 } 1363 1364 // make sure the default profile can be successfully parsed (using unshare as it is 1365 // something which we know is blocked in the default profile) 1366 func (s *DockerSuite) TestRunSeccompWithDefaultProfile(c *check.C) { 1367 testRequires(c, SameHostDaemon, seccompEnabled) 1368 1369 out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp=../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami") 1370 c.Assert(err, checker.NotNil, check.Commentf(out)) 1371 c.Assert(strings.TrimSpace(out), checker.Equals, "unshare: unshare failed: Operation not permitted") 1372 } 1373 1374 // TestRunDeviceSymlink checks run with device that follows symlink (#13840 and #22271) 1375 func (s *DockerSuite) TestRunDeviceSymlink(c *check.C) { 1376 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm, SameHostDaemon) 1377 if _, err := os.Stat("/dev/zero"); err != nil { 1378 c.Skip("Host does not have /dev/zero") 1379 } 1380 1381 // Create a temporary directory to create symlink 1382 tmpDir, err := ioutil.TempDir("", "docker_device_follow_symlink_tests") 1383 c.Assert(err, checker.IsNil) 1384 1385 defer os.RemoveAll(tmpDir) 1386 1387 // Create a symbolic link to /dev/zero 1388 symZero := filepath.Join(tmpDir, "zero") 1389 err = os.Symlink("/dev/zero", symZero) 1390 c.Assert(err, checker.IsNil) 1391 1392 // Create a temporary file "temp" inside tmpDir, write some data to "tmpDir/temp", 1393 // then create a symlink "tmpDir/file" to the temporary file "tmpDir/temp". 1394 tmpFile := filepath.Join(tmpDir, "temp") 1395 err = ioutil.WriteFile(tmpFile, []byte("temp"), 0666) 1396 c.Assert(err, checker.IsNil) 1397 symFile := filepath.Join(tmpDir, "file") 1398 err = os.Symlink(tmpFile, symFile) 1399 c.Assert(err, checker.IsNil) 1400 1401 // Create a symbolic link to /dev/zero, this time with a relative path (#22271) 1402 err = os.Symlink("zero", "/dev/symzero") 1403 if err != nil { 1404 c.Fatal("/dev/symzero creation failed") 1405 } 1406 // We need to remove this symbolic link here as it is created in /dev/, not temporary directory as above 1407 defer os.Remove("/dev/symzero") 1408 1409 // md5sum of 'dd if=/dev/zero bs=4K count=8' is bb7df04e1b0a2570657527a7e108ae23 1410 out, _ := dockerCmd(c, "run", "--device", symZero+":/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum") 1411 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "bb7df04e1b0a2570657527a7e108ae23", check.Commentf("expected output bb7df04e1b0a2570657527a7e108ae23")) 1412 1413 // symlink "tmpDir/file" to a file "tmpDir/temp" will result in an error as it is not a device. 1414 out, _, err = dockerCmdWithError("run", "--device", symFile+":/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum") 1415 c.Assert(err, check.NotNil) 1416 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "not a device node", check.Commentf("expected output 'not a device node'")) 1417 1418 // md5sum of 'dd if=/dev/zero bs=4K count=8' is bb7df04e1b0a2570657527a7e108ae23 (this time check with relative path backed, see #22271) 1419 out, _ = dockerCmd(c, "run", "--device", "/dev/symzero:/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum") 1420 c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "bb7df04e1b0a2570657527a7e108ae23", check.Commentf("expected output bb7df04e1b0a2570657527a7e108ae23")) 1421 } 1422 1423 // TestRunPIDsLimit makes sure the pids cgroup is set with --pids-limit 1424 func (s *DockerSuite) TestRunPIDsLimit(c *check.C) { 1425 testRequires(c, pidsLimit) 1426 1427 file := "/sys/fs/cgroup/pids/pids.max" 1428 out, _ := dockerCmd(c, "run", "--name", "skittles", "--pids-limit", "4", "busybox", "cat", file) 1429 c.Assert(strings.TrimSpace(out), checker.Equals, "4") 1430 1431 out = inspectField(c, "skittles", "HostConfig.PidsLimit") 1432 c.Assert(out, checker.Equals, "4", check.Commentf("setting the pids limit failed")) 1433 } 1434 1435 func (s *DockerSuite) TestRunPrivilegedAllowedDevices(c *check.C) { 1436 testRequires(c, DaemonIsLinux, NotUserNamespace) 1437 1438 file := "/sys/fs/cgroup/devices/devices.list" 1439 out, _ := dockerCmd(c, "run", "--privileged", "busybox", "cat", file) 1440 c.Logf("out: %q", out) 1441 c.Assert(strings.TrimSpace(out), checker.Equals, "a *:* rwm") 1442 } 1443 1444 func (s *DockerSuite) TestRunUserDeviceAllowed(c *check.C) { 1445 testRequires(c, DaemonIsLinux) 1446 1447 fi, err := os.Stat("/dev/snd/timer") 1448 if err != nil { 1449 c.Skip("Host does not have /dev/snd/timer") 1450 } 1451 stat, ok := fi.Sys().(*syscall.Stat_t) 1452 if !ok { 1453 c.Skip("Could not stat /dev/snd/timer") 1454 } 1455 1456 file := "/sys/fs/cgroup/devices/devices.list" 1457 out, _ := dockerCmd(c, "run", "--device", "/dev/snd/timer:w", "busybox", "cat", file) 1458 c.Assert(out, checker.Contains, fmt.Sprintf("c %d:%d w", stat.Rdev/256, stat.Rdev%256)) 1459 } 1460 1461 func (s *DockerDaemonSuite) TestRunSeccompJSONNewFormat(c *check.C) { 1462 testRequires(c, SameHostDaemon, seccompEnabled) 1463 1464 err := s.d.StartWithBusybox() 1465 c.Assert(err, check.IsNil) 1466 1467 jsonData := `{ 1468 "defaultAction": "SCMP_ACT_ALLOW", 1469 "syscalls": [ 1470 { 1471 "names": ["chmod", "fchmod", "fchmodat"], 1472 "action": "SCMP_ACT_ERRNO" 1473 } 1474 ] 1475 }` 1476 tmpFile, err := ioutil.TempFile("", "profile.json") 1477 c.Assert(err, check.IsNil) 1478 defer tmpFile.Close() 1479 _, err = tmpFile.Write([]byte(jsonData)) 1480 c.Assert(err, check.IsNil) 1481 1482 out, err := s.d.Cmd("run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "777", ".") 1483 c.Assert(err, check.NotNil) 1484 c.Assert(out, checker.Contains, "Operation not permitted") 1485 } 1486 1487 func (s *DockerDaemonSuite) TestRunSeccompJSONNoNameAndNames(c *check.C) { 1488 testRequires(c, SameHostDaemon, seccompEnabled) 1489 1490 err := s.d.StartWithBusybox() 1491 c.Assert(err, check.IsNil) 1492 1493 jsonData := `{ 1494 "defaultAction": "SCMP_ACT_ALLOW", 1495 "syscalls": [ 1496 { 1497 "name": "chmod", 1498 "names": ["fchmod", "fchmodat"], 1499 "action": "SCMP_ACT_ERRNO" 1500 } 1501 ] 1502 }` 1503 tmpFile, err := ioutil.TempFile("", "profile.json") 1504 c.Assert(err, check.IsNil) 1505 defer tmpFile.Close() 1506 _, err = tmpFile.Write([]byte(jsonData)) 1507 c.Assert(err, check.IsNil) 1508 1509 out, err := s.d.Cmd("run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "777", ".") 1510 c.Assert(err, check.NotNil) 1511 c.Assert(out, checker.Contains, "'name' and 'names' were specified in the seccomp profile, use either 'name' or 'names'") 1512 } 1513 1514 func (s *DockerDaemonSuite) TestRunSeccompJSONNoArchAndArchMap(c *check.C) { 1515 testRequires(c, SameHostDaemon, seccompEnabled) 1516 1517 err := s.d.StartWithBusybox() 1518 c.Assert(err, check.IsNil) 1519 1520 jsonData := `{ 1521 "archMap": [ 1522 { 1523 "architecture": "SCMP_ARCH_X86_64", 1524 "subArchitectures": [ 1525 "SCMP_ARCH_X86", 1526 "SCMP_ARCH_X32" 1527 ] 1528 } 1529 ], 1530 "architectures": [ 1531 "SCMP_ARCH_X32" 1532 ], 1533 "defaultAction": "SCMP_ACT_ALLOW", 1534 "syscalls": [ 1535 { 1536 "names": ["chmod", "fchmod", "fchmodat"], 1537 "action": "SCMP_ACT_ERRNO" 1538 } 1539 ] 1540 }` 1541 tmpFile, err := ioutil.TempFile("", "profile.json") 1542 c.Assert(err, check.IsNil) 1543 defer tmpFile.Close() 1544 _, err = tmpFile.Write([]byte(jsonData)) 1545 c.Assert(err, check.IsNil) 1546 1547 out, err := s.d.Cmd("run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "777", ".") 1548 c.Assert(err, check.NotNil) 1549 c.Assert(out, checker.Contains, "'architectures' and 'archMap' were specified in the seccomp profile, use either 'architectures' or 'archMap'") 1550 } 1551 1552 func (s *DockerDaemonSuite) TestRunWithDaemonDefaultSeccompProfile(c *check.C) { 1553 testRequires(c, SameHostDaemon, seccompEnabled) 1554 1555 err := s.d.StartWithBusybox() 1556 c.Assert(err, check.IsNil) 1557 1558 // 1) verify I can run containers with the Docker default shipped profile which allows chmod 1559 _, err = s.d.Cmd("run", "busybox", "chmod", "777", ".") 1560 c.Assert(err, check.IsNil) 1561 1562 jsonData := `{ 1563 "defaultAction": "SCMP_ACT_ALLOW", 1564 "syscalls": [ 1565 { 1566 "name": "chmod", 1567 "action": "SCMP_ACT_ERRNO" 1568 } 1569 ] 1570 }` 1571 tmpFile, err := ioutil.TempFile("", "profile.json") 1572 c.Assert(err, check.IsNil) 1573 defer tmpFile.Close() 1574 _, err = tmpFile.Write([]byte(jsonData)) 1575 c.Assert(err, check.IsNil) 1576 1577 // 2) restart the daemon and add a custom seccomp profile in which we deny chmod 1578 err = s.d.Restart("--seccomp-profile=" + tmpFile.Name()) 1579 c.Assert(err, check.IsNil) 1580 1581 out, err := s.d.Cmd("run", "busybox", "chmod", "777", ".") 1582 c.Assert(err, check.NotNil) 1583 c.Assert(out, checker.Contains, "Operation not permitted") 1584 } 1585 1586 func (s *DockerSuite) TestRunWithNanoCPUs(c *check.C) { 1587 testRequires(c, cpuCfsQuota, cpuCfsPeriod) 1588 1589 file1 := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us" 1590 file2 := "/sys/fs/cgroup/cpu/cpu.cfs_period_us" 1591 out, _ := dockerCmd(c, "run", "--cpus", "0.5", "--name", "test", "busybox", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2)) 1592 c.Assert(strings.TrimSpace(out), checker.Equals, "50000\n100000") 1593 1594 out = inspectField(c, "test", "HostConfig.NanoCpus") 1595 c.Assert(out, checker.Equals, "5e+08", check.Commentf("setting the Nano CPUs failed")) 1596 out = inspectField(c, "test", "HostConfig.CpuQuota") 1597 c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS quota should be 0")) 1598 out = inspectField(c, "test", "HostConfig.CpuPeriod") 1599 c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS period should be 0")) 1600 1601 out, _, err := dockerCmdWithError("run", "--cpus", "0.5", "--cpu-quota", "50000", "--cpu-period", "100000", "busybox", "sh") 1602 c.Assert(err, check.NotNil) 1603 c.Assert(out, checker.Contains, "Conflicting options: Nano CPUs and CPU Period cannot both be set") 1604 }