mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
committed by
gVisor bot
parent
8ff6816f07
commit
21d66119b7
@@ -46,9 +46,16 @@ const (
|
||||
// Only passable via clone3(2).
|
||||
CLONE_CLEAR_SIGHAND = 0x100000000
|
||||
CLONE_INTO_CGROUP = 0x200000000
|
||||
|
||||
// Sizeof first published struct.
|
||||
CLONE_ARGS_SIZE_VER0 = 64
|
||||
// Sizeof third published struct.
|
||||
CLONE_ARGS_SIZE_VER2 = 88
|
||||
)
|
||||
|
||||
// CloneArgs is struct clone_args, from include/uapi/linux/sched.h.
|
||||
//
|
||||
// +marshal
|
||||
type CloneArgs struct {
|
||||
Flags uint64
|
||||
Pidfd uint64
|
||||
|
||||
@@ -30,6 +30,16 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
// SupportedFlags is the bitwise OR of all the supported flags for clone.
|
||||
// TODO(b/290826530): Implement CLONE_INTO_CGROUP when cgroups v2 is
|
||||
// implemented.
|
||||
const SupportedFlags = linux.CLONE_VM | linux.CLONE_FS | linux.CLONE_FILES | linux.CLONE_SYSVSEM |
|
||||
linux.CLONE_THREAD | linux.CLONE_SIGHAND | linux.CLONE_CHILD_SETTID | linux.CLONE_NEWPID |
|
||||
linux.CLONE_CHILD_CLEARTID | linux.CLONE_CHILD_SETTID | linux.CLONE_PARENT |
|
||||
linux.CLONE_PARENT_SETTID | linux.CLONE_SETTLS | linux.CLONE_NEWUSER | linux.CLONE_NEWUTS |
|
||||
linux.CLONE_NEWIPC | linux.CLONE_NEWNET | linux.CLONE_PTRACE | linux.CLONE_UNTRACED |
|
||||
linux.CLONE_IO | linux.CLONE_VFORK
|
||||
|
||||
// Clone implements the clone(2) syscall and returns the thread ID of the new
|
||||
// task in t's PID namespace. Clone may return both a non-zero thread ID and a
|
||||
// non-nil error.
|
||||
@@ -37,12 +47,18 @@ import (
|
||||
// Preconditions: The caller must be running Task.doSyscallInvoke on the task
|
||||
// goroutine.
|
||||
func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) {
|
||||
if args.Flags&^SupportedFlags != 0 {
|
||||
return 0, nil, linuxerr.EINVAL
|
||||
}
|
||||
// Since signal actions may refer to application signal handlers by virtual
|
||||
// address, any set of signal handlers must refer to the same address
|
||||
// space.
|
||||
if args.Flags&(linux.CLONE_SIGHAND|linux.CLONE_VM) == linux.CLONE_SIGHAND {
|
||||
return 0, nil, linuxerr.EINVAL
|
||||
}
|
||||
if args.SetTID != 0 {
|
||||
return 0, nil, linuxerr.ENOTSUP
|
||||
}
|
||||
// In order for the behavior of thread-group-directed signals to be sane,
|
||||
// all tasks in a thread group must share signal handlers.
|
||||
if args.Flags&(linux.CLONE_THREAD|linux.CLONE_SIGHAND) == linux.CLONE_THREAD {
|
||||
@@ -160,7 +176,7 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) {
|
||||
// clone() returns 0 in the child.
|
||||
image.Arch.SetReturn(0)
|
||||
if args.Stack != 0 {
|
||||
image.Arch.SetStack(uintptr(args.Stack))
|
||||
image.Arch.SetStack(uintptr(args.Stack + args.StackSize))
|
||||
}
|
||||
if args.Flags&linux.CLONE_SETTLS != 0 {
|
||||
if !image.Arch.SetTLS(uintptr(args.TLS)) {
|
||||
|
||||
@@ -108,7 +108,7 @@ var AMD64 = &kernel.SyscallTable{
|
||||
53: syscalls.SupportedPoint("socketpair", SocketPair, PointSocketpair),
|
||||
54: syscalls.Supported("setsockopt", SetSockOpt),
|
||||
55: syscalls.Supported("getsockopt", GetSockOpt),
|
||||
56: syscalls.PartiallySupportedPoint("clone", Clone, PointClone, "Mount namespace (CLONE_NEWNS) not supported. Options CLONE_PARENT, CLONE_SYSVSEM not supported.", nil),
|
||||
56: syscalls.PartiallySupportedPoint("clone", Clone, PointClone, "Options CLONE_PIDFD, CLONE_NEWNS, CLONE_PARENT, CLONE_NEWTIME, CLONE_CLEAR_SIGHAND, and CLONE_SYSVSEM not supported.", nil),
|
||||
57: syscalls.SupportedPoint("fork", Fork, PointFork),
|
||||
58: syscalls.SupportedPoint("vfork", Vfork, PointVfork),
|
||||
59: syscalls.SupportedPoint("execve", Execve, PointExecve),
|
||||
@@ -403,7 +403,7 @@ var AMD64 = &kernel.SyscallTable{
|
||||
432: syscalls.ErrorWithEvent("fsmount", linuxerr.ENOSYS, "", nil),
|
||||
433: syscalls.ErrorWithEvent("fspick", linuxerr.ENOSYS, "", nil),
|
||||
434: syscalls.ErrorWithEvent("pidfd_open", linuxerr.ENOSYS, "", nil),
|
||||
435: syscalls.ErrorWithEvent("clone3", linuxerr.ENOSYS, "", nil),
|
||||
435: syscalls.PartiallySupported("clone3", Clone3, "Options CLONE_PIDFD, CLONE_NEWNS, CLONE_INTO_CGROUP, CLONE_NEWTIME, CLONE_CLEAR_SIGHAND, CLONE_PARENT, CLONE_SYSVSEM and, SetTid are not supported.", nil),
|
||||
436: syscalls.Supported("close_range", CloseRange),
|
||||
439: syscalls.Supported("faccessat2", Faccessat2),
|
||||
441: syscalls.Supported("epoll_pwait2", EpollPwait2),
|
||||
@@ -651,7 +651,7 @@ var ARM64 = &kernel.SyscallTable{
|
||||
217: syscalls.Error("add_key", linuxerr.EACCES, "Not available to user.", nil),
|
||||
218: syscalls.Error("request_key", linuxerr.EACCES, "Not available to user.", nil),
|
||||
219: syscalls.Error("keyctl", linuxerr.EACCES, "Not available to user.", nil),
|
||||
220: syscalls.PartiallySupportedPoint("clone", Clone, PointClone, "Mount namespace (CLONE_NEWNS) not supported. Options CLONE_PARENT, CLONE_SYSVSEM not supported.", nil),
|
||||
220: syscalls.PartiallySupportedPoint("clone", Clone, PointClone, "Options CLONE_PIDFD, CLONE_NEWNS, CLONE_PARENT, CLONE_NEWTIME, CLONE_CLEAR_SIGHAND, and CLONE_SYSVSEM not supported.", nil),
|
||||
221: syscalls.SupportedPoint("execve", Execve, PointExecve),
|
||||
222: syscalls.Supported("mmap", Mmap),
|
||||
223: syscalls.PartiallySupported("fadvise64", Fadvise64, "Not all options are supported.", nil),
|
||||
@@ -724,7 +724,7 @@ var ARM64 = &kernel.SyscallTable{
|
||||
432: syscalls.ErrorWithEvent("fsmount", linuxerr.ENOSYS, "", nil),
|
||||
433: syscalls.ErrorWithEvent("fspick", linuxerr.ENOSYS, "", nil),
|
||||
434: syscalls.ErrorWithEvent("pidfd_open", linuxerr.ENOSYS, "", nil),
|
||||
435: syscalls.ErrorWithEvent("clone3", linuxerr.ENOSYS, "", nil),
|
||||
435: syscalls.PartiallySupported("clone3", Clone3, "Options CLONE_PIDFD, CLONE_NEWNS, CLONE_INTO_CGROUP, CLONE_NEWTIME, CLONE_CLEAR_SIGHAND, CLONE_PARENT, CLONE_SYSVSEM and clone_args.set_tid are not supported.", nil),
|
||||
436: syscalls.Supported("close_range", CloseRange),
|
||||
439: syscalls.Supported("faccessat2", Faccessat2),
|
||||
441: syscalls.Supported("epoll_pwait2", EpollPwait2),
|
||||
|
||||
@@ -206,7 +206,6 @@ func ExitGroup(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintp
|
||||
func clone(t *kernel.Task, flags int, stack hostarch.Addr, parentTID hostarch.Addr, childTID hostarch.Addr, tls hostarch.Addr) (uintptr, *kernel.SyscallControl, error) {
|
||||
args := linux.CloneArgs{
|
||||
Flags: uint64(uint32(flags) &^ linux.CSIGNAL),
|
||||
Pidfd: uint64(parentTID),
|
||||
ChildTID: uint64(childTID),
|
||||
ParentTID: uint64(parentTID),
|
||||
ExitSignal: uint64(flags & linux.CSIGNAL),
|
||||
@@ -234,6 +233,29 @@ func Vfork(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr,
|
||||
return clone(t, linux.CLONE_VM|linux.CLONE_VFORK|int(linux.SIGCHLD), 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
// Clone3 implements linux syscall clone3(2).
|
||||
func Clone3(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
cloneArgsPointer := args[0].Pointer()
|
||||
size := args[1].SizeT()
|
||||
|
||||
if int(size) < linux.CLONE_ARGS_SIZE_VER0 || int(size) > linux.CLONE_ARGS_SIZE_VER2 {
|
||||
return 0, nil, linuxerr.EINVAL
|
||||
}
|
||||
|
||||
var cloneArgs linux.CloneArgs
|
||||
if cloneArgsPointer != 0 {
|
||||
if _, err := cloneArgs.CopyInN(t, cloneArgsPointer, int(size)); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ntid, ctrl, err := t.Clone(&cloneArgs)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return uintptr(ntid), ctrl, err
|
||||
}
|
||||
|
||||
// parseCommonWaitOptions applies the options common to wait4 and waitid to
|
||||
// wopts.
|
||||
func parseCommonWaitOptions(wopts *kernel.WaitOptions, options int) error {
|
||||
|
||||
@@ -18,12 +18,16 @@
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
@@ -459,6 +463,79 @@ TEST(CloneTest, NonCanonicalTLS) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SYS_clone3
|
||||
#define SYS_clone3 435
|
||||
#endif // SYS_clone3
|
||||
|
||||
// struct clone_args is a Linux clone struct. Old versions of glibc do not
|
||||
// expose it. See include/uapi/linux/sched.h
|
||||
struct clone_args {
|
||||
uint64_t flags;
|
||||
uint64_t pidfd;
|
||||
uint64_t child_tid;
|
||||
uint64_t parent_tid;
|
||||
uint64_t exit_signal;
|
||||
uint64_t stack;
|
||||
uint64_t stack_size;
|
||||
uint64_t tls;
|
||||
uint64_t set_tid;
|
||||
uint64_t set_tid_size;
|
||||
uint64_t cgroup;
|
||||
};
|
||||
|
||||
int clone3(struct clone_args* ca, size_t size) {
|
||||
return syscall(SYS_clone3, ca, size);
|
||||
}
|
||||
|
||||
// Checks that clone fails for any unsupported flag.
|
||||
TEST(CloneTest, Clone3UnknownFlag) {
|
||||
clone_args ca = {};
|
||||
ca.flags = (1ULL << 63);
|
||||
ca.exit_signal = SIGCHLD;
|
||||
EXPECT_THAT(clone3(&ca, sizeof(ca)), SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
// Clone3 works as Clone.
|
||||
TEST(CloneTest, Clone3AsClone) {
|
||||
clone_args ca = {};
|
||||
ca.exit_signal = SIGCHLD;
|
||||
|
||||
int child_pid;
|
||||
EXPECT_THAT(child_pid = clone3(&ca, sizeof(ca)), SyscallSucceeds());
|
||||
|
||||
if (child_pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int status;
|
||||
EXPECT_THAT(waitpid(child_pid, &status, 0),
|
||||
SyscallSucceedsWithValue(child_pid));
|
||||
EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
|
||||
}
|
||||
|
||||
// Clone3 works with basic Clone3 values for args like exit_signal & parent_tid.
|
||||
TEST(CloneTest, Clone3Basic) {
|
||||
clone_args ca = {};
|
||||
|
||||
ca.flags = CLONE_PARENT_SETTID;
|
||||
ca.exit_signal = SIGCHLD;
|
||||
|
||||
pid_t store_child_tid = 0;
|
||||
ca.parent_tid = reinterpret_cast<uint64_t>(&store_child_tid);
|
||||
int child_pid;
|
||||
EXPECT_THAT(child_pid = clone3(&ca, sizeof(ca)), SyscallSucceeds());
|
||||
EXPECT_EQ(store_child_tid, child_pid);
|
||||
|
||||
if (child_pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int status;
|
||||
EXPECT_THAT(waitpid(child_pid, &status, 0),
|
||||
SyscallSucceedsWithValue(child_pid));
|
||||
EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
Reference in New Issue
Block a user