github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/integration/execin_test.go (about) 1 package integration 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "os" 8 "strconv" 9 "strings" 10 "syscall" 11 "testing" 12 "time" 13 14 "github.com/opencontainers/runc/libcontainer" 15 "github.com/opencontainers/runc/libcontainer/configs" 16 ) 17 18 func TestExecIn(t *testing.T) { 19 if testing.Short() { 20 return 21 } 22 rootfs, err := newRootfs() 23 ok(t, err) 24 defer remove(rootfs) 25 config := newTemplateConfig(rootfs) 26 container, err := newContainer(config) 27 ok(t, err) 28 defer container.Destroy() 29 30 // Execute a first process in the container 31 stdinR, stdinW, err := os.Pipe() 32 ok(t, err) 33 process := &libcontainer.Process{ 34 Cwd: "/", 35 Args: []string{"cat"}, 36 Env: standardEnvironment, 37 Stdin: stdinR, 38 } 39 err = container.Run(process) 40 stdinR.Close() 41 defer stdinW.Close() 42 ok(t, err) 43 44 buffers := newStdBuffers() 45 ps := &libcontainer.Process{ 46 Cwd: "/", 47 Args: []string{"ps"}, 48 Env: standardEnvironment, 49 Stdin: buffers.Stdin, 50 Stdout: buffers.Stdout, 51 Stderr: buffers.Stderr, 52 } 53 54 err = container.Run(ps) 55 ok(t, err) 56 waitProcess(ps, t) 57 stdinW.Close() 58 waitProcess(process, t) 59 60 out := buffers.Stdout.String() 61 if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") { 62 t.Fatalf("unexpected running process, output %q", out) 63 } 64 if strings.Contains(out, "\r") { 65 t.Fatalf("unexpected carriage-return in output") 66 } 67 } 68 69 func TestExecInUsernsRlimit(t *testing.T) { 70 if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { 71 t.Skip("userns is unsupported") 72 } 73 74 testExecInRlimit(t, true) 75 } 76 77 func TestExecInRlimit(t *testing.T) { 78 testExecInRlimit(t, false) 79 } 80 81 func testExecInRlimit(t *testing.T, userns bool) { 82 if testing.Short() { 83 return 84 } 85 86 rootfs, err := newRootfs() 87 ok(t, err) 88 defer remove(rootfs) 89 90 config := newTemplateConfig(rootfs) 91 if userns { 92 config.UidMappings = []configs.IDMap{{0, 0, 1000}} 93 config.GidMappings = []configs.IDMap{{0, 0, 1000}} 94 config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER}) 95 } 96 97 container, err := newContainer(config) 98 ok(t, err) 99 defer container.Destroy() 100 101 stdinR, stdinW, err := os.Pipe() 102 ok(t, err) 103 process := &libcontainer.Process{ 104 Cwd: "/", 105 Args: []string{"cat"}, 106 Env: standardEnvironment, 107 Stdin: stdinR, 108 } 109 err = container.Run(process) 110 stdinR.Close() 111 defer stdinW.Close() 112 ok(t, err) 113 114 buffers := newStdBuffers() 115 ps := &libcontainer.Process{ 116 Cwd: "/", 117 Args: []string{"/bin/sh", "-c", "ulimit -n"}, 118 Env: standardEnvironment, 119 Stdin: buffers.Stdin, 120 Stdout: buffers.Stdout, 121 Stderr: buffers.Stderr, 122 Rlimits: []configs.Rlimit{ 123 // increase process rlimit higher than container rlimit to test per-process limit 124 {Type: syscall.RLIMIT_NOFILE, Hard: 1026, Soft: 1026}, 125 }, 126 } 127 err = container.Run(ps) 128 ok(t, err) 129 waitProcess(ps, t) 130 131 stdinW.Close() 132 waitProcess(process, t) 133 134 out := buffers.Stdout.String() 135 if limit := strings.TrimSpace(out); limit != "1026" { 136 t.Fatalf("expected rlimit to be 1026, got %s", limit) 137 } 138 } 139 140 func TestExecInAdditionalGroups(t *testing.T) { 141 if testing.Short() { 142 return 143 } 144 145 rootfs, err := newRootfs() 146 ok(t, err) 147 defer remove(rootfs) 148 149 config := newTemplateConfig(rootfs) 150 container, err := newContainer(config) 151 ok(t, err) 152 defer container.Destroy() 153 154 // Execute a first process in the container 155 stdinR, stdinW, err := os.Pipe() 156 ok(t, err) 157 process := &libcontainer.Process{ 158 Cwd: "/", 159 Args: []string{"cat"}, 160 Env: standardEnvironment, 161 Stdin: stdinR, 162 } 163 err = container.Run(process) 164 stdinR.Close() 165 defer stdinW.Close() 166 ok(t, err) 167 168 var stdout bytes.Buffer 169 pconfig := libcontainer.Process{ 170 Cwd: "/", 171 Args: []string{"sh", "-c", "id", "-Gn"}, 172 Env: standardEnvironment, 173 Stdin: nil, 174 Stdout: &stdout, 175 AdditionalGroups: []string{"plugdev", "audio"}, 176 } 177 err = container.Run(&pconfig) 178 ok(t, err) 179 180 // Wait for process 181 waitProcess(&pconfig, t) 182 183 stdinW.Close() 184 waitProcess(process, t) 185 186 outputGroups := string(stdout.Bytes()) 187 188 // Check that the groups output has the groups that we specified 189 if !strings.Contains(outputGroups, "audio") { 190 t.Fatalf("Listed groups do not contain the audio group as expected: %v", outputGroups) 191 } 192 193 if !strings.Contains(outputGroups, "plugdev") { 194 t.Fatalf("Listed groups do not contain the plugdev group as expected: %v", outputGroups) 195 } 196 } 197 198 func TestExecInError(t *testing.T) { 199 if testing.Short() { 200 return 201 } 202 rootfs, err := newRootfs() 203 ok(t, err) 204 defer remove(rootfs) 205 config := newTemplateConfig(rootfs) 206 container, err := newContainer(config) 207 ok(t, err) 208 defer container.Destroy() 209 210 // Execute a first process in the container 211 stdinR, stdinW, err := os.Pipe() 212 ok(t, err) 213 process := &libcontainer.Process{ 214 Cwd: "/", 215 Args: []string{"cat"}, 216 Env: standardEnvironment, 217 Stdin: stdinR, 218 } 219 err = container.Run(process) 220 stdinR.Close() 221 defer func() { 222 stdinW.Close() 223 if _, err := process.Wait(); err != nil { 224 t.Log(err) 225 } 226 }() 227 ok(t, err) 228 229 for i := 0; i < 42; i++ { 230 var out bytes.Buffer 231 unexistent := &libcontainer.Process{ 232 Cwd: "/", 233 Args: []string{"unexistent"}, 234 Env: standardEnvironment, 235 Stdout: &out, 236 } 237 err = container.Run(unexistent) 238 if err == nil { 239 t.Fatal("Should be an error") 240 } 241 if !strings.Contains(err.Error(), "executable file not found") { 242 t.Fatalf("Should be error about not found executable, got %s", err) 243 } 244 if !bytes.Contains(out.Bytes(), []byte("executable file not found")) { 245 t.Fatalf("executable file not found error not delivered to stdio:\n%s", out.String()) 246 } 247 } 248 } 249 250 func TestExecInTTY(t *testing.T) { 251 if testing.Short() { 252 return 253 } 254 rootfs, err := newRootfs() 255 ok(t, err) 256 defer remove(rootfs) 257 config := newTemplateConfig(rootfs) 258 container, err := newContainer(config) 259 ok(t, err) 260 defer container.Destroy() 261 262 // Execute a first process in the container 263 stdinR, stdinW, err := os.Pipe() 264 ok(t, err) 265 process := &libcontainer.Process{ 266 Cwd: "/", 267 Args: []string{"cat"}, 268 Env: standardEnvironment, 269 Stdin: stdinR, 270 } 271 err = container.Run(process) 272 stdinR.Close() 273 defer stdinW.Close() 274 ok(t, err) 275 276 var stdout bytes.Buffer 277 ps := &libcontainer.Process{ 278 Cwd: "/", 279 Args: []string{"ps"}, 280 Env: standardEnvironment, 281 } 282 console, err := ps.NewConsole(0, 0) 283 copy := make(chan struct{}) 284 go func() { 285 io.Copy(&stdout, console) 286 close(copy) 287 }() 288 ok(t, err) 289 err = container.Run(ps) 290 ok(t, err) 291 select { 292 case <-time.After(5 * time.Second): 293 t.Fatal("Waiting for copy timed out") 294 case <-copy: 295 } 296 waitProcess(ps, t) 297 298 stdinW.Close() 299 waitProcess(process, t) 300 301 out := stdout.String() 302 if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") { 303 t.Fatalf("unexpected running process, output %q", out) 304 } 305 if strings.Contains(out, "\r") { 306 t.Fatalf("unexpected carriage-return in output") 307 } 308 } 309 310 func TestExecInEnvironment(t *testing.T) { 311 if testing.Short() { 312 return 313 } 314 rootfs, err := newRootfs() 315 ok(t, err) 316 defer remove(rootfs) 317 config := newTemplateConfig(rootfs) 318 container, err := newContainer(config) 319 ok(t, err) 320 defer container.Destroy() 321 322 // Execute a first process in the container 323 stdinR, stdinW, err := os.Pipe() 324 ok(t, err) 325 process := &libcontainer.Process{ 326 Cwd: "/", 327 Args: []string{"cat"}, 328 Env: standardEnvironment, 329 Stdin: stdinR, 330 } 331 err = container.Run(process) 332 stdinR.Close() 333 defer stdinW.Close() 334 ok(t, err) 335 336 buffers := newStdBuffers() 337 process2 := &libcontainer.Process{ 338 Cwd: "/", 339 Args: []string{"env"}, 340 Env: []string{ 341 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 342 "DEBUG=true", 343 "DEBUG=false", 344 "ENV=test", 345 }, 346 Stdin: buffers.Stdin, 347 Stdout: buffers.Stdout, 348 Stderr: buffers.Stderr, 349 } 350 err = container.Run(process2) 351 ok(t, err) 352 waitProcess(process2, t) 353 354 stdinW.Close() 355 waitProcess(process, t) 356 357 out := buffers.Stdout.String() 358 // check execin's process environment 359 if !strings.Contains(out, "DEBUG=false") || 360 !strings.Contains(out, "ENV=test") || 361 !strings.Contains(out, "HOME=/root") || 362 !strings.Contains(out, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin") || 363 strings.Contains(out, "DEBUG=true") { 364 t.Fatalf("unexpected running process, output %q", out) 365 } 366 } 367 368 func TestExecinPassExtraFiles(t *testing.T) { 369 if testing.Short() { 370 return 371 } 372 rootfs, err := newRootfs() 373 if err != nil { 374 t.Fatal(err) 375 } 376 defer remove(rootfs) 377 config := newTemplateConfig(rootfs) 378 container, err := newContainer(config) 379 if err != nil { 380 t.Fatal(err) 381 } 382 defer container.Destroy() 383 384 // Execute a first process in the container 385 stdinR, stdinW, err := os.Pipe() 386 if err != nil { 387 t.Fatal(err) 388 } 389 process := &libcontainer.Process{ 390 Cwd: "/", 391 Args: []string{"cat"}, 392 Env: standardEnvironment, 393 Stdin: stdinR, 394 } 395 err = container.Run(process) 396 stdinR.Close() 397 defer stdinW.Close() 398 if err != nil { 399 t.Fatal(err) 400 } 401 402 var stdout bytes.Buffer 403 pipeout1, pipein1, err := os.Pipe() 404 pipeout2, pipein2, err := os.Pipe() 405 inprocess := &libcontainer.Process{ 406 Cwd: "/", 407 Args: []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"}, 408 Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}, 409 ExtraFiles: []*os.File{pipein1, pipein2}, 410 Stdin: nil, 411 Stdout: &stdout, 412 } 413 err = container.Run(inprocess) 414 if err != nil { 415 t.Fatal(err) 416 } 417 418 waitProcess(inprocess, t) 419 stdinW.Close() 420 waitProcess(process, t) 421 422 out := string(stdout.Bytes()) 423 // fd 5 is the directory handle for /proc/$$/fd 424 if out != "0 1 2 3 4 5" { 425 t.Fatalf("expected to have the file descriptors '0 1 2 3 4 5' passed to exec, got '%s'", out) 426 } 427 var buf = []byte{0} 428 _, err = pipeout1.Read(buf) 429 if err != nil { 430 t.Fatal(err) 431 } 432 out1 := string(buf) 433 if out1 != "1" { 434 t.Fatalf("expected first pipe to receive '1', got '%s'", out1) 435 } 436 437 _, err = pipeout2.Read(buf) 438 if err != nil { 439 t.Fatal(err) 440 } 441 out2 := string(buf) 442 if out2 != "2" { 443 t.Fatalf("expected second pipe to receive '2', got '%s'", out2) 444 } 445 } 446 447 func TestExecInOomScoreAdj(t *testing.T) { 448 if testing.Short() { 449 return 450 } 451 rootfs, err := newRootfs() 452 ok(t, err) 453 defer remove(rootfs) 454 config := newTemplateConfig(rootfs) 455 config.OomScoreAdj = 200 456 container, err := newContainer(config) 457 ok(t, err) 458 defer container.Destroy() 459 460 stdinR, stdinW, err := os.Pipe() 461 ok(t, err) 462 process := &libcontainer.Process{ 463 Cwd: "/", 464 Args: []string{"cat"}, 465 Env: standardEnvironment, 466 Stdin: stdinR, 467 } 468 err = container.Run(process) 469 stdinR.Close() 470 defer stdinW.Close() 471 ok(t, err) 472 473 buffers := newStdBuffers() 474 ps := &libcontainer.Process{ 475 Cwd: "/", 476 Args: []string{"/bin/sh", "-c", "cat /proc/self/oom_score_adj"}, 477 Env: standardEnvironment, 478 Stdin: buffers.Stdin, 479 Stdout: buffers.Stdout, 480 Stderr: buffers.Stderr, 481 } 482 err = container.Run(ps) 483 ok(t, err) 484 waitProcess(ps, t) 485 486 stdinW.Close() 487 waitProcess(process, t) 488 489 out := buffers.Stdout.String() 490 if oomScoreAdj := strings.TrimSpace(out); oomScoreAdj != strconv.Itoa(config.OomScoreAdj) { 491 t.Fatalf("expected oomScoreAdj to be %d, got %s", config.OomScoreAdj, oomScoreAdj) 492 } 493 } 494 495 func TestExecInUserns(t *testing.T) { 496 if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { 497 t.Skip("userns is unsupported") 498 } 499 if testing.Short() { 500 return 501 } 502 rootfs, err := newRootfs() 503 ok(t, err) 504 defer remove(rootfs) 505 config := newTemplateConfig(rootfs) 506 config.UidMappings = []configs.IDMap{{0, 0, 1000}} 507 config.GidMappings = []configs.IDMap{{0, 0, 1000}} 508 config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER}) 509 container, err := newContainer(config) 510 ok(t, err) 511 defer container.Destroy() 512 513 // Execute a first process in the container 514 stdinR, stdinW, err := os.Pipe() 515 ok(t, err) 516 517 process := &libcontainer.Process{ 518 Cwd: "/", 519 Args: []string{"cat"}, 520 Env: standardEnvironment, 521 Stdin: stdinR, 522 } 523 err = container.Run(process) 524 stdinR.Close() 525 defer stdinW.Close() 526 ok(t, err) 527 528 initPID, err := process.Pid() 529 ok(t, err) 530 initUserns, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/user", initPID)) 531 ok(t, err) 532 533 buffers := newStdBuffers() 534 process2 := &libcontainer.Process{ 535 Cwd: "/", 536 Args: []string{"readlink", "/proc/self/ns/user"}, 537 Env: []string{ 538 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 539 }, 540 Stdout: buffers.Stdout, 541 Stderr: os.Stderr, 542 } 543 err = container.Run(process2) 544 ok(t, err) 545 waitProcess(process2, t) 546 stdinW.Close() 547 waitProcess(process, t) 548 549 if out := strings.TrimSpace(buffers.Stdout.String()); out != initUserns { 550 t.Errorf("execin userns(%s), wanted %s", out, initUserns) 551 } 552 }