From 536a924f1abc556a6f905855059cca7f7d511be5 Mon Sep 17 00:00:00 2001 From: Shambhavi Srivastava Date: Fri, 18 Nov 2022 11:45:57 -0800 Subject: [PATCH] Adding more trace point integration tests for the following syscalls: - chroot - dup - dup2 - dup3 - prlimit64 - eventfd - eventfd2 - bind - accept - accept4 Updates #4805 PiperOrigin-RevId: 489526376 --- test/trace/trace_test.go | 127 +++++++++++++++++-- test/trace/workload/BUILD | 1 + test/trace/workload/workload.cc | 208 ++++++++++++++++++++++++++++++++ test/util/eventfd_util.h | 7 +- 4 files changed, 335 insertions(+), 8 deletions(-) diff --git a/test/trace/trace_test.go b/test/trace/trace_test.go index 601960b82..54ba184a7 100644 --- a/test/trace/trace_test.go +++ b/test/trace/trace_test.go @@ -75,7 +75,7 @@ func TestAll(t *testing.T) { cutoffTime = time.Now() cmd := exec.Command( runsc, - "--debug", "--strace", "--alsologtostderr", // Debug logging for troubleshooting + "--debug", "--alsologtostderr", // Debug logging for troubleshooting "--rootless", "--network=none", "--TESTONLY-unsafe-nonroot", // Disable features that we don't care "--pod-init-config", cfgFile.Name(), "do", workload) @@ -112,14 +112,16 @@ func matchPoints(t *testing.T, msgs []test.Message) { pb.MessageType_MESSAGE_SYSCALL_CHDIR: {checker: checkSyscallChdir}, pb.MessageType_MESSAGE_SYSCALL_SETID: {checker: checkSyscallSetid}, pb.MessageType_MESSAGE_SYSCALL_SETRESID: {checker: checkSyscallSetresid}, + pb.MessageType_MESSAGE_SYSCALL_CHROOT: {checker: checkSyscallChroot}, + 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_BIND: {checker: checkSyscallBind}, + pb.MessageType_MESSAGE_SYSCALL_ACCEPT: {checker: checkSyscallAccept}, // TODO(gvisor.dev/issue/4805): Add validation for these messages. - pb.MessageType_MESSAGE_SYSCALL_ACCEPT: {checker: checkTODO}, - pb.MessageType_MESSAGE_SYSCALL_BIND: {checker: checkTODO}, - pb.MessageType_MESSAGE_SYSCALL_CLONE: {checker: checkTODO}, - pb.MessageType_MESSAGE_SYSCALL_DUP: {checker: checkTODO}, - pb.MessageType_MESSAGE_SYSCALL_PIPE: {checker: checkTODO}, - pb.MessageType_MESSAGE_SYSCALL_PRLIMIT64: {checker: checkTODO}, + pb.MessageType_MESSAGE_SYSCALL_CLONE: {checker: checkTODO}, + pb.MessageType_MESSAGE_SYSCALL_PIPE: {checker: checkTODO}, } for _, msg := range msgs { t.Logf("Processing message type %v", msg.MsgType) @@ -540,6 +542,117 @@ func checkSyscallChdir(msg test.Message) error { return nil } +func checkSyscallDup(msg test.Message) error { + p := pb.Dup{} + if err := proto.Unmarshal(msg.Msg, &p); err != nil { + return err + } + if err := checkContextData(p.ContextData); err != nil { + return err + } + if p.OldFd < 0 { + return fmt.Errorf("invalid FD: %d", p.OldFd) + } + if p.NewFd < 0 { + 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) + } + + return nil +} + +func checkSyscallPrlimit64(msg test.Message) error { + p := pb.Prlimit{} + if err := proto.Unmarshal(msg.Msg, &p); err != nil { + return err + } + if err := checkContextData(p.ContextData); err != nil { + return err + } + if p.Pid < 0 { + return fmt.Errorf("invalid PID: %d", p.Pid) + } + return nil +} + +func checkSyscallEventfd(msg test.Message) error { + p := pb.Eventfd{} + if err := proto.Unmarshal(msg.Msg, &p); err != nil { + return err + } + if err := checkContextData(p.ContextData); err != nil { + return err + } + if p.Val < 0 { + 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 nil +} + +func checkSyscallBind(msg test.Message) error { + p := pb.Bind{} + 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 len(p.Address) == 0 { + return fmt.Errorf("invalid address: %d", p.Address) + } + return nil +} + +func checkSyscallAccept(msg test.Message) error { + p := pb.Accept{} + 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 len(p.Address) != 0 { + return fmt.Errorf("invalid address: %d, %v", p.Address, p.Sysno) + } + if p.Flags != 0 && p.Flags != unix.SOCK_CLOEXEC { + return fmt.Errorf("invalid flag got: %d", p.Flags) + } + return nil +} + +func checkSyscallChroot(msg test.Message) error { + p := pb.Chroot{} + if err := proto.Unmarshal(msg.Msg, &p); err != nil { + return err + } + if err := checkContextData(p.ContextData); err != nil { + 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 nil +} + func checkTODO(_ test.Message) error { return nil } diff --git a/test/trace/workload/BUILD b/test/trace/workload/BUILD index 7391ac2c8..2f0c6b28e 100644 --- a/test/trace/workload/BUILD +++ b/test/trace/workload/BUILD @@ -10,6 +10,7 @@ cc_binary( ], visibility = ["//test/trace:__pkg__"], deps = [ + "//test/util:eventfd_util", "//test/util:file_descriptor", "//test/util:multiprocess_util", "//test/util:posix_error", diff --git a/test/trace/workload/workload.cc b/test/trace/workload/workload.cc index d8f51f564..0fb294044 100644 --- a/test/trace/workload/workload.cc +++ b/test/trace/workload/workload.cc @@ -14,18 +14,22 @@ #include #include +#include +#include #include #include #include #include #include +#include #include #include #include "absl/cleanup/cleanup.h" #include "absl/strings/str_cat.h" #include "absl/time/clock.h" +#include "test/util/eventfd_util.h" #include "test/util/file_descriptor.h" #include "test/util/multiprocess_util.h" #include "test/util/posix_error.h" @@ -261,6 +265,199 @@ void runSetresgid() { } } +void runChroot() { + 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"); + } + if (chroot(pathname)) { + err(1, "chroot"); + } +} +void runDup() { + 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"); + } + int res = dup(fd); + if (res < 0) { + err(1, "dup"); + } + rmdir(pathname); +} + +void runDup2() { + 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 oldfd = open(pathname, O_DIRECTORY | O_RDONLY); + if (oldfd < 0) { + err(1, "open"); + } + int newfd = open(pathname, O_DIRECTORY | O_RDONLY); + if (newfd < 0) { + err(1, "open"); + } + int res = dup2(oldfd, newfd); + if (res != newfd) { + err(1, "dup2"); + } + rmdir(pathname); +} + +void runDup3() { + 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 oldfd = open(pathname, O_DIRECTORY | O_RDONLY); + if (oldfd < 0) { + err(1, "open"); + } + int newfd = open(pathname, O_DIRECTORY | O_RDONLY); + if (newfd < 0) { + err(1, "open"); + } + int res = dup3(oldfd, newfd, O_CLOEXEC); + if (res != newfd) { + err(1, "dup3"); + } + rmdir(pathname); +} + +void runPrlimit64() { + struct rlimit setlim; + setlim.rlim_cur = 0; + setlim.rlim_max = RLIM_INFINITY; + int res = prlimit(0, RLIMIT_DATA, &setlim, nullptr); + if (res != 0) { + err(1, "prlimit64"); + } +} + +void runEventfd() { + int res = eventfd(0, EFD_NONBLOCK); + if (res < 0) { + err(1, "eventfd"); + } +} + +void runEventfd2() { + int res = Eventdfd2Setup(0, EFD_NONBLOCK); + if (res < 0) { + err(1, "eventfd2"); + } +} + +void runBind() { + auto path = absl::StrCat(std::string("\0", 1), "trace_test.abc"); + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path.c_str(), path.size() + 1); + + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + err(1, "socket"); + } + auto sock_closer = absl::MakeCleanup([fd] { close(fd); }); + + if (bind(fd, reinterpret_cast(&addr), sizeof(addr))) { + err(1, "bind"); + } +} + +void runAccept() { + auto path = absl::StrCat(std::string("\0", 1), "trace_test.abc"); + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path.c_str(), path.size() + 1); + + int server = socket(AF_UNIX, SOCK_STREAM, 0); + if (server < 0) { + err(1, "socket"); + } + auto sock_closer = absl::MakeCleanup([server] { close(server); }); + + if (bind(server, reinterpret_cast(&addr), sizeof(addr)) < 0) { + err(1, "bind"); + } + + if (listen(server, 5) < 0) { + err(1, "listen"); + } + + int client = socket(AF_UNIX, SOCK_STREAM, 0); + if (client < 0) { + err(1, "socket"); + } + auto client_closer = absl::MakeCleanup([client] { close(client); }); + + if (connect(client, reinterpret_cast(&addr), sizeof(addr)) < + 0) { + err(1, "connect"); + } + + int fd = RetryEINTR(accept)(server, nullptr, nullptr); + if (fd < 0) { + err(1, "accept"); + } + close(fd); +} + +void runAccept4() { + auto path = absl::StrCat(std::string("\0", 1), "trace_test.abc"); + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path.c_str(), path.size() + 1); + + int server = socket(AF_UNIX, SOCK_STREAM, 0); + if (server < 0) { + err(1, "socket"); + } + auto sock_closer = absl::MakeCleanup([server] { close(server); }); + + if (bind(server, reinterpret_cast(&addr), sizeof(addr)) < 0) { + err(1, "bind"); + } + + if (listen(server, 5) < 0) { + err(1, "listen"); + } + + int client = socket(AF_UNIX, SOCK_STREAM, 0); + if (client < 0) { + err(1, "socket"); + } + auto client_closer = absl::MakeCleanup([client] { close(client); }); + + if (connect(client, reinterpret_cast(&addr), sizeof(addr)) < + 0) { + err(1, "connect"); + } + + int fd = RetryEINTR(accept4)(server, nullptr, nullptr, SOCK_CLOEXEC); + if (fd < 0) { + err(1, "accept4"); + } + close(fd); +} + } // namespace testing } // namespace gvisor @@ -275,5 +472,16 @@ int main(int argc, char** argv) { ::gvisor::testing::runSetsid(); ::gvisor::testing::runSetresuid(); ::gvisor::testing::runSetresgid(); + ::gvisor::testing::runDup(); + ::gvisor::testing::runDup2(); + ::gvisor::testing::runDup3(); + ::gvisor::testing::runPrlimit64(); + ::gvisor::testing::runEventfd(); + ::gvisor::testing::runEventfd2(); + ::gvisor::testing::runBind(); + ::gvisor::testing::runAccept(); + ::gvisor::testing::runAccept4(); + // Run chroot at the end since it changes the root for all other tests. + ::gvisor::testing::runChroot(); return 0; } diff --git a/test/util/eventfd_util.h b/test/util/eventfd_util.h index cb9ce829c..261ccc7a0 100644 --- a/test/util/eventfd_util.h +++ b/test/util/eventfd_util.h @@ -14,7 +14,7 @@ #ifndef GVISOR_TEST_UTIL_EVENTFD_UTIL_H_ #define GVISOR_TEST_UTIL_EVENTFD_UTIL_H_ - +#include #include #include @@ -37,6 +37,11 @@ inline PosixErrorOr NewEventFD(unsigned int initval = 0, return FileDescriptor(fd); } +// This is a wrapper for the eventfd2(2) system call. +inline int Eventdfd2Setup(unsigned int initval, int flags) { + return syscall(__NR_eventfd2, initval, flags); +} + } // namespace testing } // namespace gvisor