Adding more trace point integration tests for the following syscalls:

- signalfd
  - signalfd4
  - fcntl
  - pipe
  - pipe2
  - timerfd_create
  - timerfd_settime
  - timerfd_gettime
  - fork
  - vfork
  - inotify_init
  - inotify_init1
  - inotify_add_watch
  - inotify_rm_watch
  - clone

Updates #4805

PiperOrigin-RevId: 492297673
This commit is contained in:
Shambhavi Srivastava
2022-12-01 14:19:28 -08:00
committed by gVisor bot
parent 9c444c44e0
commit 4e11daccf0
6 changed files with 553 additions and 29 deletions
+5 -2
View File
@@ -4,8 +4,11 @@ package(licenses = ["notice"])
go_test(
name = "trace_test",
size = "small",
srcs = ["trace_test.go"],
srcs = [
"trace_amd64_test.go",
"trace_arm64_test.go",
"trace_test.go",
],
data = [
"//runsc",
"//test/trace/workload",
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build amd64
// +build amd64
package trace
import (
"fmt"
"testing"
"golang.org/x/sys/unix"
"google.golang.org/protobuf/proto"
pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto"
"gvisor.dev/gvisor/pkg/sentry/seccheck/sinks/remote/test"
)
func extraMatchers(t *testing.T, msgs []test.Message, matchers map[pb.MessageType]*checkers) {
// Register functions that verify each available point specific to amd64 architecture.
matchers[pb.MessageType_MESSAGE_SYSCALL_FORK] = &checkers{checker: checkSyscallFork}
}
func checkSyscallSignalfdFlags(flags int32) error {
if flags != 0 && flags != (unix.SFD_CLOEXEC|unix.SFD_NONBLOCK) {
return fmt.Errorf("invalid flag got: %v", flags)
}
return nil
}
func checkSyscallFork(msg test.Message) error {
p := pb.Fork{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
return nil
}
+39
View File
@@ -0,0 +1,39 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build arm64
// +build arm64
package trace
import (
"fmt"
"testing"
"golang.org/x/sys/unix"
pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto"
"gvisor.dev/gvisor/pkg/sentry/seccheck/sinks/remote/test"
)
func extraMatchers(t *testing.T, msgs []test.Message, matchers map[pb.MessageType]*checkers) {
// Register functions that verify each available point specific to arm64 architecture.
return
}
func checkSyscallSignalfdFlags(flags int32) error {
if flags != (unix.SFD_CLOEXEC | unix.SFD_NONBLOCK) {
return fmt.Errorf("invalid flag got: %v", flags)
}
return nil
}
+232 -26
View File
@@ -34,6 +34,11 @@ import (
var cutoffTime time.Time
type checkers struct {
checker func(test.Message) error
count int
}
// TestAll enabled all trace points in the system with all optional and context
// fields enabled. Then it runs a workload that will trigger those points and
// run some basic validation over the points generated.
@@ -87,15 +92,15 @@ func TestAll(t *testing.T) {
// Wait until the sandbox disconnects to ensure all points were gathered.
server.WaitForNoClients()
matchPoints(t, server.GetPoints())
matchers := matchPoints(t, server.GetPoints())
extraMatchers(t, server.GetPoints(), matchers)
validatePoints(t, server.GetPoints(), matchers)
}
func matchPoints(t *testing.T, msgs []test.Message) {
func matchPoints(t *testing.T, msgs []test.Message) map[pb.MessageType]*checkers {
// Register functions that verify each available point.
matchers := map[pb.MessageType]*struct {
checker func(test.Message) error
count int
}{
matchers := map[pb.MessageType]*checkers{
pb.MessageType_MESSAGE_CONTAINER_START: {checker: checkContainerStart},
pb.MessageType_MESSAGE_SENTRY_CLONE: {checker: checkSentryClone},
pb.MessageType_MESSAGE_SENTRY_EXEC: {checker: checkSentryExec},
@@ -116,13 +121,23 @@ func matchPoints(t *testing.T, msgs []test.Message) {
pb.MessageType_MESSAGE_SYSCALL_DUP: {checker: checkSyscallDup},
pb.MessageType_MESSAGE_SYSCALL_PRLIMIT64: {checker: checkSyscallPrlimit64},
pb.MessageType_MESSAGE_SYSCALL_EVENTFD: {checker: checkSyscallEventfd},
pb.MessageType_MESSAGE_SYSCALL_SIGNALFD: {checker: checkSyscallSignalfd},
pb.MessageType_MESSAGE_SYSCALL_BIND: {checker: checkSyscallBind},
pb.MessageType_MESSAGE_SYSCALL_ACCEPT: {checker: checkSyscallAccept},
// TODO(gvisor.dev/issue/4805): Add validation for these messages.
pb.MessageType_MESSAGE_SYSCALL_CLONE: {checker: checkTODO},
pb.MessageType_MESSAGE_SYSCALL_PIPE: {checker: checkTODO},
pb.MessageType_MESSAGE_SYSCALL_FCNTL: {checker: checkSyscallFcntl},
pb.MessageType_MESSAGE_SYSCALL_PIPE: {checker: checkSyscallPipe},
pb.MessageType_MESSAGE_SYSCALL_TIMERFD_CREATE: {checker: checkSyscallTimerfdCreate},
pb.MessageType_MESSAGE_SYSCALL_TIMERFD_SETTIME: {checker: checkSyscallTimerfdSettime},
pb.MessageType_MESSAGE_SYSCALL_TIMERFD_GETTIME: {checker: checkSyscallTimerfdGettime},
pb.MessageType_MESSAGE_SYSCALL_INOTIFY_INIT: {checker: checkSyscallInotifyInit},
pb.MessageType_MESSAGE_SYSCALL_INOTIFY_ADD_WATCH: {checker: checkSyscallInotifyInitAddWatch},
pb.MessageType_MESSAGE_SYSCALL_INOTIFY_RM_WATCH: {checker: checkSyscallInotifyInitRmWatch},
pb.MessageType_MESSAGE_SYSCALL_CLONE: {checker: checkSyscallClone},
}
return matchers
}
func validatePoints(t *testing.T, msgs []test.Message, matchers map[pb.MessageType]*checkers) {
for _, msg := range msgs {
t.Logf("Processing message type %v", msg.MsgType)
if handler := matchers[msg.MsgType]; handler == nil {
@@ -147,7 +162,7 @@ func matchPoints(t *testing.T, msgs []test.Message) {
func checkTimeNs(ns int64) error {
if ns <= int64(cutoffTime.Nanosecond()) {
return fmt.Errorf("time should not be less than %d (%v), got: %d (%v)", cutoffTime.Nanosecond(), cutoffTime, ns, time.Unix(0, ns))
return fmt.Errorf("time: got: %d (%v), should not be less than %d (%v)", ns, time.Unix(0, ns), cutoffTime.Nanosecond(), cutoffTime)
}
return nil
}
@@ -497,7 +512,7 @@ func checkSyscallSetid(msg test.Message) error {
return err
}
if p.Id != 0 {
return fmt.Errorf(" invalid id: %d", p.Id)
return fmt.Errorf("invalid id: %d", p.Id)
}
return nil
@@ -512,13 +527,13 @@ func checkSyscallSetresid(msg test.Message) error {
return err
}
if p.GetRid() != 0 {
return fmt.Errorf(" Invalid RID: %d", p.Rid)
return fmt.Errorf("invalid rid: %d", p.Rid)
}
if p.GetEid() != 0 {
return fmt.Errorf(" Invalid EID: %d", p.Eid)
return fmt.Errorf("invalid eid: %d", p.Eid)
}
if p.GetSid() != 0 {
return fmt.Errorf(" Invalid SID: %d", p.Sid)
return fmt.Errorf("invalid sid: %d", p.Sid)
}
return nil
@@ -551,10 +566,10 @@ func checkSyscallDup(msg test.Message) error {
return err
}
if p.OldFd < 0 {
return fmt.Errorf("invalid FD: %d", p.OldFd)
return fmt.Errorf("invalid fd: %d", p.OldFd)
}
if p.NewFd < 0 {
return fmt.Errorf("invalid FD: %d", p.NewFd)
return fmt.Errorf("invalid fd: %d", p.NewFd)
}
if p.Flags != unix.O_CLOEXEC && p.Flags != 0 {
return fmt.Errorf("invalid flag got: %v", p.Flags)
@@ -572,7 +587,7 @@ func checkSyscallPrlimit64(msg test.Message) error {
return err
}
if p.Pid < 0 {
return fmt.Errorf("invalid PID: %d", p.Pid)
return fmt.Errorf("invalid pid: %d", p.Pid)
}
return nil
}
@@ -586,10 +601,10 @@ func checkSyscallEventfd(msg test.Message) error {
return err
}
if p.Val < 0 {
return fmt.Errorf("invalid PID: %d", p.Val)
return fmt.Errorf("invalid pid: %d", p.Val)
}
if p.Flags != unix.EFD_NONBLOCK && p.Flags != 0 {
return fmt.Errorf("invalid Flag got: %d, ", p.Flags)
return fmt.Errorf("invalid flag got: %d, ", p.Flags)
}
return nil
@@ -604,10 +619,10 @@ func checkSyscallBind(msg test.Message) error {
return err
}
if p.Fd < 0 {
return fmt.Errorf("invalid FD: %d", p.Fd)
return fmt.Errorf("invalid fd: %d", p.Fd)
}
if p.FdPath == " " {
return fmt.Errorf("invalid Path: %v", p.FdPath)
return fmt.Errorf("invalid path: %v", p.FdPath)
}
if len(p.Address) == 0 {
return fmt.Errorf("invalid address: %d", p.Address)
@@ -624,10 +639,10 @@ func checkSyscallAccept(msg test.Message) error {
return err
}
if p.Fd < 0 {
return fmt.Errorf("invalid FD: %d", p.Fd)
return fmt.Errorf("invalid fd: %d", p.Fd)
}
if p.FdPath == "" {
return fmt.Errorf("invalid Path: %v", p.FdPath)
return fmt.Errorf("invalid path: %v", p.FdPath)
}
if len(p.Address) != 0 {
return fmt.Errorf("invalid address: %d, %v", p.Address, p.Sysno)
@@ -647,12 +662,203 @@ func checkSyscallChroot(msg test.Message) error {
return err
}
if want := "trace_test.abc"; !strings.Contains(p.Pathname, want) {
return fmt.Errorf("wrong Pathname, want: %q, got: %q", want, p.Pathname)
return fmt.Errorf("wrong pathname, want: %q, got: %q", want, p.Pathname)
}
return nil
}
func checkTODO(_ test.Message) error {
func checkSyscallFcntl(msg test.Message) error {
p := pb.Fcntl{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
if p.Fd < 0 {
return fmt.Errorf("invalid fd: %d", p.Fd)
}
if p.Cmd != unix.F_GETFL {
return fmt.Errorf("invalid cmd: got: %v, want: F_GETFL", p.Cmd)
}
return nil
}
func checkSyscallPipe(msg test.Message) error {
p := pb.Pipe{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
if p.Reader < 0 {
return fmt.Errorf("invalid reader fd: %d", p.Reader)
}
if p.Writer < 0 {
return fmt.Errorf("invalid writer fd: %d", p.Writer)
}
if p.Flags != unix.O_CLOEXEC && p.Flags != 0 {
return fmt.Errorf("invalid flag got: %v", p.Flags)
}
return nil
}
func checkSyscallSignalfd(msg test.Message) error {
p := pb.Signalfd{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
if p.Fd != -1 {
return fmt.Errorf("invalid fd: %d", p.Fd)
}
if p.Sigset != 0 && p.Sigset != uint64(unix.SIGILL) {
return fmt.Errorf("invalid signal got: %v", p.Sigset)
}
return checkSyscallSignalfdFlags(p.Flags)
}
func checkSyscallTimerfdCreate(msg test.Message) error {
p := pb.TimerfdCreate{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
if p.ClockId != unix.CLOCK_REALTIME {
return fmt.Errorf("invalid clockid: %d", p.ClockId)
}
if p.Flags != 0 {
return fmt.Errorf("invalid flag got: %v", p.Flags)
}
return nil
}
func checkSyscallTimerfdSettime(msg test.Message) error {
p := pb.TimerfdSetTime{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
if p.Fd < 0 {
return fmt.Errorf("invalid clockid: %d", p.Fd)
}
if p.FdPath == "" {
return fmt.Errorf("invalid path: %q", p.FdPath)
}
if p.Flags != unix.TFD_TIMER_ABSTIME {
return fmt.Errorf("invalid flag got: %v", p.Flags)
}
if p.OldValue != nil {
return fmt.Errorf("invalid oldvalue: %v", p.OldValue.String())
}
if p.NewValue == nil {
return fmt.Errorf("invalid oldvalue: %v", p.OldValue.String())
}
return nil
}
func checkSyscallTimerfdGettime(msg test.Message) error {
p := pb.TimerfdGetTime{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
if p.Fd < 0 {
return fmt.Errorf("invalid clockid: %d", p.Fd)
}
if p.FdPath == "" {
return fmt.Errorf("invalid path: %q", p.FdPath)
}
if p.CurValue == nil {
return fmt.Errorf("invalid oldvalue: %v", p.CurValue.String())
}
return nil
}
func checkSyscallClone(msg test.Message) error {
p := pb.Clone{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
// Flags used by default in system calls that use clone(2) in the underying.
rawFlags := unix.CLONE_CHILD_CLEARTID | unix.CLONE_CHILD_SETTID | uint64(unix.SIGCHLD)
// Flags used for clone(2) syscall in workload.cc
cloneFlags := uint64(unix.SIGCHLD) | unix.CLONE_VFORK | unix.CLONE_FILES
if p.Flags != uint64(rawFlags) && p.Flags != cloneFlags {
return fmt.Errorf("invalid flag got: %v", p.Flags)
}
if (p.Flags == uint64(rawFlags) && p.Stack != 0) || (p.Flags == cloneFlags && p.Stack == 0) {
return fmt.Errorf("invalid stack got: %v", p.Stack)
}
return nil
}
func checkSyscallInotifyInit(msg test.Message) error {
p := pb.InotifyInit{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
if !(p.Flags == 0 || p.Flags == unix.IN_NONBLOCK) {
return fmt.Errorf("invalid flag got: %v", p.Flags)
}
return nil
}
func checkSyscallInotifyInitAddWatch(msg test.Message) error {
p := pb.InotifyAddWatch{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
if p.Fd < 0 {
return fmt.Errorf("invalid fd: %d", p.Fd)
}
if p.FdPath == "" {
return fmt.Errorf("invalid path: %v", p.FdPath)
}
if want := "timer_trace_test.abc"; !strings.Contains(p.Pathname, want) {
return fmt.Errorf("wrong pathname, got: %q, want: %q", p.Pathname, want)
}
if want := unix.IN_NONBLOCK; want != int(p.Mask) {
return fmt.Errorf("invalid mask: want: %v, got:%v", want, p.Mask)
}
return nil
}
func checkSyscallInotifyInitRmWatch(msg test.Message) error {
p := pb.InotifyRmWatch{}
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
return err
}
if err := checkContextData(p.ContextData); err != nil {
return err
}
if p.Fd < 0 {
return fmt.Errorf("invalid fd: %d", p.Fd)
}
if p.FdPath == "" {
return fmt.Errorf("invalid path: %q", p.FdPath)
}
if p.Wd < 0 {
return fmt.Errorf("invalid wd: %d", p.Wd)
}
return nil
}
+2
View File
@@ -12,8 +12,10 @@ cc_binary(
deps = [
"//test/util:eventfd_util",
"//test/util:file_descriptor",
"//test/util:memory_util",
"//test/util:multiprocess_util",
"//test/util:posix_error",
"//test/util:signal_util",
"//test/util:test_util",
"@com_google_absl//absl/cleanup",
"@com_google_absl//absl/strings",
+224 -1
View File
@@ -12,17 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <bits/types/struct_itimerspec.h>
#include <err.h>
#include <fcntl.h>
#include <sched.h>
#include <stdlib.h>
#include <sys/eventfd.h>
#include <sys/inotify.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/timerfd.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <csignal>
#include <cstdio>
#include <iostream>
#include <ostream>
@@ -31,6 +39,7 @@
#include "absl/time/clock.h"
#include "test/util/eventfd_util.h"
#include "test/util/file_descriptor.h"
#include "test/util/memory_util.h"
#include "test/util/multiprocess_util.h"
#include "test/util/posix_error.h"
#include "test/util/test_util.h"
@@ -82,7 +91,6 @@ void runSocket() {
if (pid < 0) {
// Fork error.
err(1, "fork");
} else if (pid == 0) {
// Child.
close(parent_sock); // ensure it's not mistakely used in child.
@@ -458,6 +466,202 @@ void runAccept4() {
close(fd);
}
void runSignalfd4() {
sigset_t mask;
sigemptyset(&mask);
int res = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
if (res < 0) {
err(1, "signalfd4");
}
}
void runFcntl() {
const auto pathname = "trace_test.abc";
static constexpr mode_t kDefaultDirMode = 0755;
int path_or_error = mkdir(pathname, kDefaultDirMode);
if (path_or_error != 0) {
err(1, "mkdir");
}
int fd = open(pathname, O_DIRECTORY | O_RDONLY);
if (fd < 0) {
err(1, "open");
}
auto fd_closer = absl::MakeCleanup([fd] { close(fd); });
int res = fcntl(fd, F_GETFL);
if (res < 0) {
err(1, "fcntl");
}
rmdir(pathname);
}
void runPipe() {
int fd[2];
int res = pipe(fd);
if (res < 0) {
err(1, "pipe");
}
close(fd[0]);
close(fd[1]);
}
void runPipe2() {
int fd[2];
int res = pipe2(fd, O_CLOEXEC);
if (res < 0) {
err(1, "pipe2");
}
close(fd[0]);
close(fd[1]);
}
void runTimerfdCreate() {
int fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd < 0) {
err(1, "timerfd_create");
}
close(fd);
}
void runTimerfdSettime() {
int fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd < 0) {
err(1, "timerfd_create");
}
auto fd_closer = absl::MakeCleanup([fd] { close(fd); });
constexpr auto kInitial = absl::Milliseconds(10);
constexpr auto kInterval = absl::Milliseconds(25);
const itimerspec val = {absl::ToTimespec(kInitial),
absl::ToTimespec(kInterval)};
int res = timerfd_settime(fd, TFD_TIMER_ABSTIME, &val, 0);
if (res < 0) {
err(1, "timerfd_settime");
}
}
void runTimerfdGettime() {
int fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd < 0) {
err(1, "timerfd_create");
}
auto fd_closer = absl::MakeCleanup([fd] { close(fd); });
itimerspec val;
int res = timerfd_gettime(fd, &val);
if (res < 0) {
err(1, "timerfd_gettime");
}
}
// signalfd(2), fork(2), and vfork(2) system calls are not supported in arm
// architecture.
#ifdef __x86_64__
void runFork() {
pid_t pid = syscall(__NR_fork);
if (pid < 0) {
err(1, "fork");
} else if (pid == 0) {
exit(0);
}
RetryEINTR(waitpid)(pid, nullptr, 0);
}
void runVfork() {
pid_t pid = vfork();
if (pid < 0) {
err(1, "vfork");
} else if (pid == 0) {
_exit(0);
}
RetryEINTR(waitpid)(pid, nullptr, 0);
}
void runSignalfd() {
sigset_t mask;
sigemptyset(&mask);
constexpr int kSizeofKernelSigset = 8;
int res = syscall(__NR_signalfd, -1, &mask, kSizeofKernelSigset);
if (res < 0) {
err(1, "signalfd");
}
}
#endif
void runClone() {
Mapping child_stack = ASSERT_NO_ERRNO_AND_VALUE(
MmapAnon(kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE));
int child_pid;
child_pid = clone(
+[](void*) { return 0; },
reinterpret_cast<void*>(child_stack.addr() + kPageSize),
SIGCHLD | CLONE_VFORK | CLONE_FILES, nullptr);
if (child_pid < 0) {
err(1, "clone");
}
RetryEINTR(waitpid)(child_pid, nullptr, 0);
}
void runInotifyInit() {
int fd = inotify_init();
if (fd < 0) {
err(1, "inotify_init");
}
close(fd);
}
void runInotifyInit1() {
int fd = inotify_init1(IN_NONBLOCK);
if (fd < 0) {
err(1, "inotify_init1");
}
close(fd);
}
void runInotifyAddWatch() {
const auto pathname = "timer_trace_test.abc";
static constexpr mode_t kDefaultDirMode = 0755;
int path_or_error = mkdir(pathname, kDefaultDirMode);
if (path_or_error != 0) {
err(1, "mkdir");
}
int fd = inotify_init1(IN_NONBLOCK);
if (fd < 0) {
err(1, "inotify_init1");
}
auto fd_closer = absl::MakeCleanup([fd] { close(fd); });
int res = inotify_add_watch(fd, pathname, IN_NONBLOCK);
if (res < 0) {
err(1, "inotify_add_watch");
}
rmdir(pathname);
}
void runInotifyRmWatch() {
const auto pathname = "timer_trace_test.abc";
static constexpr mode_t kDefaultDirMode = 0755;
int path_or_error = mkdir(pathname, kDefaultDirMode);
if (path_or_error != 0) {
err(1, "mkdir");
}
int fd = inotify_init1(IN_NONBLOCK);
if (fd < 0) {
err(1, "inotify_init1");
}
auto fd_closer = absl::MakeCleanup([fd] { close(fd); });
int wd = inotify_add_watch(fd, pathname, IN_NONBLOCK);
if (wd < 0) {
err(1, "inotify_add_watch");
}
int res = inotify_rm_watch(fd, wd);
if (res < 0) {
err(1, "inotify_rm_watch");
}
rmdir(pathname);
}
} // namespace testing
} // namespace gvisor
@@ -481,6 +685,25 @@ int main(int argc, char** argv) {
::gvisor::testing::runBind();
::gvisor::testing::runAccept();
::gvisor::testing::runAccept4();
::gvisor::testing::runSignalfd4();
::gvisor::testing::runFcntl();
::gvisor::testing::runPipe();
::gvisor::testing::runPipe2();
::gvisor::testing::runTimerfdCreate();
::gvisor::testing::runTimerfdSettime();
::gvisor::testing::runTimerfdGettime();
::gvisor::testing::runClone();
::gvisor::testing::runInotifyInit();
::gvisor::testing::runInotifyInit1();
::gvisor::testing::runInotifyAddWatch();
::gvisor::testing::runInotifyRmWatch();
// signalfd(2), fork(2), and vfork(2) system calls are not supported in arm
// architecture.
#ifdef __x86_64__
::gvisor::testing::runSignalfd();
::gvisor::testing::runFork();
::gvisor::testing::runVfork();
#endif
// Run chroot at the end since it changes the root for all other tests.
::gvisor::testing::runChroot();
return 0;