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