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/platform"
15 "internal/syscall/unix"
16 "internal/testenv"
17 "io"
18 "os"
19 "os/exec"
20 "os/user"
21 "path"
22 "path/filepath"
23 "runtime"
24 "strconv"
25 "strings"
26 "syscall"
27 "testing"
28 "time"
29 "unsafe"
30 )
31
32
33
34 func whoamiNEWUSER(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
35 t.Helper()
36 testenv.MustHaveExecPath(t, "whoami")
37 cmd := testenv.Command(t, "whoami")
38 cmd.SysProcAttr = &syscall.SysProcAttr{
39 Cloneflags: syscall.CLONE_NEWUSER,
40 UidMappings: []syscall.SysProcIDMap{
41 {ContainerID: 0, HostID: uid, Size: 1},
42 },
43 GidMappings: []syscall.SysProcIDMap{
44 {ContainerID: 0, HostID: gid, Size: 1},
45 },
46 GidMappingsEnableSetgroups: setgroups,
47 }
48 return cmd
49 }
50
51 func TestCloneNEWUSERAndRemap(t *testing.T) {
52 for _, setgroups := range []bool{false, true} {
53 setgroups := setgroups
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 testenv.MustHaveExec(t)
236 exe, err := os.Executable()
237 if err != nil {
238 t.Fatal(err)
239 }
240
241 d := t.TempDir()
242 t.Cleanup(func() {
243
244
245 if _, err := os.Stat(d); err == nil {
246 syscall.Unmount(d, syscall.MNT_FORCE)
247 }
248 })
249 cmd := testenv.Command(t, exe, "-test.run=^TestUnshareMountNameSpace$", d)
250 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
251 cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
252
253 out, err := cmd.CombinedOutput()
254 if err != nil {
255 if testenv.SyscallIsNotSupported(err) {
256 t.Skipf("skipping: could not start process with CLONE_NEWNS: %v", err)
257 }
258 t.Fatalf("unshare failed: %v\n%s", err, out)
259 } else if len(out) != 0 {
260 if bytes.HasPrefix(out, []byte(mountNotSupported)) {
261 t.Skipf("skipping: helper process reported %s", out)
262 }
263 t.Fatalf("unexpected output from helper process: %s", out)
264 }
265
266
267
268
269 if err := os.Remove(d); err != nil {
270 t.Errorf("rmdir failed on %v: %v", d, err)
271 }
272 }
273
274
275 func TestUnshareMountNameSpaceChroot(t *testing.T) {
276 const mountNotSupported = "mount is not supported: "
277 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
278 dir := flag.Args()[0]
279 err := syscall.Mount("none", dir, "proc", 0, "")
280 if testenv.SyscallIsNotSupported(err) {
281 fmt.Print(mountNotSupported, err)
282 } else if err != nil {
283 fmt.Fprintf(os.Stderr, "unshare: mount %s: %v\n", dir, err)
284 os.Exit(2)
285 }
286 os.Exit(0)
287 }
288
289 d := t.TempDir()
290
291
292
293 testenv.MustHaveGoBuild(t)
294 if platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH, false) {
295 t.Skipf("skipping: can't build static binary because %s/%s requires external linking", runtime.GOOS, runtime.GOARCH)
296 }
297 x := filepath.Join(d, "syscall.test")
298 t.Cleanup(func() {
299
300
301 if _, err := os.Stat(d); err == nil {
302 syscall.Unmount(d, syscall.MNT_FORCE)
303 }
304 })
305
306 cmd := testenv.Command(t, testenv.GoToolPath(t), "test", "-c", "-o", x, "syscall")
307 cmd.Env = append(cmd.Environ(), "CGO_ENABLED=0")
308 if o, err := cmd.CombinedOutput(); err != nil {
309 t.Fatalf("%v: %v\n%s", cmd, err, o)
310 }
311
312 cmd = testenv.Command(t, "/syscall.test", "-test.run=^TestUnshareMountNameSpaceChroot$", "/")
313 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
314 cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: d, Unshareflags: syscall.CLONE_NEWNS}
315
316 out, err := cmd.CombinedOutput()
317 if err != nil {
318 if testenv.SyscallIsNotSupported(err) {
319 t.Skipf("skipping: could not start process with CLONE_NEWNS and Chroot %q: %v", d, err)
320 }
321 t.Fatalf("unshare failed: %v\n%s", err, out)
322 } else if len(out) != 0 {
323 if bytes.HasPrefix(out, []byte(mountNotSupported)) {
324 t.Skipf("skipping: helper process reported %s", out)
325 }
326 t.Fatalf("unexpected output from helper process: %s", out)
327 }
328
329
330
331
332 if err := os.Remove(x); err != nil {
333 t.Errorf("rm failed on %v: %v", x, err)
334 }
335 if err := os.Remove(d); err != nil {
336 t.Errorf("rmdir failed on %v: %v", d, err)
337 }
338 }
339
340
341 func TestUnshareUidGidMapping(t *testing.T) {
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 testenv.MustHaveExec(t)
355 exe, err := os.Executable()
356 if err != nil {
357 t.Fatal(err)
358 }
359
360 cmd := testenv.Command(t, exe, "-test.run=^TestUnshareUidGidMapping$")
361 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
362 cmd.SysProcAttr = &syscall.SysProcAttr{
363 Unshareflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER,
364 GidMappingsEnableSetgroups: false,
365 UidMappings: []syscall.SysProcIDMap{
366 {
367 ContainerID: 0,
368 HostID: syscall.Getuid(),
369 Size: 1,
370 },
371 },
372 GidMappings: []syscall.SysProcIDMap{
373 {
374 ContainerID: 0,
375 HostID: syscall.Getgid(),
376 Size: 1,
377 },
378 },
379 }
380 out, err := cmd.CombinedOutput()
381 if err != nil {
382 if testenv.SyscallIsNotSupported(err) {
383 t.Skipf("skipping: could not start process with CLONE_NEWNS and CLONE_NEWUSER: %v", err)
384 }
385 t.Fatalf("Cmd failed with err %v, output: %s", err, out)
386 }
387 }
388
389 func prepareCgroupFD(t *testing.T) (int, string) {
390 t.Helper()
391
392 const O_PATH = 0x200000
393
394
395 const prefix = "/sys/fs/cgroup"
396 selfCg, err := os.ReadFile("/proc/self/cgroup")
397 if err != nil {
398 if os.IsNotExist(err) || os.IsPermission(err) {
399 t.Skip(err)
400 }
401 t.Fatal(err)
402 }
403
404
405
406
407 if bytes.Count(selfCg, []byte("\n")) > 1 {
408 t.Skip("cgroup v2 not available")
409 }
410 cg := bytes.TrimPrefix(selfCg, []byte("0::"))
411 if len(cg) == len(selfCg) {
412 t.Skipf("cgroup v2 not available (/proc/self/cgroup contents: %q)", selfCg)
413 }
414
415
416 subCgroup, err := os.MkdirTemp(prefix+string(bytes.TrimSpace(cg)), "subcg-")
417 if err != nil {
418
419
420 if os.IsNotExist(err) || testenv.SyscallIsNotSupported(err) {
421 t.Skipf("skipping: %v", err)
422 }
423 t.Fatal(err)
424 }
425 t.Cleanup(func() { syscall.Rmdir(subCgroup) })
426
427 cgroupFD, err := syscall.Open(subCgroup, O_PATH, 0)
428 if err != nil {
429 t.Fatal(&os.PathError{Op: "open", Path: subCgroup, Err: err})
430 }
431 t.Cleanup(func() { syscall.Close(cgroupFD) })
432
433 return cgroupFD, "/" + path.Base(subCgroup)
434 }
435
436 func TestUseCgroupFD(t *testing.T) {
437 testenv.MustHaveExec(t)
438
439 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
440
441 selfCg, err := os.ReadFile("/proc/self/cgroup")
442 if err != nil {
443 fmt.Fprintln(os.Stderr, err)
444 os.Exit(2)
445 }
446 fmt.Print(string(selfCg))
447 os.Exit(0)
448 }
449
450 exe, err := os.Executable()
451 if err != nil {
452 t.Fatal(err)
453 }
454
455 fd, suffix := prepareCgroupFD(t)
456
457 cmd := testenv.Command(t, exe, "-test.run=^TestUseCgroupFD$")
458 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
459 cmd.SysProcAttr = &syscall.SysProcAttr{
460 UseCgroupFD: true,
461 CgroupFD: fd,
462 }
463 out, err := cmd.CombinedOutput()
464 if err != nil {
465 if testenv.SyscallIsNotSupported(err) && !errors.Is(err, syscall.EINVAL) {
466
467
468
469
470 t.Skipf("clone3 with CLONE_INTO_CGROUP not available: %v", err)
471 }
472 t.Fatalf("Cmd failed with err %v, output: %s", err, out)
473 }
474
475 if !bytes.HasSuffix(bytes.TrimSpace(out), []byte(suffix)) {
476 t.Fatalf("got: %q, want: a line that ends with %q", out, suffix)
477 }
478 }
479
480 func TestCloneTimeNamespace(t *testing.T) {
481 testenv.MustHaveExec(t)
482
483 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
484 timens, err := os.Readlink("/proc/self/ns/time")
485 if err != nil {
486 fmt.Fprintln(os.Stderr, err)
487 os.Exit(2)
488 }
489 fmt.Print(string(timens))
490 os.Exit(0)
491 }
492
493 exe, err := os.Executable()
494 if err != nil {
495 t.Fatal(err)
496 }
497
498 cmd := testenv.Command(t, exe, "-test.run=^TestCloneTimeNamespace$")
499 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
500 cmd.SysProcAttr = &syscall.SysProcAttr{
501 Cloneflags: syscall.CLONE_NEWTIME,
502 }
503 out, err := cmd.CombinedOutput()
504 if err != nil {
505 if testenv.SyscallIsNotSupported(err) {
506
507 t.Skipf("skipping, CLONE_NEWTIME not supported: %v", err)
508 }
509 t.Fatalf("Cmd failed with err %v, output: %s", err, out)
510 }
511
512
513
514 timens, err := os.Readlink("/proc/self/ns/time")
515 if err != nil {
516 t.Fatal(err)
517 }
518
519 parentTimeNS := timens
520 childTimeNS := string(out)
521 if childTimeNS == parentTimeNS {
522 t.Fatalf("expected child time namespace to be different from parent time namespace: %s", parentTimeNS)
523 }
524 }
525
526 func testPidFD(t *testing.T, userns bool) error {
527 testenv.MustHaveExec(t)
528
529 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
530
531 time.Sleep(time.Hour)
532 }
533
534 exe, err := os.Executable()
535 if err != nil {
536 t.Fatal(err)
537 }
538
539 var pidfd int
540 cmd := testenv.Command(t, exe, "-test.run=^TestPidFD$")
541 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
542 cmd.SysProcAttr = &syscall.SysProcAttr{
543 PidFD: &pidfd,
544 }
545 if userns {
546 cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER
547 }
548 if err := cmd.Start(); err != nil {
549 return err
550 }
551 defer func() {
552 cmd.Process.Kill()
553 cmd.Wait()
554 }()
555 t.Log("got pidfd:", pidfd)
556
557 if pidfd == -1 {
558 t.Skip("pidfd not supported")
559 }
560 defer syscall.Close(pidfd)
561
562
563 sig := syscall.SIGINT
564 if err := unix.PidFDSendSignal(uintptr(pidfd), sig); err != nil {
565 if err != syscall.EINVAL && testenv.SyscallIsNotSupported(err) {
566 t.Skip("pidfd_send_signal syscall not supported:", err)
567 }
568 t.Fatal("pidfd_send_signal syscall failed:", err)
569 }
570
571 err = cmd.Wait()
572 if cmd.ProcessState == nil || cmd.ProcessState.Sys().(syscall.WaitStatus).Signal() != sig {
573 t.Fatal("unexpected child error:", err)
574 }
575 return nil
576 }
577
578 func TestPidFD(t *testing.T) {
579 if err := testPidFD(t, false); err != nil {
580 t.Fatal("can't start a process:", err)
581 }
582 }
583
584 func TestPidFDWithUserNS(t *testing.T) {
585 if err := testPidFD(t, true); err != nil {
586 if testenv.SyscallIsNotSupported(err) {
587 t.Skip("userns not supported:", err)
588 }
589 t.Fatal("can't start a process:", err)
590 }
591 }
592
593 func TestPidFDClone3(t *testing.T) {
594 *syscall.ForceClone3 = true
595 defer func() { *syscall.ForceClone3 = false }()
596
597 if err := testPidFD(t, false); err != nil {
598 if testenv.SyscallIsNotSupported(err) {
599 t.Skip("clone3 not supported:", err)
600 }
601 t.Fatal("can't start a process:", err)
602 }
603 }
604
605 type capHeader struct {
606 version uint32
607 pid int32
608 }
609
610 type capData struct {
611 effective uint32
612 permitted uint32
613 inheritable uint32
614 }
615
616 const CAP_SYS_TIME = 25
617 const CAP_SYSLOG = 34
618
619 type caps struct {
620 hdr capHeader
621 data [2]capData
622 }
623
624 func getCaps() (caps, error) {
625 var c caps
626
627
628 if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(nil)), 0); errno != 0 {
629 return c, fmt.Errorf("SYS_CAPGET: %v", errno)
630 }
631
632
633 if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(&c.data[0])), 0); errno != 0 {
634 return c, fmt.Errorf("SYS_CAPGET: %v", errno)
635 }
636
637 return c, nil
638 }
639
640 func TestAmbientCaps(t *testing.T) {
641 testAmbientCaps(t, false)
642 }
643
644 func TestAmbientCapsUserns(t *testing.T) {
645 b, err := os.ReadFile("/proc/sys/kernel/apparmor_restrict_unprivileged_userns")
646 if err == nil && strings.TrimSpace(string(b)) == "1" {
647 t.Skip("AppArmor restriction for unprivileged user namespaces is enabled")
648 }
649 testAmbientCaps(t, true)
650 }
651
652 func testAmbientCaps(t *testing.T, userns bool) {
653 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
654 caps, err := getCaps()
655 if err != nil {
656 fmt.Fprintln(os.Stderr, err)
657 os.Exit(2)
658 }
659 if caps.data[0].effective&(1<<uint(CAP_SYS_TIME)) == 0 {
660 fmt.Fprintln(os.Stderr, "CAP_SYS_TIME unexpectedly not in the effective capability mask")
661 os.Exit(2)
662 }
663 if caps.data[1].effective&(1<<uint(CAP_SYSLOG&31)) == 0 {
664 fmt.Fprintln(os.Stderr, "CAP_SYSLOG unexpectedly not in the effective capability mask")
665 os.Exit(2)
666 }
667 os.Exit(0)
668 }
669
670
671 if runtime.GOOS == "android" {
672 t.Skip("skipping test on android; see Issue 27327")
673 }
674
675 u, err := user.Lookup("nobody")
676 if err != nil {
677 t.Fatal(err)
678 }
679 uid, err := strconv.ParseInt(u.Uid, 0, 32)
680 if err != nil {
681 t.Fatal(err)
682 }
683 gid, err := strconv.ParseInt(u.Gid, 0, 32)
684 if err != nil {
685 t.Fatal(err)
686 }
687
688
689 f, err := os.CreateTemp("", "gotest")
690 if err != nil {
691 t.Fatal(err)
692 }
693 t.Cleanup(func() {
694 f.Close()
695 os.Remove(f.Name())
696 })
697
698 testenv.MustHaveExec(t)
699 exe, err := os.Executable()
700 if err != nil {
701 t.Fatal(err)
702 }
703
704 e, err := os.Open(exe)
705 if err != nil {
706 t.Fatal(err)
707 }
708 defer e.Close()
709 if _, err := io.Copy(f, e); err != nil {
710 t.Fatal(err)
711 }
712 if err := f.Chmod(0755); err != nil {
713 t.Fatal(err)
714 }
715 if err := f.Close(); err != nil {
716 t.Fatal(err)
717 }
718
719 cmd := testenv.Command(t, f.Name(), "-test.run=^"+t.Name()+"$")
720 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
721 cmd.Stdout = os.Stdout
722 cmd.Stderr = os.Stderr
723 cmd.SysProcAttr = &syscall.SysProcAttr{
724 Credential: &syscall.Credential{
725 Uid: uint32(uid),
726 Gid: uint32(gid),
727 },
728 AmbientCaps: []uintptr{CAP_SYS_TIME, CAP_SYSLOG},
729 }
730 if userns {
731 cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER
732 const nobody = 65534
733 uid := os.Getuid()
734 gid := os.Getgid()
735 cmd.SysProcAttr.UidMappings = []syscall.SysProcIDMap{{
736 ContainerID: int(nobody),
737 HostID: uid,
738 Size: int(1),
739 }}
740 cmd.SysProcAttr.GidMappings = []syscall.SysProcIDMap{{
741 ContainerID: int(nobody),
742 HostID: gid,
743 Size: int(1),
744 }}
745
746
747 cmd.SysProcAttr.Credential = &syscall.Credential{
748 Uid: nobody,
749 Gid: nobody,
750 }
751 }
752 if err := cmd.Run(); err != nil {
753 if testenv.SyscallIsNotSupported(err) {
754 t.Skipf("skipping: %v: %v", cmd, err)
755 }
756 t.Fatal(err.Error())
757 }
758 }
759
View as plain text