Skip to content

Commit 7c019c6

Browse files
tklausergopherbot
authored andcommitted
syscall: use clone3 syscall with CLONE_NEWTIME
CLONE_NEWTIME can only be used with the clone3 and unshare system calls, see torvalds/linux@769071a: > All available clone flags have been used, so CLONE_NEWTIME uses the highest > bit of CSIGNAL. It means that it can be used only with the unshare() and > the clone3() system calls. The clone3 syscall was added in Linux kernel version 5.3 and CLONE_NEWTIME was added in version 5.6. However, it was non-functional until version 6.3 (and stable versions with the corresponding fix [1]). [1] https://lore.kernel.org/lkml/[email protected]/ In case CLONE_NEWTIME is set in SysProcAttr.Cloneflags on an unsupported kernel version, the fork/exec call will fail. Fixes #49779 Change-Id: Ic3ecfc2b601bafaab12b1805d7f9512955a8c7e2 Reviewed-on: https://go-review.googlesource.com/c/go/+/474356 TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Tobias Klauser <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Auto-Submit: Tobias Klauser <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent 778627f commit 7c019c6

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/syscall/exec_linux.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
293293
exitSignal: uint64(SIGCHLD),
294294
cgroup: uint64(sys.CgroupFD),
295295
}
296+
} else if flags&CLONE_NEWTIME != 0 {
297+
clone3 = &cloneArgs{
298+
flags: uint64(flags),
299+
exitSignal: uint64(SIGCHLD),
300+
}
296301
}
297302

298303
// About to call fork.

src/syscall/exec_linux_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,52 @@ func TestUseCgroupFDHelper(*testing.T) {
487487
fmt.Print(string(selfCg))
488488
}
489489

490+
func TestCloneTimeNamespace(t *testing.T) {
491+
testenv.MustHaveExec(t)
492+
493+
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
494+
timens, err := os.Readlink("/proc/self/ns/time")
495+
if err != nil {
496+
fmt.Fprintln(os.Stderr, err)
497+
os.Exit(2)
498+
}
499+
fmt.Print(string(timens))
500+
os.Exit(0)
501+
}
502+
503+
exe, err := os.Executable()
504+
if err != nil {
505+
t.Fatal(err)
506+
}
507+
508+
cmd := testenv.Command(t, exe, "-test.run=TestCloneTimeNamespace")
509+
cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
510+
cmd.SysProcAttr = &syscall.SysProcAttr{
511+
Cloneflags: syscall.CLONE_NEWTIME,
512+
}
513+
out, err := cmd.CombinedOutput()
514+
if err != nil {
515+
if isNotSupported(err) {
516+
// CLONE_NEWTIME does not appear to be supported.
517+
t.Skipf("skipping, CLONE_NEWTIME not supported: %v", err)
518+
}
519+
t.Fatalf("Cmd failed with err %v, output: %s", err, out)
520+
}
521+
522+
// Inode numer of the time namespaces should be different.
523+
// Based on https://man7.org/linux/man-pages/man7/time_namespaces.7.html#EXAMPLES
524+
timens, err := os.Readlink("/proc/self/ns/time")
525+
if err != nil {
526+
t.Fatal(err)
527+
}
528+
529+
parentTimeNS := string(timens)
530+
childTimeNS := string(out)
531+
if childTimeNS == parentTimeNS {
532+
t.Fatalf("expected child time namespace to be different from parent time namespace: %s", parentTimeNS)
533+
}
534+
}
535+
490536
type capHeader struct {
491537
version uint32
492538
pid int32

0 commit comments

Comments
 (0)