Source file
src/syscall/exec_linux_test.go
1
2
3
4
5
6
7 package syscall_test
8
9 import (
10 "bytes"
11 "errors"
12 "flag"
13 "fmt"
14 "internal/asan"
15 "internal/platform"
16 "internal/syscall/unix"
17 "internal/testenv"
18 "io"
19 "os"
20 "os/exec"
21 "os/user"
22 "path"
23 "path/filepath"
24 "runtime"
25 "strconv"
26 "strings"
27 "syscall"
28 "testing"
29 "time"
30 "unsafe"
31 )
32
33
34
35 func whoamiNEWUSER(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
36 t.Helper()
37 testenv.MustHaveExecPath(t, "whoami")
38 cmd := testenv.Command(t, "whoami")
39 cmd.SysProcAttr = &syscall.SysProcAttr{
40 Cloneflags: syscall.CLONE_NEWUSER,
41 UidMappings: []syscall.SysProcIDMap{
42 {ContainerID: 0, HostID: uid, Size: 1},
43 },
44 GidMappings: []syscall.SysProcIDMap{
45 {ContainerID: 0, HostID: gid, Size: 1},
46 },
47 GidMappingsEnableSetgroups: setgroups,
48 }
49 return cmd
50 }
51
52 func TestCloneNEWUSERAndRemap(t *testing.T) {
53 for _, setgroups := range []bool{false, true} {
54 setgroups := setgroups
55 t.Run(fmt.Sprintf("setgroups=%v", setgroups), func(t *testing.T) {
56 uid := os.Getuid()
57 gid := os.Getgid()
58
59 cmd := whoamiNEWUSER(t, uid, gid, setgroups)
60 out, err := cmd.CombinedOutput()
61 t.Logf("%v: %v", cmd, err)
62
63 if uid != 0 && setgroups {
64 t.Logf("as non-root, expected permission error due to unprivileged gid_map")
65 if !os.IsPermission(err) {
66 if err == nil {
67 t.Skipf("unexpected success: probably old kernel without security fix?")
68 }
69 if testenv.SyscallIsNotSupported(err) {
70 t.Skipf("skipping: CLONE_NEWUSER appears to be unsupported")
71 }
72 t.Fatalf("got non-permission error")
73 }
74 return
75 }
76
77 if err != nil {
78 if testenv.SyscallIsNotSupported(err) {
79
80 t.Skipf("skipping: CLONE_NEWUSER appears to be unsupported")
81 }
82 t.Fatalf("unexpected command failure; output:\n%s", out)
83 }
84
85 sout := strings.TrimSpace(string(out))
86 want := "root"
87 if sout != want {
88 t.Fatalf("whoami = %q; want %q", out, want)
89 }
90 })
91 }
92 }
93
94 func TestEmptyCredGroupsDisableSetgroups(t *testing.T) {
95 cmd := whoamiNEWUSER(t, os.Getuid(), os.Getgid(), false)
96 cmd.SysProcAttr.Credential = &syscall.Credential{}
97 if err := cmd.Run(); err != nil {
98 if testenv.SyscallIsNotSupported(err) {
99 t.Skipf("skipping: %v: %v", cmd, err)
100 }
101 t.Fatal(err)
102 }
103 }
104
105 func TestUnshare(t *testing.T) {
106 path := "/proc/net/dev"
107 if _, err := os.Stat(path); err != nil {
108 if os.IsNotExist(err) {
109 t.Skip("kernel doesn't support proc filesystem")
110 }
111 if os.IsPermission(err) {
112 t.Skip("unable to test proc filesystem due to permissions")
113 }
114 t.Fatal(err)
115 }
116
117 b, err := os.ReadFile(path)
118 if err != nil {
119 t.Fatal(err)
120 }
121 orig := strings.TrimSpace(string(b))
122 if strings.Contains(orig, "lo:") && strings.Count(orig, ":") == 1 {
123
124
125
126 t.Skip("not enough network interfaces to test unshare with")
127 }
128
129 cmd := testenv.Command(t, "cat", path)
130 cmd.SysProcAttr = &syscall.SysProcAttr{
131 Unshareflags: syscall.CLONE_NEWNET,
132 }
133 out, err := cmd.CombinedOutput()
134 if err != nil {
135 if testenv.SyscallIsNotSupported(err) {
136
137 t.Skipf("skipping due to permission error: %v", err)
138 }
139 t.Fatalf("Cmd failed with err %v, output: %s", err, out)
140 }
141
142
143 sout := strings.TrimSpace(string(out))
144 if !strings.Contains(sout, "lo:") {
145 t.Fatalf("Expected lo network interface to exist, got %s", sout)
146 }
147
148 origLines := strings.Split(orig, "\n")
149 lines := strings.Split(sout, "\n")
150 if len(lines) >= len(origLines) {
151 t.Logf("%s before unshare:\n%s", path, orig)
152 t.Logf("%s after unshare:\n%s", path, sout)
153 t.Fatalf("Got %d lines of output, want < %d", len(lines), len(origLines))
154 }
155 }
156
157 func TestGroupCleanup(t *testing.T) {
158 testenv.MustHaveExecPath(t, "id")
159 cmd := testenv.Command(t, "id")
160 cmd.SysProcAttr = &syscall.SysProcAttr{
161 Credential: &syscall.Credential{
162 Uid: 0,
163 Gid: 0,
164 },
165 }
166 out, err := cmd.CombinedOutput()
167 if err != nil {
168 if testenv.SyscallIsNotSupported(err) {
169 t.Skipf("skipping: %v: %v", cmd, err)
170 }
171 t.Fatalf("Cmd failed with err %v, output: %s", err, out)
172 }
173 strOut := strings.TrimSpace(string(out))
174 t.Logf("id: %s", strOut)
175
176 expected := "uid=0(root) gid=0(root)"
177
178
179
180 if !strings.HasPrefix(strOut, expected) {
181 t.Errorf("expected prefix: %q", expected)
182 }
183 }
184
185 func TestGroupCleanupUserNamespace(t *testing.T) {
186 testenv.MustHaveExecPath(t, "id")
187 cmd := testenv.Command(t, "id")
188 uid, gid := os.Getuid(), os.Getgid()
189 cmd.SysProcAttr = &syscall.SysProcAttr{
190 Cloneflags: syscall.CLONE_NEWUSER,
191 Credential: &syscall.Credential{
192 Uid: uint32(uid),
193 Gid: uint32(gid),
194 },
195 UidMappings: []syscall.SysProcIDMap{
196 {ContainerID: 0, HostID: uid, Size: 1},
197 },
198 GidMappings: []syscall.SysProcIDMap{
199 {ContainerID: 0, HostID: gid, Size: 1},
200 },
201 }
202 out, err := cmd.CombinedOutput()
203 if err != nil {
204 if testenv.SyscallIsNotSupported(err) {
205 t.Skipf("skipping: %v: %v", cmd, err)
206 }
207 t.Fatalf("Cmd failed with err %v, output: %s", err, out)
208 }
209 strOut := strings.TrimSpace(string(out))
210 t.Logf("id: %s", strOut)
211
212
213
214 expected := "uid=0(root) gid=0(root) groups=0(root)"
215 if !strings.HasPrefix(strOut, expected) {
216 t.Errorf("expected prefix: %q", expected)
217 }
218 }
219
220
221
222 func TestUnshareMountNameSpace(t *testing.T) {
223 const mountNotSupported = "mount is not supported: "
224 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
225 dir := flag.Args()[0]
226 err := syscall.Mount("none", dir, "proc", 0, "")
227 if testenv.SyscallIsNotSupported(err) {
228 fmt.Print(mountNotSupported, err)
229 } else if err != nil {
230 fmt.Fprintf(os.Stderr, "unshare: mount %s: %v\n", dir, err)
231 os.Exit(2)
232 }
233 os.Exit(0)
234 }
235
236 exe := testenv.Executable(t)
237 d := t.TempDir()
238 t.Cleanup(func() {
239
240
241 if _, err := os.Stat(d); err == nil {
242 syscall.Unmount(d, syscall.MNT_FORCE)
243 }
244 })
245 cmd := testenv.Command(t, exe, "-test.run=^TestUnshareMountNameSpace$", d)
246 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
247 cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
248
249 out, err := cmd.CombinedOutput()
250 if err != nil {
251 if testenv.SyscallIsNotSupported(err) {
252 t.Skipf("skipping: could not start process with CLONE_NEWNS: %v", err)
253 }
254 t.Fatalf("unshare failed: %v\n%s", err, out)
255 } else if len(out) != 0 {
256 if bytes.HasPrefix(out, []byte(mountNotSupported)) {
257 t.Skipf("skipping: helper process reported %s", out)
258 }
259 t.Fatalf("unexpected output from helper process: %s", out)
260 }
261
262
263
264
265 if err := os.Remove(d); err != nil {
266 t.Errorf("rmdir failed on %v: %v", d, err)
267 }
268 }
269
270
271 func TestUnshareMountNameSpaceChroot(t *testing.T) {
272 const mountNotSupported = "mount is not supported: "
273 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
274 dir := flag.Args()[0]
275 err := syscall.Mount("none", dir, "proc", 0, "")
276 if testenv.SyscallIsNotSupported(err) {
277 fmt.Print(mountNotSupported, err)
278 } else if err != nil {
279 fmt.Fprintf(os.Stderr, "unshare: mount %s: %v\n", dir, err)
280 os.Exit(2)
281 }
282 os.Exit(0)
283 }
284
285 d := t.TempDir()
286
287
288
289 testenv.MustHaveGoBuild(t)
290 if platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH, false) {
291 t.Skipf("skipping: can't build static binary because %s/%s requires external linking", runtime.GOOS, runtime.GOARCH)
292 }
293 x := filepath.Join(d, "syscall.test")
294 t.Cleanup(func() {
295
296
297 if _, err := os.Stat(d); err == nil {
298 syscall.Unmount(d, syscall.MNT_FORCE)
299 }
300 })
301
302 cmd := testenv.Command(t, testenv.GoToolPath(t), "test", "-c", "-o", x, "syscall")
303 cmd.Env = append(cmd.Environ(), "CGO_ENABLED=0")
304 if o, err := cmd.CombinedOutput(); err != nil {
305 t.Fatalf("%v: %v\n%s", cmd, err, o)
306 }
307
308 cmd = testenv.Command(t, "/syscall.test", "-test.run=^TestUnshareMountNameSpaceChroot$", "/")
309 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
310 cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: d, Unshareflags: syscall.CLONE_NEWNS}
311
312 out, err := cmd.CombinedOutput()
313 if err != nil {
314 if testenv.SyscallIsNotSupported(err) {
315 t.Skipf("skipping: could not start process with CLONE_NEWNS and Chroot %q: %v", d, err)
316 }
317 t.Fatalf("unshare failed: %v\n%s", err, out)
318 } else if len(out) != 0 {
319 if bytes.HasPrefix(out, []byte(mountNotSupported)) {
320 t.Skipf("skipping: helper process reported %s", out)
321 }
322 t.Fatalf("unexpected output from helper process: %s", out)
323 }
324
325
326
327
328 if err := os.Remove(x); err != nil {
329 t.Errorf("rm failed on %v: %v", x, err)
330 }
331 if err := os.Remove(d); err != nil {
332 t.Errorf("rmdir failed on %v: %v", d, err)
333 }
334 }
335
336
337 func TestUnshareUidGidMapping(t *testing.T) {
338 if asan.Enabled {
339 t.Skip("test fails with ASAN beause the ASAN leak checker fails finding memory regions")
340 }
341
342 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
343 defer os.Exit(0)
344 if err := syscall.Chroot(os.TempDir()); err != nil {
345 fmt.Fprintln(os.Stderr, err)
346 os.Exit(2)
347 }
348 }
349
350 if os.Getuid() == 0 {
351 t.Skip("test exercises unprivileged user namespace, fails with privileges")
352 }
353
354 exe := testenv.Executable(t)
355 cmd := testenv.Command(t, exe, "-test.run=^TestUnshareUidGidMapping$")
356 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
357 cmd.SysProcAttr = &syscall.SysProcAttr{
358 Unshareflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER,
359 GidMappingsEnableSetgroups: false,
360 UidMappings: []syscall.SysProcIDMap{
361 {
362 ContainerID: 0,
363 HostID: syscall.Getuid(),
364 Size: 1,
365 },
366 },
367 GidMappings: []syscall.SysProcIDMap{
368 {
369 ContainerID: 0,
370 HostID: syscall.Getgid(),
371 Size: 1,
372 },
373 },
374 }
375 out, err := cmd.CombinedOutput()
376 if err != nil {
377 if testenv.SyscallIsNotSupported(err) {
378 t.Skipf("skipping: could not start process with CLONE_NEWNS and CLONE_NEWUSER: %v", err)
379 }
380 t.Fatalf("Cmd failed with err %v, output: %s", err, out)
381 }
382 }
383
384 func prepareCgroupFD(t *testing.T) (int, string) {
385 t.Helper()
386
387 const O_PATH = 0x200000
388
389
390 const prefix = "/sys/fs/cgroup"
391 selfCg, err := os.ReadFile("/proc/self/cgroup")
392 if err != nil {
393 if os.IsNotExist(err) || os.IsPermission(err) {
394 t.Skip(err)
395 }
396 t.Fatal(err)
397 }
398
399
400
401
402 if bytes.Count(selfCg, []byte("\n")) > 1 {
403 t.Skip("cgroup v2 not available")
404 }
405 cg := bytes.TrimPrefix(selfCg, []byte("0::"))
406 if len(cg) == len(selfCg) {
407 t.Skipf("cgroup v2 not available (/proc/self/cgroup contents: %q)", selfCg)
408 }
409
410
411 subCgroup, err := os.MkdirTemp(prefix+string(bytes.TrimSpace(cg)), "subcg-")
412 if err != nil {
413
414
415 if os.IsNotExist(err) || testenv.SyscallIsNotSupported(err) {
416 t.Skipf("skipping: %v", err)
417 }
418 t.Fatal(err)
419 }
420 t.Cleanup(func() { syscall.Rmdir(subCgroup) })
421
422 cgroupFD, err := syscall.Open(subCgroup, O_PATH, 0)
423 if err != nil {
424 t.Fatal(&os.PathError{Op: "open", Path: subCgroup, Err: err})
425 }
426 t.Cleanup(func() { syscall.Close(cgroupFD) })
427
428 return cgroupFD, "/" + path.Base(subCgroup)
429 }
430
431 func TestUseCgroupFD(t *testing.T) {
432 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
433
434 selfCg, err := os.ReadFile("/proc/self/cgroup")
435 if err != nil {
436 fmt.Fprintln(os.Stderr, err)
437 os.Exit(2)
438 }
439 fmt.Print(string(selfCg))
440 os.Exit(0)
441 }
442
443 exe := testenv.Executable(t)
444 fd, suffix := prepareCgroupFD(t)
445
446 cmd := testenv.Command(t, exe, "-test.run=^TestUseCgroupFD$")
447 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
448 cmd.SysProcAttr = &syscall.SysProcAttr{
449 UseCgroupFD: true,
450 CgroupFD: fd,
451 }
452 out, err := cmd.CombinedOutput()
453 if err != nil {
454 if testenv.SyscallIsNotSupported(err) && !errors.Is(err, syscall.EINVAL) {
455
456
457
458
459 t.Skipf("clone3 with CLONE_INTO_CGROUP not available: %v", err)
460 }
461 t.Fatalf("Cmd failed with err %v, output: %s", err, out)
462 }
463
464 if !bytes.HasSuffix(bytes.TrimSpace(out), []byte(suffix)) {
465 t.Fatalf("got: %q, want: a line that ends with %q", out, suffix)
466 }
467 }
468
469 func TestCloneTimeNamespace(t *testing.T) {
470 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
471 timens, err := os.Readlink("/proc/self/ns/time")
472 if err != nil {
473 fmt.Fprintln(os.Stderr, err)
474 os.Exit(2)
475 }
476 fmt.Print(string(timens))
477 os.Exit(0)
478 }
479
480 exe := testenv.Executable(t)
481 cmd := testenv.Command(t, exe, "-test.run=^TestCloneTimeNamespace$")
482 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
483 cmd.SysProcAttr = &syscall.SysProcAttr{
484 Cloneflags: syscall.CLONE_NEWTIME,
485 }
486 out, err := cmd.CombinedOutput()
487 if err != nil {
488 if testenv.SyscallIsNotSupported(err) {
489
490 t.Skipf("skipping, CLONE_NEWTIME not supported: %v", err)
491 }
492 t.Fatalf("Cmd failed with err %v, output: %s", err, out)
493 }
494
495
496
497 timens, err := os.Readlink("/proc/self/ns/time")
498 if err != nil {
499 t.Fatal(err)
500 }
501
502 parentTimeNS := timens
503 childTimeNS := string(out)
504 if childTimeNS == parentTimeNS {
505 t.Fatalf("expected child time namespace to be different from parent time namespace: %s", parentTimeNS)
506 }
507 }
508
509 func testPidFD(t *testing.T, userns bool) error {
510 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
511
512 time.Sleep(time.Hour)
513 }
514
515 exe := testenv.Executable(t)
516 var pidfd int
517 cmd := testenv.Command(t, exe, "-test.run=^TestPidFD$")
518 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
519 cmd.SysProcAttr = &syscall.SysProcAttr{
520 PidFD: &pidfd,
521 }
522 if userns {
523 cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER
524 }
525 if err := cmd.Start(); err != nil {
526 return err
527 }
528 defer func() {
529 cmd.Process.Kill()
530 cmd.Wait()
531 }()
532 t.Log("got pidfd:", pidfd)
533
534 if pidfd == -1 {
535 t.Skip("pidfd not supported")
536 }
537 defer syscall.Close(pidfd)
538
539
540 sig := syscall.SIGINT
541 if err := unix.PidFDSendSignal(uintptr(pidfd), sig); err != nil {
542 if err != syscall.EINVAL && testenv.SyscallIsNotSupported(err) {
543 t.Skip("pidfd_send_signal syscall not supported:", err)
544 }
545 t.Fatal("pidfd_send_signal syscall failed:", err)
546 }
547
548 err := cmd.Wait()
549 if cmd.ProcessState == nil || cmd.ProcessState.Sys().(syscall.WaitStatus).Signal() != sig {
550 t.Fatal("unexpected child error:", err)
551 }
552 return nil
553 }
554
555 func TestPidFD(t *testing.T) {
556 if err := testPidFD(t, false); err != nil {
557 t.Fatal("can't start a process:", err)
558 }
559 }
560
561 func TestPidFDWithUserNS(t *testing.T) {
562 if err := testPidFD(t, true); err != nil {
563 if testenv.SyscallIsNotSupported(err) {
564 t.Skip("userns not supported:", err)
565 }
566 t.Fatal("can't start a process:", err)
567 }
568 }
569
570 func TestPidFDClone3(t *testing.T) {
571 *syscall.ForceClone3 = true
572 defer func() { *syscall.ForceClone3 = false }()
573
574 if err := testPidFD(t, false); err != nil {
575 if testenv.SyscallIsNotSupported(err) {
576 t.Skip("clone3 not supported:", err)
577 }
578 t.Fatal("can't start a process:", err)
579 }
580 }
581
582 type capHeader struct {
583 version uint32
584 pid int32
585 }
586
587 type capData struct {
588 effective uint32
589 permitted uint32
590 inheritable uint32
591 }
592
593 const CAP_SYS_TIME = 25
594 const CAP_SYSLOG = 34
595
596 type caps struct {
597 hdr capHeader
598 data [2]capData
599 }
600
601 func getCaps() (caps, error) {
602 var c caps
603
604
605 if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(nil)), 0); errno != 0 {
606 return c, fmt.Errorf("SYS_CAPGET: %v", errno)
607 }
608
609
610 if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(&c.data[0])), 0); errno != 0 {
611 return c, fmt.Errorf("SYS_CAPGET: %v", errno)
612 }
613
614 return c, nil
615 }
616
617 func TestAmbientCaps(t *testing.T) {
618 testAmbientCaps(t, false)
619 }
620
621 func TestAmbientCapsUserns(t *testing.T) {
622 b, err := os.ReadFile("/proc/sys/kernel/apparmor_restrict_unprivileged_userns")
623 if err == nil && strings.TrimSpace(string(b)) == "1" {
624 t.Skip("AppArmor restriction for unprivileged user namespaces is enabled")
625 }
626 testAmbientCaps(t, true)
627 }
628
629 func testAmbientCaps(t *testing.T, userns bool) {
630 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
631 caps, err := getCaps()
632 if err != nil {
633 fmt.Fprintln(os.Stderr, err)
634 os.Exit(2)
635 }
636 if caps.data[0].effective&(1<<uint(CAP_SYS_TIME)) == 0 {
637 fmt.Fprintln(os.Stderr, "CAP_SYS_TIME unexpectedly not in the effective capability mask")
638 os.Exit(2)
639 }
640 if caps.data[1].effective&(1<<uint(CAP_SYSLOG&31)) == 0 {
641 fmt.Fprintln(os.Stderr, "CAP_SYSLOG unexpectedly not in the effective capability mask")
642 os.Exit(2)
643 }
644 os.Exit(0)
645 }
646
647
648 if runtime.GOOS == "android" {
649 t.Skip("skipping test on android; see Issue 27327")
650 }
651
652 u, err := user.Lookup("nobody")
653 if err != nil {
654 t.Skip("skipping: the nobody user does not exist; see Issue 71644")
655 }
656 uid, err := strconv.ParseInt(u.Uid, 0, 32)
657 if err != nil {
658 t.Fatal(err)
659 }
660 gid, err := strconv.ParseInt(u.Gid, 0, 32)
661 if err != nil {
662 t.Fatal(err)
663 }
664
665
666 f, err := os.CreateTemp("", "gotest")
667 if err != nil {
668 t.Fatal(err)
669 }
670 t.Cleanup(func() {
671 f.Close()
672 os.Remove(f.Name())
673 })
674
675 exe := testenv.Executable(t)
676 e, err := os.Open(exe)
677 if err != nil {
678 t.Fatal(err)
679 }
680 defer e.Close()
681 if _, err := io.Copy(f, e); err != nil {
682 t.Fatal(err)
683 }
684 if err := f.Chmod(0755); err != nil {
685 t.Fatal(err)
686 }
687 if err := f.Close(); err != nil {
688 t.Fatal(err)
689 }
690
691 cmd := testenv.Command(t, f.Name(), "-test.run=^"+t.Name()+"$")
692 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
693 cmd.Stdout = os.Stdout
694 cmd.Stderr = os.Stderr
695 cmd.SysProcAttr = &syscall.SysProcAttr{
696 Credential: &syscall.Credential{
697 Uid: uint32(uid),
698 Gid: uint32(gid),
699 },
700 AmbientCaps: []uintptr{CAP_SYS_TIME, CAP_SYSLOG},
701 }
702 if userns {
703 cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER
704 const nobody = 65534
705 uid := os.Getuid()
706 gid := os.Getgid()
707 cmd.SysProcAttr.UidMappings = []syscall.SysProcIDMap{{
708 ContainerID: int(nobody),
709 HostID: uid,
710 Size: int(1),
711 }}
712 cmd.SysProcAttr.GidMappings = []syscall.SysProcIDMap{{
713 ContainerID: int(nobody),
714 HostID: gid,
715 Size: int(1),
716 }}
717
718
719 cmd.SysProcAttr.Credential = &syscall.Credential{
720 Uid: nobody,
721 Gid: nobody,
722 }
723 }
724 if err := cmd.Run(); err != nil {
725 if testenv.SyscallIsNotSupported(err) {
726 t.Skipf("skipping: %v: %v", cmd, err)
727 }
728 t.Fatal(err.Error())
729 }
730 }
731
View as plain text