summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/packetimpact/runner/defs.bzl6
-rw-r--r--test/packetimpact/runner/packetimpact_test.go8
-rw-r--r--test/packetimpact/tests/BUILD12
-rw-r--r--test/packetimpact/tests/tcp_queue_receive_in_syn_sent_test.go131
-rw-r--r--test/packetimpact/tests/tcp_splitseg_mss_test.go71
-rw-r--r--test/packetimpact/tests/tcp_zero_window_probe_retransmit_test.go4
-rw-r--r--test/syscalls/BUILD5
-rw-r--r--test/syscalls/linux/BUILD5
-rw-r--r--test/syscalls/linux/fallocate.cc45
-rw-r--r--test/syscalls/linux/fcntl.cc60
-rw-r--r--test/syscalls/linux/pwritev2.cc59
-rw-r--r--test/syscalls/linux/socket_netlink_route.cc2
-rw-r--r--test/syscalls/linux/sticky.cc77
-rw-r--r--test/util/test_util.cc11
-rw-r--r--test/util/test_util.h3
15 files changed, 278 insertions, 221 deletions
diff --git a/test/packetimpact/runner/defs.bzl b/test/packetimpact/runner/defs.bzl
index ea66b9756..77cdfea12 100644
--- a/test/packetimpact/runner/defs.bzl
+++ b/test/packetimpact/runner/defs.bzl
@@ -20,12 +20,12 @@ def _packetimpact_test_impl(ctx):
])
ctx.actions.write(bench, bench_content, is_executable = True)
- transitive_files = depset()
+ transitive_files = []
if hasattr(ctx.attr._test_runner, "data_runfiles"):
- transitive_files = depset(ctx.attr._test_runner.data_runfiles.files)
+ transitive_files.append(ctx.attr._test_runner.data_runfiles.files)
runfiles = ctx.runfiles(
files = [test_runner] + ctx.files.testbench_binary + ctx.files._posix_server_binary,
- transitive_files = transitive_files,
+ transitive_files = depset(transitive = transitive_files),
collect_default = True,
collect_data = True,
)
diff --git a/test/packetimpact/runner/packetimpact_test.go b/test/packetimpact/runner/packetimpact_test.go
index 3cac5915f..c0a2620de 100644
--- a/test/packetimpact/runner/packetimpact_test.go
+++ b/test/packetimpact/runner/packetimpact_test.go
@@ -242,7 +242,13 @@ func TestOne(t *testing.T) {
}
// Kill so that it will flush output.
- defer testbench.Exec(dockerutil.RunOpts{}, "killall", snifferArgs[0])
+ defer func() {
+ // Wait 1 second before killing tcpdump to give it time to flush
+ // any packets. On linux tests killing it immediately can
+ // sometimes result in partial pcaps.
+ time.Sleep(1 * time.Second)
+ testbench.Exec(dockerutil.RunOpts{}, "killall", snifferArgs[0])
+ }()
if _, err := testbench.WaitForOutput(snifferRegex, 60*time.Second); err != nil {
t.Fatalf("sniffer on %s never listened: %s", dut.Name, err)
diff --git a/test/packetimpact/tests/BUILD b/test/packetimpact/tests/BUILD
index 1c9f59df5..85749c559 100644
--- a/test/packetimpact/tests/BUILD
+++ b/test/packetimpact/tests/BUILD
@@ -183,8 +183,6 @@ packetimpact_go_test(
packetimpact_go_test(
name = "tcp_queue_receive_in_syn_sent",
srcs = ["tcp_queue_receive_in_syn_sent_test.go"],
- # TODO(b/157658105): Fix netstack then remove the line below.
- expect_netstack_failure = True,
deps = [
"//pkg/tcpip/header",
"//test/packetimpact/testbench",
@@ -213,16 +211,6 @@ packetimpact_go_test(
)
packetimpact_go_test(
- name = "tcp_splitseg_mss",
- srcs = ["tcp_splitseg_mss_test.go"],
- deps = [
- "//pkg/tcpip/header",
- "//test/packetimpact/testbench",
- "@org_golang_x_sys//unix:go_default_library",
- ],
-)
-
-packetimpact_go_test(
name = "tcp_cork_mss",
srcs = ["tcp_cork_mss_test.go"],
deps = [
diff --git a/test/packetimpact/tests/tcp_queue_receive_in_syn_sent_test.go b/test/packetimpact/tests/tcp_queue_receive_in_syn_sent_test.go
index b640d8673..8fbec893b 100644
--- a/test/packetimpact/tests/tcp_queue_receive_in_syn_sent_test.go
+++ b/test/packetimpact/tests/tcp_queue_receive_in_syn_sent_test.go
@@ -35,53 +35,98 @@ func init() {
testbench.RegisterFlags(flag.CommandLine)
}
+// TestQueueReceiveInSynSent tests receive behavior when the TCP state
+// is SYN-SENT.
+// It tests for 2 variants where the receive is blocked and:
+// (1) we complete handshake and send sample data.
+// (2) we send a TCP RST.
func TestQueueReceiveInSynSent(t *testing.T) {
- dut := testbench.NewDUT(t)
- defer dut.TearDown()
+ for _, tt := range []struct {
+ description string
+ reset bool
+ }{
+ {description: "Send DATA", reset: false},
+ {description: "Send RST", reset: true},
+ } {
+ t.Run(tt.description, func(t *testing.T) {
+ dut := testbench.NewDUT(t)
+ defer dut.TearDown()
- socket, remotePort := dut.CreateBoundSocket(unix.SOCK_STREAM, unix.IPPROTO_TCP, net.ParseIP(testbench.RemoteIPv4))
- conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
- defer conn.Close()
+ socket, remotePort := dut.CreateBoundSocket(unix.SOCK_STREAM, unix.IPPROTO_TCP, net.ParseIP(testbench.RemoteIPv4))
+ conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
+ defer conn.Close()
- sampleData := []byte("Sample Data")
+ sampleData := []byte("Sample Data")
- dut.SetNonBlocking(socket, true)
- if _, err := dut.ConnectWithErrno(context.Background(), socket, conn.LocalAddr()); !errors.Is(err, syscall.EINPROGRESS) {
- t.Fatalf("failed to bring DUT to SYN-SENT, got: %s, want EINPROGRESS", err)
- }
- if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)}, time.Second); err != nil {
- t.Fatalf("expected a SYN from DUT, but got none: %s", err)
- }
+ dut.SetNonBlocking(socket, true)
+ if _, err := dut.ConnectWithErrno(context.Background(), socket, conn.LocalAddr()); !errors.Is(err, syscall.EINPROGRESS) {
+ t.Fatalf("failed to bring DUT to SYN-SENT, got: %s, want EINPROGRESS", err)
+ }
+ if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)}, time.Second); err != nil {
+ t.Fatalf("expected a SYN from DUT, but got none: %s", err)
+ }
- // Issue RECEIVE call in SYN-SENT, this should be queued for process until the connection
- // is established.
- dut.SetNonBlocking(socket, false)
- var wg sync.WaitGroup
- defer wg.Wait()
- wg.Add(1)
- go func() {
- defer wg.Done()
- ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
- defer cancel()
- n, buff, err := dut.RecvWithErrno(ctx, socket, int32(len(sampleData)), 0)
- if n == -1 {
- t.Fatalf("failed to recv on DUT: %s", err)
- }
- if got := buff[:n]; !bytes.Equal(got, sampleData) {
- t.Fatalf("received data don't match, got:\n%s, want:\n%s", hex.Dump(got), hex.Dump(sampleData))
- }
- }()
-
- // The following sleep is used to prevent the connection from being established while the
- // RPC is in flight.
- time.Sleep(time.Second)
-
- // Bring the connection to Established.
- conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)})
- if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second); err != nil {
- t.Fatalf("expected an ACK from DUT, but got none: %s", err)
- }
+ if _, _, err := dut.RecvWithErrno(context.Background(), socket, int32(len(sampleData)), 0); err != syscall.Errno(unix.EWOULDBLOCK) {
+ t.Fatalf("expected error %s, got %s", syscall.Errno(unix.EWOULDBLOCK), err)
+ }
+
+ // Test blocking read.
+ dut.SetNonBlocking(socket, false)
+
+ var wg sync.WaitGroup
+ defer wg.Wait()
+ wg.Add(1)
+ var block sync.WaitGroup
+ block.Add(1)
+ go func() {
+ defer wg.Done()
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
+ defer cancel()
- // Send sample data to DUT.
- conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &testbench.Payload{Bytes: sampleData})
+ block.Done()
+ // Issue RECEIVE call in SYN-SENT, this should be queued for
+ // process until the connection is established.
+ n, buff, err := dut.RecvWithErrno(ctx, socket, int32(len(sampleData)), 0)
+ if tt.reset {
+ if err != syscall.Errno(unix.ECONNREFUSED) {
+ t.Errorf("expected error %s, got %s", syscall.Errno(unix.ECONNREFUSED), err)
+ }
+ if n != -1 {
+ t.Errorf("expected return value %d, got %d", -1, n)
+ }
+ return
+ }
+ if n == -1 {
+ t.Errorf("failed to recv on DUT: %s", err)
+ }
+ if got := buff[:n]; !bytes.Equal(got, sampleData) {
+ t.Errorf("received data doesn't match, got:\n%s, want:\n%s", hex.Dump(got), hex.Dump(sampleData))
+ }
+ }()
+
+ // Wait for the goroutine to be scheduled and before it
+ // blocks on endpoint receive.
+ block.Wait()
+ // The following sleep is used to prevent the connection
+ // from being established before we are blocked on Recv.
+ time.Sleep(100 * time.Millisecond)
+
+ if tt.reset {
+ conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst | header.TCPFlagAck)})
+ return
+ }
+
+ // Bring the connection to Established.
+ conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)})
+ if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second); err != nil {
+ t.Fatalf("expected an ACK from DUT, but got none: %s", err)
+ }
+
+ // Send sample payload and expect an ACK.
+ conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &testbench.Payload{Bytes: sampleData})
+ if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second); err != nil {
+ t.Fatalf("expected an ACK from DUT, but got none: %s", err)
+ }
+ })
+ }
}
diff --git a/test/packetimpact/tests/tcp_splitseg_mss_test.go b/test/packetimpact/tests/tcp_splitseg_mss_test.go
deleted file mode 100644
index 9350d0988..000000000
--- a/test/packetimpact/tests/tcp_splitseg_mss_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2020 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.
-
-package tcp_splitseg_mss_test
-
-import (
- "flag"
- "testing"
- "time"
-
- "golang.org/x/sys/unix"
- "gvisor.dev/gvisor/pkg/tcpip/header"
- "gvisor.dev/gvisor/test/packetimpact/testbench"
-)
-
-func init() {
- testbench.RegisterFlags(flag.CommandLine)
-}
-
-// TestTCPSplitSegMSS lets the dut try to send segments larger than MSS.
-// It tests if the transmitted segments are capped at MSS and are split.
-func TestTCPSplitSegMSS(t *testing.T) {
- dut := testbench.NewDUT(t)
- defer dut.TearDown()
- listenFD, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
- defer dut.Close(listenFD)
- conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
- defer conn.Close()
-
- const mss = uint32(header.TCPDefaultMSS)
- options := make([]byte, header.TCPOptionMSSLength)
- header.EncodeMSSOption(mss, options)
- conn.ConnectWithOptions(options)
-
- acceptFD, _ := dut.Accept(listenFD)
- defer dut.Close(acceptFD)
-
- // Let the dut send a segment larger than MSS.
- largeData := make([]byte, mss+1)
- for i := 0; i < 2; i++ {
- dut.Send(acceptFD, largeData, 0)
- if i == 0 {
- // On Linux, the initial segment goes out beyond MSS and the segment
- // split occurs on retransmission. Call ExpectData to wait to
- // receive the split segment.
- if _, err := conn.ExpectData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &testbench.Payload{Bytes: largeData[:mss]}, time.Second); err != nil {
- t.Fatalf("expected payload was not received: %s", err)
- }
- } else {
- if _, err := conn.ExpectNextData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &testbench.Payload{Bytes: largeData[:mss]}, time.Second); err != nil {
- t.Fatalf("expected payload was not received: %s", err)
- }
- }
- conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
- if _, err := conn.ExpectNextData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh)}, &testbench.Payload{Bytes: largeData[mss:]}, time.Second); err != nil {
- t.Fatalf("expected payload was not received: %s", err)
- }
- conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
- }
-}
diff --git a/test/packetimpact/tests/tcp_zero_window_probe_retransmit_test.go b/test/packetimpact/tests/tcp_zero_window_probe_retransmit_test.go
index 5ab193181..8c89d57c9 100644
--- a/test/packetimpact/tests/tcp_zero_window_probe_retransmit_test.go
+++ b/test/packetimpact/tests/tcp_zero_window_probe_retransmit_test.go
@@ -88,8 +88,8 @@ func TestZeroWindowProbeRetransmit(t *testing.T) {
continue
}
// Check if the probes came at exponentially increasing intervals.
- if p := time.Since(start); p < current-startProbeDuration {
- t.Fatalf("zero probe came sooner interval %d probe %d\n", p, i)
+ if got, want := time.Since(start), current-startProbeDuration; got < want {
+ t.Errorf("got zero probe %d after %s, want >= %s", i, got, want)
}
// Acknowledge the zero-window probes from the dut.
conn.Send(testbench.TCP{AckNum: ackProbe, Flags: testbench.Uint8(header.TCPFlagAck), WindowSize: testbench.Uint16(0)})
diff --git a/test/syscalls/BUILD b/test/syscalls/BUILD
index 36c178e4a..7c4cd8192 100644
--- a/test/syscalls/BUILD
+++ b/test/syscalls/BUILD
@@ -199,6 +199,7 @@ syscall_test(
syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:fallocate_test",
+ vfs2 = "True",
)
syscall_test(
@@ -288,6 +289,7 @@ syscall_test(
size = "medium",
add_overlay = True,
test = "//test/syscalls/linux:ioctl_test",
+ vfs2 = "True",
)
syscall_test(
@@ -355,6 +357,7 @@ syscall_test(
size = "medium",
shard_count = 5,
test = "//test/syscalls/linux:mmap_test",
+ vfs2 = "True",
)
syscall_test(
@@ -528,6 +531,7 @@ syscall_test(
syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:pwritev2_test",
+ vfs2 = "True",
)
syscall_test(
@@ -960,6 +964,7 @@ syscall_test(
syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:sync_file_range_test",
+ vfs2 = "True",
)
syscall_test(
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 8c7d54b21..9e097c888 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -748,9 +748,14 @@ cc_binary(
linkstatic = 1,
deps = [
":file_base",
+ ":socket_test_util",
"//test/util:cleanup",
+ "//test/util:eventfd_util",
"//test/util:file_descriptor",
+ "@com_google_absl//absl/strings",
+ "@com_google_absl//absl/time",
gtest,
+ "//test/util:posix_error",
"//test/util:temp_path",
"//test/util:test_main",
"//test/util:test_util",
diff --git a/test/syscalls/linux/fallocate.cc b/test/syscalls/linux/fallocate.cc
index 7819f4ac3..cabc2b751 100644
--- a/test/syscalls/linux/fallocate.cc
+++ b/test/syscalls/linux/fallocate.cc
@@ -15,16 +15,27 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
+#include <sys/eventfd.h>
#include <sys/resource.h>
+#include <sys/signalfd.h>
+#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/timerfd.h>
#include <syscall.h>
#include <time.h>
#include <unistd.h>
+#include <ctime>
+
#include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
+#include "absl/time/time.h"
#include "test/syscalls/linux/file_base.h"
+#include "test/syscalls/linux/socket_test_util.h"
#include "test/util/cleanup.h"
+#include "test/util/eventfd_util.h"
#include "test/util/file_descriptor.h"
+#include "test/util/posix_error.h"
#include "test/util/temp_path.h"
#include "test/util/test_util.h"
@@ -70,6 +81,12 @@ TEST_F(AllocateTest, Fallocate) {
ASSERT_THAT(fallocate(test_file_fd_.get(), 0, 39, 1), SyscallSucceeds());
ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds());
EXPECT_EQ(buf.st_size, 40);
+
+ // Given length 0 should fail with EINVAL.
+ ASSERT_THAT(fallocate(test_file_fd_.get(), 0, 50, 0),
+ SyscallFailsWithErrno(EINVAL));
+ ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds());
+ EXPECT_EQ(buf.st_size, 40);
}
TEST_F(AllocateTest, FallocateInvalid) {
@@ -136,6 +153,34 @@ TEST_F(AllocateTest, FallocateRlimit) {
ASSERT_THAT(sigprocmask(SIG_UNBLOCK, &new_mask, nullptr), SyscallSucceeds());
}
+TEST_F(AllocateTest, FallocateOtherFDs) {
+ int fd;
+ ASSERT_THAT(fd = timerfd_create(CLOCK_MONOTONIC, 0), SyscallSucceeds());
+ auto timer_fd = FileDescriptor(fd);
+ EXPECT_THAT(fallocate(timer_fd.get(), 0, 0, 10),
+ SyscallFailsWithErrno(ENODEV));
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ ASSERT_THAT(fd = signalfd(-1, &mask, 0), SyscallSucceeds());
+ auto sfd = FileDescriptor(fd);
+ EXPECT_THAT(fallocate(sfd.get(), 0, 0, 10), SyscallFailsWithErrno(ENODEV));
+
+ auto efd =
+ ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
+ EXPECT_THAT(fallocate(efd.get(), 0, 0, 10), SyscallFailsWithErrno(ENODEV));
+
+ auto sockfd = ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0));
+ EXPECT_THAT(fallocate(sockfd.get(), 0, 0, 10), SyscallFailsWithErrno(ENODEV));
+
+ int socks[2];
+ ASSERT_THAT(socketpair(AF_UNIX, SOCK_STREAM, PF_UNIX, socks),
+ SyscallSucceeds());
+ auto sock0 = FileDescriptor(socks[0]);
+ auto sock1 = FileDescriptor(socks[1]);
+ EXPECT_THAT(fallocate(sock0.get(), 0, 0, 10), SyscallFailsWithErrno(ENODEV));
+}
+
} // namespace
} // namespace testing
} // namespace gvisor
diff --git a/test/syscalls/linux/fcntl.cc b/test/syscalls/linux/fcntl.cc
index 9130618fa..5467fa2c8 100644
--- a/test/syscalls/linux/fcntl.cc
+++ b/test/syscalls/linux/fcntl.cc
@@ -18,7 +18,10 @@
#include <syscall.h>
#include <unistd.h>
+#include <iostream>
+#include <list>
#include <string>
+#include <vector>
#include "gtest/gtest.h"
#include "absl/base/macros.h"
@@ -1028,6 +1031,30 @@ TEST(FcntlTest, SetOwnPgrp) {
MaybeSave();
}
+TEST(FcntlTest, SetOwnUnset) {
+ FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
+ Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
+
+ // Set and unset pid.
+ pid_t pid;
+ EXPECT_THAT(pid = getpid(), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, pid), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, 0), SyscallSucceeds());
+
+ EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
+ SyscallSucceedsWithValue(0));
+
+ // Set and unset pgid.
+ pid_t pgid;
+ EXPECT_THAT(pgid = getpgrp(), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, -pgid), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, 0), SyscallSucceeds());
+
+ EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
+ SyscallSucceedsWithValue(0));
+ MaybeSave();
+}
+
// F_SETOWN flips the sign of negative values, an operation that is guarded
// against overflow.
TEST(FcntlTest, SetOwnOverflow) {
@@ -1138,6 +1165,39 @@ TEST(FcntlTest, SetOwnExPgrp) {
MaybeSave();
}
+TEST(FcntlTest, SetOwnExUnset) {
+ SKIP_IF(IsRunningWithVFS1());
+
+ FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
+ Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
+
+ // Set and unset pid.
+ f_owner_ex owner = {};
+ owner.type = F_OWNER_PID;
+ EXPECT_THAT(owner.pid = getpid(), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
+ SyscallSucceeds());
+ owner.pid = 0;
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
+ SyscallSucceeds());
+
+ EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
+ SyscallSucceedsWithValue(0));
+
+ // Set and unset pgid.
+ owner.type = F_OWNER_PGRP;
+ EXPECT_THAT(owner.pid = getpgrp(), SyscallSucceeds());
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
+ SyscallSucceeds());
+ owner.pid = 0;
+ ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
+ SyscallSucceeds());
+
+ EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
+ SyscallSucceedsWithValue(0));
+ MaybeSave();
+}
+
TEST(FcntlTest, GetOwnExTid) {
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
diff --git a/test/syscalls/linux/pwritev2.cc b/test/syscalls/linux/pwritev2.cc
index 3fe5a600f..63b686c62 100644
--- a/test/syscalls/linux/pwritev2.cc
+++ b/test/syscalls/linux/pwritev2.cc
@@ -69,7 +69,7 @@ ssize_t pwritev2(unsigned long fd, const struct iovec* iov,
}
// This test is the base case where we call pwritev (no offset, no flags).
-TEST(Writev2Test, TestBaseCall) {
+TEST(Writev2Test, BaseCall) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
@@ -97,7 +97,7 @@ TEST(Writev2Test, TestBaseCall) {
}
// This test is where we call pwritev2 with a positive offset and no flags.
-TEST(Pwritev2Test, TestValidPositiveOffset) {
+TEST(Pwritev2Test, ValidPositiveOffset) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
std::string prefix(kBufSize, '0');
@@ -129,7 +129,7 @@ TEST(Pwritev2Test, TestValidPositiveOffset) {
// This test is the base case where we call writev by using -1 as the offset.
// The write should use the file offset, so the test increments the file offset
// prior to call pwritev2.
-TEST(Pwritev2Test, TestNegativeOneOffset) {
+TEST(Pwritev2Test, NegativeOneOffset) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
const std::string prefix = "00";
@@ -164,7 +164,7 @@ TEST(Pwritev2Test, TestNegativeOneOffset) {
// pwritev2 requires if the RWF_HIPRI flag is passed, the fd must be opened with
// O_DIRECT. This test implements a correct call with the RWF_HIPRI flag.
-TEST(Pwritev2Test, TestCallWithRWF_HIPRI) {
+TEST(Pwritev2Test, CallWithRWF_HIPRI) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
@@ -189,47 +189,8 @@ TEST(Pwritev2Test, TestCallWithRWF_HIPRI) {
EXPECT_EQ(buf, content);
}
-// This test checks that pwritev2 can be called with valid flags
-TEST(Pwritev2Test, TestCallWithValidFlags) {
- SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
-
- const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
- GetAbsoluteTestTmpdir(), "", TempPath::kDefaultFileMode));
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR));
-
- std::vector<char> content(kBufSize, '0');
- struct iovec iov;
- iov.iov_base = content.data();
- iov.iov_len = content.size();
-
- EXPECT_THAT(pwritev2(fd.get(), &iov, /*iovcnt=*/1,
- /*offset=*/0, /*flags=*/RWF_DSYNC),
- SyscallSucceedsWithValue(kBufSize));
-
- std::vector<char> buf(content.size());
- EXPECT_THAT(read(fd.get(), buf.data(), buf.size()),
- SyscallSucceedsWithValue(buf.size()));
-
- EXPECT_EQ(buf, content);
-
- SetContent(content);
-
- EXPECT_THAT(pwritev2(fd.get(), &iov, /*iovcnt=*/1,
- /*offset=*/0, /*flags=*/0x4),
- SyscallSucceedsWithValue(kBufSize));
-
- ASSERT_THAT(lseek(fd.get(), 0, SEEK_CUR),
- SyscallSucceedsWithValue(content.size()));
-
- EXPECT_THAT(pread(fd.get(), buf.data(), buf.size(), /*offset=*/0),
- SyscallSucceedsWithValue(buf.size()));
-
- EXPECT_EQ(buf, content);
-}
-
// This test calls pwritev2 with a bad file descriptor.
-TEST(Writev2Test, TestBadFile) {
+TEST(Writev2Test, BadFile) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
ASSERT_THAT(pwritev2(/*fd=*/-1, /*iov=*/nullptr, /*iovcnt=*/0,
/*offset=*/0, /*flags=*/0),
@@ -237,7 +198,7 @@ TEST(Writev2Test, TestBadFile) {
}
// This test calls pwrite2 with an invalid offset.
-TEST(Pwritev2Test, TestInvalidOffset) {
+TEST(Pwritev2Test, InvalidOffset) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
@@ -255,7 +216,7 @@ TEST(Pwritev2Test, TestInvalidOffset) {
SyscallFailsWithErrno(EINVAL));
}
-TEST(Pwritev2Test, TestUnseekableFileValid) {
+TEST(Pwritev2Test, UnseekableFileValid) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
int pipe_fds[2];
@@ -285,7 +246,7 @@ TEST(Pwritev2Test, TestUnseekableFileValid) {
// Calling pwritev2 with a non-negative offset calls pwritev. Calling pwritev
// with an unseekable file is not allowed. A pipe is used for an unseekable
// file.
-TEST(Pwritev2Test, TestUnseekableFileInValid) {
+TEST(Pwritev2Test, UnseekableFileInvalid) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
int pipe_fds[2];
@@ -304,7 +265,7 @@ TEST(Pwritev2Test, TestUnseekableFileInValid) {
EXPECT_THAT(close(pipe_fds[1]), SyscallSucceeds());
}
-TEST(Pwritev2Test, TestReadOnlyFile) {
+TEST(Pwritev2Test, ReadOnlyFile) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
@@ -323,7 +284,7 @@ TEST(Pwritev2Test, TestReadOnlyFile) {
}
// This test calls pwritev2 with an invalid flag.
-TEST(Pwritev2Test, TestInvalidFlag) {
+TEST(Pwritev2Test, InvalidFlag) {
SKIP_IF(pwritev2(-1, nullptr, 0, 0, 0) < 0 && errno == ENOSYS);
const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
diff --git a/test/syscalls/linux/socket_netlink_route.cc b/test/syscalls/linux/socket_netlink_route.cc
index fbe61c5a0..e6647a1c3 100644
--- a/test/syscalls/linux/socket_netlink_route.cc
+++ b/test/syscalls/linux/socket_netlink_route.cc
@@ -595,7 +595,7 @@ TEST(NetlinkRouteTest, GetRouteRequest) {
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
uint32_t port = ASSERT_NO_ERRNO_AND_VALUE(NetlinkPortID(fd.get()));
- struct __attribute__((__packed__)) request {
+ struct request {
struct nlmsghdr hdr;
struct rtmsg rtm;
struct nlattr nla;
diff --git a/test/syscalls/linux/sticky.cc b/test/syscalls/linux/sticky.cc
index 39f4fb801..4afed6d08 100644
--- a/test/syscalls/linux/sticky.cc
+++ b/test/syscalls/linux/sticky.cc
@@ -42,12 +42,15 @@ TEST(StickyTest, StickyBitPermDenied) {
const TempPath parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
EXPECT_THAT(chmod(parent.path().c_str(), 0777 | S_ISVTX), SyscallSucceeds());
- const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(
- TempPath::CreateFileWith(parent.path(), "some content", 0755));
- const TempPath dir =
- ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirWith(parent.path(), 0755));
- const TempPath link = ASSERT_NO_ERRNO_AND_VALUE(
- TempPath::CreateSymlinkTo(parent.path(), file.path()));
+
+ // After changing credentials below, we need to use an open fd to make
+ // modifications in the parent dir, because there is no guarantee that we will
+ // still have the ability to open it.
+ const FileDescriptor parent_fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open(parent.path(), O_DIRECTORY));
+ ASSERT_THAT(openat(parent_fd.get(), "file", O_CREAT), SyscallSucceeds());
+ ASSERT_THAT(mkdirat(parent_fd.get(), "dir", 0777), SyscallSucceeds());
+ ASSERT_THAT(symlinkat("xyz", parent_fd.get(), "link"), SyscallSucceeds());
// Drop privileges and change IDs only in child thread, or else this parent
// thread won't be able to open some log files after the test ends.
@@ -65,12 +68,14 @@ TEST(StickyTest, StickyBitPermDenied) {
syscall(SYS_setresuid, -1, absl::GetFlag(FLAGS_scratch_uid), -1),
SyscallSucceeds());
- std::string new_path = NewTempAbsPath();
- EXPECT_THAT(rename(file.path().c_str(), new_path.c_str()),
+ EXPECT_THAT(renameat(parent_fd.get(), "file", parent_fd.get(), "file2"),
+ SyscallFailsWithErrno(EPERM));
+ EXPECT_THAT(unlinkat(parent_fd.get(), "file", 0),
+ SyscallFailsWithErrno(EPERM));
+ EXPECT_THAT(unlinkat(parent_fd.get(), "dir", AT_REMOVEDIR),
+ SyscallFailsWithErrno(EPERM));
+ EXPECT_THAT(unlinkat(parent_fd.get(), "link", 0),
SyscallFailsWithErrno(EPERM));
- EXPECT_THAT(unlink(file.path().c_str()), SyscallFailsWithErrno(EPERM));
- EXPECT_THAT(rmdir(dir.path().c_str()), SyscallFailsWithErrno(EPERM));
- EXPECT_THAT(unlink(link.path().c_str()), SyscallFailsWithErrno(EPERM));
});
}
@@ -79,12 +84,15 @@ TEST(StickyTest, StickyBitSameUID) {
const TempPath parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
EXPECT_THAT(chmod(parent.path().c_str(), 0777 | S_ISVTX), SyscallSucceeds());
- const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(
- TempPath::CreateFileWith(parent.path(), "some content", 0755));
- const TempPath dir =
- ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirWith(parent.path(), 0755));
- const TempPath link = ASSERT_NO_ERRNO_AND_VALUE(
- TempPath::CreateSymlinkTo(parent.path(), file.path()));
+
+ // After changing credentials below, we need to use an open fd to make
+ // modifications in the parent dir, because there is no guarantee that we will
+ // still have the ability to open it.
+ const FileDescriptor parent_fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open(parent.path(), O_DIRECTORY));
+ ASSERT_THAT(openat(parent_fd.get(), "file", O_CREAT), SyscallSucceeds());
+ ASSERT_THAT(mkdirat(parent_fd.get(), "dir", 0777), SyscallSucceeds());
+ ASSERT_THAT(symlinkat("xyz", parent_fd.get(), "link"), SyscallSucceeds());
// Drop privileges and change IDs only in child thread, or else this parent
// thread won't be able to open some log files after the test ends.
@@ -100,12 +108,12 @@ TEST(StickyTest, StickyBitSameUID) {
SyscallSucceeds());
// We still have the same EUID.
- std::string new_path = NewTempAbsPath();
- EXPECT_THAT(rename(file.path().c_str(), new_path.c_str()),
+ EXPECT_THAT(renameat(parent_fd.get(), "file", parent_fd.get(), "file2"),
+ SyscallSucceeds());
+ EXPECT_THAT(unlinkat(parent_fd.get(), "file2", 0), SyscallSucceeds());
+ EXPECT_THAT(unlinkat(parent_fd.get(), "dir", AT_REMOVEDIR),
SyscallSucceeds());
- EXPECT_THAT(unlink(new_path.c_str()), SyscallSucceeds());
- EXPECT_THAT(rmdir(dir.path().c_str()), SyscallSucceeds());
- EXPECT_THAT(unlink(link.path().c_str()), SyscallSucceeds());
+ EXPECT_THAT(unlinkat(parent_fd.get(), "link", 0), SyscallSucceeds());
});
}
@@ -114,12 +122,15 @@ TEST(StickyTest, StickyBitCapFOWNER) {
const TempPath parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
EXPECT_THAT(chmod(parent.path().c_str(), 0777 | S_ISVTX), SyscallSucceeds());
- const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(
- TempPath::CreateFileWith(parent.path(), "some content", 0755));
- const TempPath dir =
- ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirWith(parent.path(), 0755));
- const TempPath link = ASSERT_NO_ERRNO_AND_VALUE(
- TempPath::CreateSymlinkTo(parent.path(), file.path()));
+
+ // After changing credentials below, we need to use an open fd to make
+ // modifications in the parent dir, because there is no guarantee that we will
+ // still have the ability to open it.
+ const FileDescriptor parent_fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open(parent.path(), O_DIRECTORY));
+ ASSERT_THAT(openat(parent_fd.get(), "file", O_CREAT), SyscallSucceeds());
+ ASSERT_THAT(mkdirat(parent_fd.get(), "dir", 0777), SyscallSucceeds());
+ ASSERT_THAT(symlinkat("xyz", parent_fd.get(), "link"), SyscallSucceeds());
// Drop privileges and change IDs only in child thread, or else this parent
// thread won't be able to open some log files after the test ends.
@@ -136,12 +147,12 @@ TEST(StickyTest, StickyBitCapFOWNER) {
SyscallSucceeds());
EXPECT_NO_ERRNO(SetCapability(CAP_FOWNER, true));
- std::string new_path = NewTempAbsPath();
- EXPECT_THAT(rename(file.path().c_str(), new_path.c_str()),
+ EXPECT_THAT(renameat(parent_fd.get(), "file", parent_fd.get(), "file2"),
+ SyscallSucceeds());
+ EXPECT_THAT(unlinkat(parent_fd.get(), "file2", 0), SyscallSucceeds());
+ EXPECT_THAT(unlinkat(parent_fd.get(), "dir", AT_REMOVEDIR),
SyscallSucceeds());
- EXPECT_THAT(unlink(new_path.c_str()), SyscallSucceeds());
- EXPECT_THAT(rmdir(dir.path().c_str()), SyscallSucceeds());
- EXPECT_THAT(unlink(link.path().c_str()), SyscallSucceeds());
+ EXPECT_THAT(unlinkat(parent_fd.get(), "link", 0), SyscallSucceeds());
});
}
} // namespace
diff --git a/test/util/test_util.cc b/test/util/test_util.cc
index b20758626..8a037f45f 100644
--- a/test/util/test_util.cc
+++ b/test/util/test_util.cc
@@ -40,15 +40,14 @@
namespace gvisor {
namespace testing {
-#define TEST_ON_GVISOR "TEST_ON_GVISOR"
-#define GVISOR_NETWORK "GVISOR_NETWORK"
-#define GVISOR_VFS "GVISOR_VFS"
+constexpr char kGvisorNetwork[] = "GVISOR_NETWORK";
+constexpr char kGvisorVfs[] = "GVISOR_VFS";
bool IsRunningOnGvisor() { return GvisorPlatform() != Platform::kNative; }
const std::string GvisorPlatform() {
// Set by runner.go.
- const char* env = getenv(TEST_ON_GVISOR);
+ const char* env = getenv(kTestOnGvisor);
if (!env) {
return Platform::kNative;
}
@@ -56,12 +55,12 @@ const std::string GvisorPlatform() {
}
bool IsRunningWithHostinet() {
- const char* env = getenv(GVISOR_NETWORK);
+ const char* env = getenv(kGvisorNetwork);
return env && strcmp(env, "host") == 0;
}
bool IsRunningWithVFS1() {
- const char* env = getenv(GVISOR_VFS);
+ const char* env = getenv(kGvisorVfs);
if (env == nullptr) {
// If not set, it's running on Linux.
return false;
diff --git a/test/util/test_util.h b/test/util/test_util.h
index e635827e6..109078fc7 100644
--- a/test/util/test_util.h
+++ b/test/util/test_util.h
@@ -195,6 +195,8 @@
namespace gvisor {
namespace testing {
+constexpr char kTestOnGvisor[] = "TEST_ON_GVISOR";
+
// TestInit must be called prior to RUN_ALL_TESTS.
//
// This parses all arguments and adjusts argc and argv appropriately.
@@ -215,6 +217,7 @@ namespace Platform {
constexpr char kNative[] = "native";
constexpr char kPtrace[] = "ptrace";
constexpr char kKVM[] = "kvm";
+constexpr char kFuchsia[] = "fuchsia";
} // namespace Platform
bool IsRunningOnGvisor();