diff options
Diffstat (limited to 'test')
40 files changed, 771 insertions, 313 deletions
diff --git a/test/BUILD b/test/BUILD index 01fa01f2e..34b950644 100644 --- a/test/BUILD +++ b/test/BUILD @@ -1,44 +1 @@ -package(licenses = ["notice"]) # Apache 2.0 - -# We need to define a bazel platform and toolchain to specify dockerPrivileged -# and dockerRunAsRoot options, they are required to run tests on the RBE -# cluster in Kokoro. -alias( - name = "rbe_ubuntu1604", - actual = ":rbe_ubuntu1604_r346485", -) - -platform( - name = "rbe_ubuntu1604_r346485", - constraint_values = [ - "@bazel_tools//platforms:x86_64", - "@bazel_tools//platforms:linux", - "@bazel_tools//tools/cpp:clang", - "@bazel_toolchains//constraints:xenial", - "@bazel_toolchains//constraints/sanitizers:support_msan", - ], - remote_execution_properties = """ - properties: { - name: "container-image" - value:"docker://gcr.io/cloud-marketplace/google/rbe-ubuntu16-04@sha256:69c9f1652941d64a46f6f7358a44c1718f25caa5cb1ced4a58ccc5281cd183b5" - } - properties: { - name: "dockerAddCapabilities" - value: "SYS_ADMIN" - } - properties: { - name: "dockerPrivileged" - value: "true" - } - """, -) - -toolchain( - name = "cc-toolchain-clang-x86_64-default", - exec_compatible_with = [ - ], - target_compatible_with = [ - ], - toolchain = "@bazel_toolchains//configs/ubuntu16_04_clang/9.0.0/bazel_0.28.0/cc:cc-compiler-k8", - toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", -) +package(licenses = ["notice"]) diff --git a/test/e2e/BUILD b/test/e2e/BUILD index 4fe03a220..76e04f878 100644 --- a/test/e2e/BUILD +++ b/test/e2e/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("//tools:defs.bzl", "go_library", "go_test") package(licenses = ["notice"]) @@ -10,7 +10,7 @@ go_test( "integration_test.go", "regression_test.go", ], - embed = [":integration"], + library = ":integration", tags = [ # Requires docker and runsc to be configured before the test runs. "manual", @@ -29,5 +29,4 @@ go_test( go_library( name = "integration", srcs = ["integration.go"], - importpath = "gvisor.dev/gvisor/test/integration", ) diff --git a/test/image/BUILD b/test/image/BUILD index 09b0a0ad5..7392ac54e 100644 --- a/test/image/BUILD +++ b/test/image/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("//tools:defs.bzl", "go_library", "go_test") package(licenses = ["notice"]) @@ -14,7 +14,7 @@ go_test( "ruby.rb", "ruby.sh", ], - embed = [":image"], + library = ":image", tags = [ # Requires docker and runsc to be configured before the test runs. "manual", @@ -30,5 +30,4 @@ go_test( go_library( name = "image", srcs = ["image.go"], - importpath = "gvisor.dev/gvisor/test/image", ) diff --git a/test/iptables/BUILD b/test/iptables/BUILD index fa833c3b2..6bb3b82b5 100644 --- a/test/iptables/BUILD +++ b/test/iptables/BUILD @@ -1,16 +1,21 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("//tools:defs.bzl", "go_library", "go_test") package(licenses = ["notice"]) go_library( name = "iptables", + testonly = 1, srcs = [ "filter_input.go", + "filter_output.go", "iptables.go", "iptables_util.go", + "nat.go", ], - importpath = "gvisor.dev/gvisor/test/iptables", visibility = ["//test/iptables:__subpackages__"], + deps = [ + "//runsc/testutil", + ], ) go_test( @@ -18,7 +23,7 @@ go_test( srcs = [ "iptables_test.go", ], - embed = [":iptables"], + library = ":iptables", tags = [ "local", "manual", diff --git a/test/iptables/filter_input.go b/test/iptables/filter_input.go index 923f44e68..fd02ff2ff 100644 --- a/test/iptables/filter_input.go +++ b/test/iptables/filter_input.go @@ -28,9 +28,13 @@ const ( ) func init() { - RegisterTestCase(FilterInputDropUDP{}) - RegisterTestCase(FilterInputDropUDPPort{}) + RegisterTestCase(FilterInputDropAll{}) RegisterTestCase(FilterInputDropDifferentUDPPort{}) + RegisterTestCase(FilterInputDropOnlyUDP{}) + RegisterTestCase(FilterInputDropTCPDestPort{}) + RegisterTestCase(FilterInputDropTCPSrcPort{}) + RegisterTestCase(FilterInputDropUDPPort{}) + RegisterTestCase(FilterInputDropUDP{}) } // FilterInputDropUDP tests that we can drop UDP traffic. @@ -64,6 +68,35 @@ func (FilterInputDropUDP) LocalAction(ip net.IP) error { return sendUDPLoop(ip, dropPort, sendloopDuration) } +// FilterInputDropOnlyUDP tests that "-p udp -j DROP" only affects UDP traffic. +type FilterInputDropOnlyUDP struct{} + +// Name implements TestCase.Name. +func (FilterInputDropOnlyUDP) Name() string { + return "FilterInputDropOnlyUDP" +} + +// ContainerAction implements TestCase.ContainerAction. +func (FilterInputDropOnlyUDP) ContainerAction(ip net.IP) error { + if err := filterTable("-A", "INPUT", "-p", "udp", "-j", "DROP"); err != nil { + return err + } + + // Listen for a TCP connection, which should be allowed. + if err := listenTCP(acceptPort, sendloopDuration); err != nil { + return fmt.Errorf("failed to establish a connection %v", err) + } + + return nil +} + +// LocalAction implements TestCase.LocalAction. +func (FilterInputDropOnlyUDP) LocalAction(ip net.IP) error { + // Try to establish a TCP connection with the container, which should + // succeed. + return connectTCP(ip, acceptPort, dropPort, sendloopDuration) +} + // FilterInputDropUDPPort tests that we can drop UDP traffic by port. type FilterInputDropUDPPort struct{} @@ -122,3 +155,96 @@ func (FilterInputDropDifferentUDPPort) ContainerAction(ip net.IP) error { func (FilterInputDropDifferentUDPPort) LocalAction(ip net.IP) error { return sendUDPLoop(ip, acceptPort, sendloopDuration) } + +// FilterInputDropTCPDestPort tests that connections are not accepted on specified source ports. +type FilterInputDropTCPDestPort struct{} + +// Name implements TestCase.Name. +func (FilterInputDropTCPDestPort) Name() string { + return "FilterInputDropTCPDestPort" +} + +// ContainerAction implements TestCase.ContainerAction. +func (FilterInputDropTCPDestPort) ContainerAction(ip net.IP) error { + if err := filterTable("-A", "INPUT", "-p", "tcp", "-m", "tcp", "--dport", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil { + return err + } + + // Listen for TCP packets on drop port. + if err := listenTCP(dropPort, sendloopDuration); err == nil { + return fmt.Errorf("connection on port %d should not be accepted, but got accepted", dropPort) + } + + return nil +} + +// LocalAction implements TestCase.LocalAction. +func (FilterInputDropTCPDestPort) LocalAction(ip net.IP) error { + if err := connectTCP(ip, dropPort, acceptPort, sendloopDuration); err == nil { + return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", dropPort) + } + + return nil +} + +// FilterInputDropTCPSrcPort tests that connections are not accepted on specified source ports. +type FilterInputDropTCPSrcPort struct{} + +// Name implements TestCase.Name. +func (FilterInputDropTCPSrcPort) Name() string { + return "FilterInputDropTCPSrcPort" +} + +// ContainerAction implements TestCase.ContainerAction. +func (FilterInputDropTCPSrcPort) ContainerAction(ip net.IP) error { + if err := filterTable("-A", "INPUT", "-p", "tcp", "-m", "tcp", "--sport", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil { + return err + } + + // Listen for TCP packets on accept port. + if err := listenTCP(acceptPort, sendloopDuration); err == nil { + return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", dropPort) + } + + return nil +} + +// LocalAction implements TestCase.LocalAction. +func (FilterInputDropTCPSrcPort) LocalAction(ip net.IP) error { + if err := connectTCP(ip, acceptPort, dropPort, sendloopDuration); err == nil { + return fmt.Errorf("connection on port %d should not be acceptedi, but got accepted", dropPort) + } + + return nil +} + +// FilterInputDropAll tests that we can drop all traffic to the INPUT chain. +type FilterInputDropAll struct{} + +// Name implements TestCase.Name. +func (FilterInputDropAll) Name() string { + return "FilterInputDropAll" +} + +// ContainerAction implements TestCase.ContainerAction. +func (FilterInputDropAll) ContainerAction(ip net.IP) error { + if err := filterTable("-A", "INPUT", "-j", "DROP"); err != nil { + return err + } + + // Listen for all packets on dropPort. + if err := listenUDP(dropPort, sendloopDuration); err == nil { + return fmt.Errorf("packets should have been dropped, but got a packet") + } else if netErr, ok := err.(net.Error); !ok || !netErr.Timeout() { + return fmt.Errorf("error reading: %v", err) + } + + // At this point we know that reading timed out and never received a + // packet. + return nil +} + +// LocalAction implements TestCase.LocalAction. +func (FilterInputDropAll) LocalAction(ip net.IP) error { + return sendUDPLoop(ip, dropPort, sendloopDuration) +} diff --git a/test/iptables/filter_output.go b/test/iptables/filter_output.go new file mode 100644 index 000000000..ee2c49f9a --- /dev/null +++ b/test/iptables/filter_output.go @@ -0,0 +1,87 @@ +// 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 iptables + +import ( + "fmt" + "net" +) + +func init() { + RegisterTestCase(FilterOutputDropTCPDestPort{}) + RegisterTestCase(FilterOutputDropTCPSrcPort{}) +} + +// FilterOutputDropTCPDestPort tests that connections are not accepted on specified source ports. +type FilterOutputDropTCPDestPort struct{} + +// Name implements TestCase.Name. +func (FilterOutputDropTCPDestPort) Name() string { + return "FilterOutputDropTCPDestPort" +} + +// ContainerAction implements TestCase.ContainerAction. +func (FilterOutputDropTCPDestPort) ContainerAction(ip net.IP) error { + if err := filterTable("-A", "OUTPUT", "-p", "tcp", "-m", "tcp", "--dport", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil { + return err + } + + // Listen for TCP packets on accept port. + if err := listenTCP(acceptPort, sendloopDuration); err == nil { + return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", dropPort) + } + + return nil +} + +// LocalAction implements TestCase.LocalAction. +func (FilterOutputDropTCPDestPort) LocalAction(ip net.IP) error { + if err := connectTCP(ip, acceptPort, dropPort, sendloopDuration); err == nil { + return fmt.Errorf("connection on port %d should not be accepted, but got accepted", dropPort) + } + + return nil +} + +// FilterOutputDropTCPSrcPort tests that connections are not accepted on specified source ports. +type FilterOutputDropTCPSrcPort struct{} + +// Name implements TestCase.Name. +func (FilterOutputDropTCPSrcPort) Name() string { + return "FilterOutputDropTCPSrcPort" +} + +// ContainerAction implements TestCase.ContainerAction. +func (FilterOutputDropTCPSrcPort) ContainerAction(ip net.IP) error { + if err := filterTable("-A", "OUTPUT", "-p", "tcp", "-m", "tcp", "--sport", fmt.Sprintf("%d", dropPort), "-j", "DROP"); err != nil { + return err + } + + // Listen for TCP packets on drop port. + if err := listenTCP(dropPort, sendloopDuration); err == nil { + return fmt.Errorf("connection on port %d should not be accepted, but got accepted", dropPort) + } + + return nil +} + +// LocalAction implements TestCase.LocalAction. +func (FilterOutputDropTCPSrcPort) LocalAction(ip net.IP) error { + if err := connectTCP(ip, dropPort, acceptPort, sendloopDuration); err == nil { + return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", dropPort) + } + + return nil +} diff --git a/test/iptables/iptables_test.go b/test/iptables/iptables_test.go index bfbf1bb87..679a29bef 100644 --- a/test/iptables/iptables_test.go +++ b/test/iptables/iptables_test.go @@ -15,6 +15,7 @@ package iptables import ( + "flag" "fmt" "net" "os" @@ -22,13 +23,12 @@ import ( "testing" "time" - "flag" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/runsc/dockerutil" "gvisor.dev/gvisor/runsc/testutil" ) -const timeout time.Duration = 10 * time.Second +const timeout = 18 * time.Second var image = flag.String("image", "bazel/test/iptables/runner:runner", "image to run tests in") @@ -177,3 +177,51 @@ func TestFilterInputDropDifferentUDPPort(t *testing.T) { t.Fatal(err) } } + +func TestFilterInputDropAll(t *testing.T) { + if err := singleTest(FilterInputDropAll{}); err != nil { + t.Fatal(err) + } +} + +func TestFilterInputDropOnlyUDP(t *testing.T) { + if err := singleTest(FilterInputDropOnlyUDP{}); err != nil { + t.Fatal(err) + } +} + +func TestNATRedirectUDPPort(t *testing.T) { + if err := singleTest(NATRedirectUDPPort{}); err != nil { + t.Fatal(err) + } +} + +func TestNATDropUDP(t *testing.T) { + if err := singleTest(NATDropUDP{}); err != nil { + t.Fatal(err) + } +} + +func TestFilterInputDropTCPDestPort(t *testing.T) { + if err := singleTest(FilterInputDropTCPDestPort{}); err != nil { + t.Fatal(err) + } +} + +func TestFilterInputDropTCPSrcPort(t *testing.T) { + if err := singleTest(FilterInputDropTCPSrcPort{}); err != nil { + t.Fatal(err) + } +} + +func TestFilterOutputDropTCPDestPort(t *testing.T) { + if err := singleTest(FilterOutputDropTCPDestPort{}); err != nil { + t.Fatal(err) + } +} + +func TestFilterOutputDropTCPSrcPort(t *testing.T) { + if err := singleTest(FilterOutputDropTCPSrcPort{}); err != nil { + t.Fatal(err) + } +} diff --git a/test/iptables/iptables_util.go b/test/iptables/iptables_util.go index 3a4d11f1a..043114c78 100644 --- a/test/iptables/iptables_util.go +++ b/test/iptables/iptables_util.go @@ -19,6 +19,8 @@ import ( "net" "os/exec" "time" + + "gvisor.dev/gvisor/runsc/testutil" ) const iptablesBinary = "iptables" @@ -80,3 +82,51 @@ func sendUDPLoop(ip net.IP, port int, duration time.Duration) error { return nil } + +// listenTCP listens for connections on a TCP port. +func listenTCP(port int, timeout time.Duration) error { + localAddr := net.TCPAddr{ + Port: port, + } + + // Starts listening on port. + lConn, err := net.ListenTCP("tcp4", &localAddr) + if err != nil { + return err + } + defer lConn.Close() + + // Accept connections on port. + lConn.SetDeadline(time.Now().Add(timeout)) + conn, err := lConn.AcceptTCP() + if err != nil { + return err + } + conn.Close() + return nil +} + +// connectTCP connects the TCP server over specified local port, server IP and remote/server port. +func connectTCP(ip net.IP, remotePort, localPort int, timeout time.Duration) error { + contAddr := net.TCPAddr{ + IP: ip, + Port: remotePort, + } + // The container may not be listening when we first connect, so retry + // upon error. + callback := func() error { + localAddr := net.TCPAddr{ + Port: localPort, + } + conn, err := net.DialTCP("tcp4", &localAddr, &contAddr) + if conn != nil { + conn.Close() + } + return err + } + if err := testutil.Poll(callback, timeout); err != nil { + return fmt.Errorf("timed out waiting to send IP, most recent error: %v", err) + } + + return nil +} diff --git a/test/iptables/nat.go b/test/iptables/nat.go new file mode 100644 index 000000000..b5c6f927e --- /dev/null +++ b/test/iptables/nat.go @@ -0,0 +1,80 @@ +// 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 iptables + +import ( + "fmt" + "net" +) + +const ( + redirectPort = 42 +) + +func init() { + RegisterTestCase(NATRedirectUDPPort{}) + RegisterTestCase(NATDropUDP{}) +} + +// NATRedirectUDPPort tests that packets are redirected to different port. +type NATRedirectUDPPort struct{} + +// Name implements TestCase.Name. +func (NATRedirectUDPPort) Name() string { + return "NATRedirectUDPPort" +} + +// ContainerAction implements TestCase.ContainerAction. +func (NATRedirectUDPPort) ContainerAction(ip net.IP) error { + if err := filterTable("-t", "nat", "-A", "PREROUTING", "-p", "udp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", redirectPort)); err != nil { + return err + } + + if err := listenUDP(redirectPort, sendloopDuration); err != nil { + return fmt.Errorf("packets on port %d should be allowed, but encountered an error: %v", redirectPort, err) + } + return nil +} + +// LocalAction implements TestCase.LocalAction. +func (NATRedirectUDPPort) LocalAction(ip net.IP) error { + return sendUDPLoop(ip, acceptPort, sendloopDuration) +} + +// NATDropUDP tests that packets are not received in ports other than redirect port. +type NATDropUDP struct{} + +// Name implements TestCase.Name. +func (NATDropUDP) Name() string { + return "NATDropUDP" +} + +// ContainerAction implements TestCase.ContainerAction. +func (NATDropUDP) ContainerAction(ip net.IP) error { + if err := filterTable("-t", "nat", "-A", "PREROUTING", "-p", "udp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", redirectPort)); err != nil { + return err + } + + if err := listenUDP(acceptPort, sendloopDuration); err == nil { + return fmt.Errorf("packets on port %d should have been redirected to port %d", acceptPort, redirectPort) + } + + return nil +} + +// LocalAction implements TestCase.LocalAction. +func (NATDropUDP) LocalAction(ip net.IP) error { + return sendUDPLoop(ip, acceptPort, sendloopDuration) +} diff --git a/test/iptables/runner/BUILD b/test/iptables/runner/BUILD index c6c42d870..b9199387a 100644 --- a/test/iptables/runner/BUILD +++ b/test/iptables/runner/BUILD @@ -1,15 +1,22 @@ -load("@io_bazel_rules_docker//go:image.bzl", "go_image") -load("@io_bazel_rules_docker//container:container.bzl", "container_image") +load("//tools:defs.bzl", "container_image", "go_binary", "go_image") package(licenses = ["notice"]) +go_binary( + name = "runner", + testonly = 1, + srcs = ["main.go"], + deps = ["//test/iptables"], +) + container_image( name = "iptables-base", base = "@iptables-test//image", ) go_image( - name = "runner", + name = "runner-image", + testonly = 1, srcs = ["main.go"], base = ":iptables-base", deps = ["//test/iptables"], diff --git a/test/root/BUILD b/test/root/BUILD index d5dd9bca2..23ce2a70f 100644 --- a/test/root/BUILD +++ b/test/root/BUILD @@ -1,11 +1,10 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("//tools:defs.bzl", "go_library", "go_test") package(licenses = ["notice"]) go_library( name = "root", srcs = ["root.go"], - importpath = "gvisor.dev/gvisor/test/root", ) go_test( @@ -21,7 +20,7 @@ go_test( data = [ "//runsc", ], - embed = [":root"], + library = ":root", tags = [ # Requires docker and runsc to be configured before the test runs. # Also test only runs as root. diff --git a/test/root/testdata/BUILD b/test/root/testdata/BUILD index 125633680..bca5f9cab 100644 --- a/test/root/testdata/BUILD +++ b/test/root/testdata/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("//tools:defs.bzl", "go_library") package(licenses = ["notice"]) @@ -12,7 +12,6 @@ go_library( "sandbox.go", "simple.go", ], - importpath = "gvisor.dev/gvisor/test/root/testdata", visibility = [ "//visibility:public", ], diff --git a/test/runtimes/BUILD b/test/runtimes/BUILD index 367295206..2c472bf8d 100644 --- a/test/runtimes/BUILD +++ b/test/runtimes/BUILD @@ -1,6 +1,6 @@ # These packages are used to run language runtime tests inside gVisor sandboxes. -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_test") +load("//tools:defs.bzl", "go_binary", "go_test") load("//test/runtimes:build_defs.bzl", "runtime_test") package(licenses = ["notice"]) @@ -49,5 +49,5 @@ go_test( name = "blacklist_test", size = "small", srcs = ["blacklist_test.go"], - embed = [":runner"], + library = ":runner", ) diff --git a/test/runtimes/build_defs.bzl b/test/runtimes/build_defs.bzl index 6f84ca852..92e275a76 100644 --- a/test/runtimes/build_defs.bzl +++ b/test/runtimes/build_defs.bzl @@ -1,6 +1,6 @@ """Defines a rule for runtime test targets.""" -load("@io_bazel_rules_go//go:def.bzl", "go_test") +load("//tools:defs.bzl", "go_test", "loopback") def runtime_test( name, @@ -34,6 +34,7 @@ def runtime_test( ] data = [ ":runner", + loopback, ] if blacklist_file: args += ["--blacklist_file", "test/runtimes/" + blacklist_file] @@ -61,7 +62,7 @@ def blacklist_test(name, blacklist_file): """Test that a blacklist parses correctly.""" go_test( name = name + "_blacklist_test", - embed = [":runner"], + library = ":runner", srcs = ["blacklist_test.go"], args = ["--blacklist_file", "test/runtimes/" + blacklist_file], data = [blacklist_file], diff --git a/test/runtimes/images/proctor/BUILD b/test/runtimes/images/proctor/BUILD index 09dc6c42f..85e004c45 100644 --- a/test/runtimes/images/proctor/BUILD +++ b/test/runtimes/images/proctor/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_test") +load("//tools:defs.bzl", "go_binary", "go_test") package(licenses = ["notice"]) @@ -19,7 +19,7 @@ go_test( name = "proctor_test", size = "small", srcs = ["proctor_test.go"], - embed = [":proctor"], + library = ":proctor", deps = [ "//runsc/testutil", ], diff --git a/test/syscalls/BUILD b/test/syscalls/BUILD index a3a85917d..40e974314 100644 --- a/test/syscalls/BUILD +++ b/test/syscalls/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_binary") +load("//tools:defs.bzl", "go_binary") load("//test/syscalls:build_defs.bzl", "syscall_test") package(licenses = ["notice"]) @@ -380,6 +380,8 @@ syscall_test(test = "//test/syscalls/linux:rseq_test") syscall_test(test = "//test/syscalls/linux:rtsignal_test") +syscall_test(test = "//test/syscalls/linux:signalfd_test") + syscall_test(test = "//test/syscalls/linux:sched_test") syscall_test(test = "//test/syscalls/linux:sched_yield_test") @@ -717,11 +719,6 @@ syscall_test(test = "//test/syscalls/linux:proc_net_tcp_test") syscall_test(test = "//test/syscalls/linux:proc_net_udp_test") -syscall_test( - add_overlay = True, - test = "//test/syscalls/linux:xattr_test", -) - go_binary( name = "syscall_test_runner", testonly = 1, diff --git a/test/syscalls/build_defs.bzl b/test/syscalls/build_defs.bzl index aaf77c65b..1df761dd0 100644 --- a/test/syscalls/build_defs.bzl +++ b/test/syscalls/build_defs.bzl @@ -1,5 +1,7 @@ """Defines a rule for syscall test targets.""" +load("//tools:defs.bzl", "loopback") + # syscall_test is a macro that will create targets to run the given test target # on the host (native) and runsc. def syscall_test( @@ -135,6 +137,7 @@ def _syscall_test( name = name, data = [ ":syscall_test_runner", + loopback, test, ], args = args, @@ -148,6 +151,3 @@ def sh_test(**kwargs): native.sh_test( **kwargs ) - -def select_for_linux(for_linux, for_others = []): - return for_linux diff --git a/test/syscalls/gtest/BUILD b/test/syscalls/gtest/BUILD index 9293f25cb..de4b2727c 100644 --- a/test/syscalls/gtest/BUILD +++ b/test/syscalls/gtest/BUILD @@ -1,12 +1,9 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("//tools:defs.bzl", "go_library") package(licenses = ["notice"]) go_library( name = "gtest", srcs = ["gtest.go"], - importpath = "gvisor.dev/gvisor/test/syscalls/gtest", - visibility = [ - "//test:__subpackages__", - ], + visibility = ["//:sandbox"], ) diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD index 4c7ec3f06..c2ef50c1d 100644 --- a/test/syscalls/linux/BUILD +++ b/test/syscalls/linux/BUILD @@ -1,5 +1,4 @@ -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") -load("//test/syscalls:build_defs.bzl", "select_for_linux") +load("//tools:defs.bzl", "cc_binary", "cc_library", "default_net_util", "select_system") package( default_visibility = ["//:sandbox"], @@ -126,13 +125,11 @@ cc_library( testonly = 1, srcs = [ "socket_test_util.cc", - ] + select_for_linux( - [ - "socket_test_util_impl.cc", - ], - ), + "socket_test_util_impl.cc", + ], hdrs = ["socket_test_util.h"], - deps = [ + defines = select_system(), + deps = default_net_util() + [ "@com_google_googletest//:gtest", "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", @@ -143,8 +140,7 @@ cc_library( "//test/util:temp_path", "//test/util:test_util", "//test/util:thread_util", - ] + select_for_linux([ - ]), + ], ) cc_library( @@ -1443,6 +1439,7 @@ cc_binary( srcs = ["arch_prctl.cc"], linkstatic = 1, deps = [ + "//test/util:file_descriptor", "//test/util:test_main", "//test/util:test_util", "@com_google_googletest//:gtest", @@ -3383,11 +3380,11 @@ cc_library( name = "udp_socket_test_cases", testonly = 1, srcs = [ - "udp_socket_test_cases.cc", - ] + select_for_linux([ "udp_socket_errqueue_test_case.cc", - ]), + "udp_socket_test_cases.cc", + ], hdrs = ["udp_socket_test_cases.h"], + defines = select_system(), deps = [ ":socket_test_util", ":unix_domain_socket_test_util", diff --git a/test/syscalls/linux/arch_prctl.cc b/test/syscalls/linux/arch_prctl.cc index 81bf5a775..3a901faf5 100644 --- a/test/syscalls/linux/arch_prctl.cc +++ b/test/syscalls/linux/arch_prctl.cc @@ -14,8 +14,10 @@ #include <asm/prctl.h> #include <sys/prctl.h> +#include <sys/syscall.h> #include "gtest/gtest.h" +#include "test/util/file_descriptor.h" #include "test/util/test_util.h" // glibc does not provide a prototype for arch_prctl() so declare it here. diff --git a/test/syscalls/linux/fault.cc b/test/syscalls/linux/fault.cc index f6e19026f..a85750382 100644 --- a/test/syscalls/linux/fault.cc +++ b/test/syscalls/linux/fault.cc @@ -37,6 +37,9 @@ int GetPcFromUcontext(ucontext_t* uc, uintptr_t* pc) { #elif defined(__i386__) *pc = uc->uc_mcontext.gregs[REG_EIP]; return 1; +#elif defined(__aarch64__) + *pc = uc->uc_mcontext.pc; + return 1; #else return 0; #endif diff --git a/test/syscalls/linux/link.cc b/test/syscalls/linux/link.cc index dd5352954..e74fa2ed5 100644 --- a/test/syscalls/linux/link.cc +++ b/test/syscalls/linux/link.cc @@ -55,7 +55,8 @@ TEST(LinkTest, CanCreateLinkFile) { const std::string newname = NewTempAbsPath(); // Get the initial link count. - uint64_t initial_link_count = ASSERT_NO_ERRNO_AND_VALUE(Links(oldfile.path())); + uint64_t initial_link_count = + ASSERT_NO_ERRNO_AND_VALUE(Links(oldfile.path())); EXPECT_THAT(link(oldfile.path().c_str(), newname.c_str()), SyscallSucceeds()); diff --git a/test/syscalls/linux/proc.cc b/test/syscalls/linux/proc.cc index 8cf08991b..bf9bb45d3 100644 --- a/test/syscalls/linux/proc.cc +++ b/test/syscalls/linux/proc.cc @@ -102,7 +102,49 @@ namespace { // O_LARGEFILE as defined by Linux. glibc tries to be clever by setting it to 0 // because "it isn't needed", even though Linux can return it via F_GETFL. +#if defined(__x86_64__) || defined(__i386__) constexpr int kOLargeFile = 00100000; +#elif __aarch64__ +// The value originate from the Linux +// kernel's arch/arm64/include/uapi/asm/fcntl.h. +constexpr int kOLargeFile = 00400000; +#else +#error "Unknown architecture" +#endif + +#if defined(__x86_64__) || defined(__i386__) +// This list of "required" fields is taken from reading the file +// arch/x86/kernel/cpu/proc.c and seeing which fields will be unconditionally +// printed by the kernel. +static const char* required_fields[] = { + "processor", + "vendor_id", + "cpu family", + "model\t\t:", + "model name", + "stepping", + "cpu MHz", + "fpu\t\t:", + "fpu_exception", + "cpuid level", + "wp", + "bogomips", + "clflush size", + "cache_alignment", + "address sizes", + "power management", +}; +#elif __aarch64__ +// This list of "required" fields is taken from reading the file +// arch/arm64/kernel/cpuinfo.c and seeing which fields will be unconditionally +// printed by the kernel. +static const char* required_fields[] = { + "processor", "BogoMIPS", "Features", "CPU implementer", + "CPU architecture", "CPU variant", "CPU part", "CPU revision", +}; +#else +#error "Unknown architecture" +#endif // Takes the subprocess command line and pid. // If it returns !OK, WithSubprocess returns immediately. @@ -717,28 +759,6 @@ TEST(ProcCpuinfo, RequiredFieldsArePresent) { ASSERT_FALSE(proc_cpuinfo.empty()); std::vector<std::string> cpuinfo_fields = absl::StrSplit(proc_cpuinfo, '\n'); - // This list of "required" fields is taken from reading the file - // arch/x86/kernel/cpu/proc.c and seeing which fields will be unconditionally - // printed by the kernel. - static const char* required_fields[] = { - "processor", - "vendor_id", - "cpu family", - "model\t\t:", - "model name", - "stepping", - "cpu MHz", - "fpu\t\t:", - "fpu_exception", - "cpuid level", - "wp", - "bogomips", - "clflush size", - "cache_alignment", - "address sizes", - "power management", - }; - // Check that the usual fields are there. We don't really care about the // contents. for (const std::string& field : required_fields) { diff --git a/test/syscalls/linux/rseq/BUILD b/test/syscalls/linux/rseq/BUILD index 5cfe4e56f..ed488dbc2 100644 --- a/test/syscalls/linux/rseq/BUILD +++ b/test/syscalls/linux/rseq/BUILD @@ -1,8 +1,7 @@ # This package contains a standalone rseq test binary. This binary must not # depend on libc, which might use rseq itself. -load("@bazel_tools//tools/cpp:cc_flags_supplier.bzl", "cc_flags_supplier") -load("@rules_cc//cc:defs.bzl", "cc_library") +load("//tools:defs.bzl", "cc_flags_supplier", "cc_library", "cc_toolchain") package(licenses = ["notice"]) @@ -37,8 +36,8 @@ genrule( "$(location start.S)", ]), toolchains = [ + cc_toolchain, ":no_pie_cc_flags", - "@bazel_tools//tools/cpp:current_cc_toolchain", ], visibility = ["//:sandbox"], ) diff --git a/test/syscalls/linux/sigaltstack.cc b/test/syscalls/linux/sigaltstack.cc index a778fa639..62b04ef1d 100644 --- a/test/syscalls/linux/sigaltstack.cc +++ b/test/syscalls/linux/sigaltstack.cc @@ -114,7 +114,7 @@ TEST(SigaltstackTest, ResetByExecve) { volatile bool badhandler_on_sigaltstack = true; // Set by the handler. char* volatile badhandler_low_water_mark = nullptr; // Set by the handler. -volatile uint8_t badhandler_recursive_faults = 0; // Consumed by the handler. +volatile uint8_t badhandler_recursive_faults = 0; // Consumed by the handler. void badhandler(int sig, siginfo_t* siginfo, void* arg) { char stack_var = 0; diff --git a/test/syscalls/linux/signalfd.cc b/test/syscalls/linux/signalfd.cc index 09ecad34a..95be4b66c 100644 --- a/test/syscalls/linux/signalfd.cc +++ b/test/syscalls/linux/signalfd.cc @@ -39,6 +39,7 @@ namespace testing { namespace { constexpr int kSigno = SIGUSR1; +constexpr int kSignoMax = 64; // SIGRTMAX constexpr int kSignoAlt = SIGUSR2; // Returns a new signalfd. @@ -51,41 +52,45 @@ inline PosixErrorOr<FileDescriptor> NewSignalFD(sigset_t* mask, int flags = 0) { return FileDescriptor(fd); } -TEST(Signalfd, Basic) { +class SignalfdTest : public ::testing::TestWithParam<int> {}; + +TEST_P(SignalfdTest, Basic) { + int signo = GetParam(); // Create the signalfd. sigset_t mask; sigemptyset(&mask); - sigaddset(&mask, kSigno); + sigaddset(&mask, signo); FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0)); // Deliver the blocked signal. const auto scoped_sigmask = - ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, kSigno)); - ASSERT_THAT(tgkill(getpid(), gettid(), kSigno), SyscallSucceeds()); + ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); + ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); // We should now read the signal. struct signalfd_siginfo rbuf; ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), SyscallSucceedsWithValue(sizeof(rbuf))); - EXPECT_EQ(rbuf.ssi_signo, kSigno); + EXPECT_EQ(rbuf.ssi_signo, signo); } -TEST(Signalfd, MaskWorks) { +TEST_P(SignalfdTest, MaskWorks) { + int signo = GetParam(); // Create two signalfds with different masks. sigset_t mask1, mask2; sigemptyset(&mask1); sigemptyset(&mask2); - sigaddset(&mask1, kSigno); + sigaddset(&mask1, signo); sigaddset(&mask2, kSignoAlt); FileDescriptor fd1 = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask1, 0)); FileDescriptor fd2 = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask2, 0)); // Deliver the two signals. const auto scoped_sigmask1 = - ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, kSigno)); + ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); const auto scoped_sigmask2 = ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, kSignoAlt)); - ASSERT_THAT(tgkill(getpid(), gettid(), kSigno), SyscallSucceeds()); + ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); ASSERT_THAT(tgkill(getpid(), gettid(), kSignoAlt), SyscallSucceeds()); // We should see the signals on the appropriate signalfds. @@ -98,7 +103,7 @@ TEST(Signalfd, MaskWorks) { EXPECT_EQ(rbuf2.ssi_signo, kSignoAlt); ASSERT_THAT(read(fd1.get(), &rbuf1, sizeof(rbuf1)), SyscallSucceedsWithValue(sizeof(rbuf1))); - EXPECT_EQ(rbuf1.ssi_signo, kSigno); + EXPECT_EQ(rbuf1.ssi_signo, signo); } TEST(Signalfd, Cloexec) { @@ -111,11 +116,12 @@ TEST(Signalfd, Cloexec) { EXPECT_THAT(fcntl(fd.get(), F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC)); } -TEST(Signalfd, Blocking) { +TEST_P(SignalfdTest, Blocking) { + int signo = GetParam(); // Create the signalfd in blocking mode. sigset_t mask; sigemptyset(&mask); - sigaddset(&mask, kSigno); + sigaddset(&mask, signo); FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0)); // Shared tid variable. @@ -136,7 +142,7 @@ TEST(Signalfd, Blocking) { struct signalfd_siginfo rbuf; ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), SyscallSucceedsWithValue(sizeof(rbuf))); - EXPECT_EQ(rbuf.ssi_signo, kSigno); + EXPECT_EQ(rbuf.ssi_signo, signo); }); // Wait until blocked. @@ -149,20 +155,21 @@ TEST(Signalfd, Blocking) { // // See gvisor.dev/issue/139. if (IsRunningOnGvisor()) { - ASSERT_THAT(tgkill(getpid(), gettid(), kSigno), SyscallSucceeds()); + ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); } else { - ASSERT_THAT(tgkill(getpid(), tid, kSigno), SyscallSucceeds()); + ASSERT_THAT(tgkill(getpid(), tid, signo), SyscallSucceeds()); } // Ensure that it was received. t.Join(); } -TEST(Signalfd, ThreadGroup) { +TEST_P(SignalfdTest, ThreadGroup) { + int signo = GetParam(); // Create the signalfd in blocking mode. sigset_t mask; sigemptyset(&mask); - sigaddset(&mask, kSigno); + sigaddset(&mask, signo); FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0)); // Shared variable. @@ -176,7 +183,7 @@ TEST(Signalfd, ThreadGroup) { struct signalfd_siginfo rbuf; ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), SyscallSucceedsWithValue(sizeof(rbuf))); - EXPECT_EQ(rbuf.ssi_signo, kSigno); + EXPECT_EQ(rbuf.ssi_signo, signo); // Wait for the other thread. absl::MutexLock ml(&mu); @@ -185,7 +192,7 @@ TEST(Signalfd, ThreadGroup) { }); // Deliver the signal to the threadgroup. - ASSERT_THAT(kill(getpid(), kSigno), SyscallSucceeds()); + ASSERT_THAT(kill(getpid(), signo), SyscallSucceeds()); // Wait for the first thread to process. { @@ -194,13 +201,13 @@ TEST(Signalfd, ThreadGroup) { } // Deliver to the thread group again (other thread still exists). - ASSERT_THAT(kill(getpid(), kSigno), SyscallSucceeds()); + ASSERT_THAT(kill(getpid(), signo), SyscallSucceeds()); // Ensure that we can also receive it. struct signalfd_siginfo rbuf; ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), SyscallSucceedsWithValue(sizeof(rbuf))); - EXPECT_EQ(rbuf.ssi_signo, kSigno); + EXPECT_EQ(rbuf.ssi_signo, signo); // Mark the test as done. { @@ -212,11 +219,12 @@ TEST(Signalfd, ThreadGroup) { t.Join(); } -TEST(Signalfd, Nonblock) { +TEST_P(SignalfdTest, Nonblock) { + int signo = GetParam(); // Create the signalfd in non-blocking mode. sigset_t mask; sigemptyset(&mask); - sigaddset(&mask, kSigno); + sigaddset(&mask, signo); FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_NONBLOCK)); @@ -227,20 +235,21 @@ TEST(Signalfd, Nonblock) { // Block and deliver the signal. const auto scoped_sigmask = - ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, kSigno)); - ASSERT_THAT(tgkill(getpid(), gettid(), kSigno), SyscallSucceeds()); + ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); + ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); // Ensure that a read actually works. ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), SyscallSucceedsWithValue(sizeof(rbuf))); - EXPECT_EQ(rbuf.ssi_signo, kSigno); + EXPECT_EQ(rbuf.ssi_signo, signo); // Should block again. EXPECT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), SyscallFailsWithErrno(EWOULDBLOCK)); } -TEST(Signalfd, SetMask) { +TEST_P(SignalfdTest, SetMask) { + int signo = GetParam(); // Create the signalfd matching nothing. sigset_t mask; sigemptyset(&mask); @@ -249,8 +258,8 @@ TEST(Signalfd, SetMask) { // Block and deliver a signal. const auto scoped_sigmask = - ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, kSigno)); - ASSERT_THAT(tgkill(getpid(), gettid(), kSigno), SyscallSucceeds()); + ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); + ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); // We should have nothing. struct signalfd_siginfo rbuf; @@ -258,29 +267,30 @@ TEST(Signalfd, SetMask) { SyscallFailsWithErrno(EWOULDBLOCK)); // Change the signal mask. - sigaddset(&mask, kSigno); + sigaddset(&mask, signo); ASSERT_THAT(signalfd(fd.get(), &mask, 0), SyscallSucceeds()); // We should now have the signal. ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), SyscallSucceedsWithValue(sizeof(rbuf))); - EXPECT_EQ(rbuf.ssi_signo, kSigno); + EXPECT_EQ(rbuf.ssi_signo, signo); } -TEST(Signalfd, Poll) { +TEST_P(SignalfdTest, Poll) { + int signo = GetParam(); // Create the signalfd. sigset_t mask; sigemptyset(&mask); - sigaddset(&mask, kSigno); + sigaddset(&mask, signo); FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0)); // Block the signal, and start a thread to deliver it. const auto scoped_sigmask = - ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, kSigno)); + ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); pid_t orig_tid = gettid(); ScopedThread t([&] { absl::SleepFor(absl::Seconds(5)); - ASSERT_THAT(tgkill(getpid(), orig_tid, kSigno), SyscallSucceeds()); + ASSERT_THAT(tgkill(getpid(), orig_tid, signo), SyscallSucceeds()); }); // Start polling for the signal. We expect that it is not available at the @@ -297,19 +307,18 @@ TEST(Signalfd, Poll) { SyscallSucceedsWithValue(sizeof(rbuf))); } -TEST(Signalfd, KillStillKills) { - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGKILL); - FileDescriptor fd = - ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_CLOEXEC)); - - // Just because there is a signalfd, we shouldn't see any change in behavior - // for unblockable signals. It's easier to test this with SIGKILL. - const auto scoped_sigmask = - ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, SIGKILL)); - EXPECT_EXIT(tgkill(getpid(), gettid(), SIGKILL), KilledBySignal(SIGKILL), ""); +std::string PrintSigno(::testing::TestParamInfo<int> info) { + switch (info.param) { + case kSigno: + return "kSigno"; + case kSignoMax: + return "kSignoMax"; + default: + return absl::StrCat(info.param); + } } +INSTANTIATE_TEST_SUITE_P(Signalfd, SignalfdTest, + ::testing::Values(kSigno, kSignoMax), PrintSigno); TEST(Signalfd, Ppoll) { sigset_t mask; @@ -328,6 +337,20 @@ TEST(Signalfd, Ppoll) { SyscallSucceedsWithValue(0)); } +TEST(Signalfd, KillStillKills) { + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGKILL); + FileDescriptor fd = + ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_CLOEXEC)); + + // Just because there is a signalfd, we shouldn't see any change in behavior + // for unblockable signals. It's easier to test this with SIGKILL. + const auto scoped_sigmask = + ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, SIGKILL)); + EXPECT_EXIT(tgkill(getpid(), gettid(), SIGKILL), KilledBySignal(SIGKILL), ""); +} + } // namespace } // namespace testing @@ -340,6 +363,7 @@ int main(int argc, char** argv) { sigset_t set; sigemptyset(&set); sigaddset(&set, gvisor::testing::kSigno); + sigaddset(&set, gvisor::testing::kSignoMax); sigaddset(&set, gvisor::testing::kSignoAlt); TEST_PCHECK(sigprocmask(SIG_BLOCK, &set, nullptr) == 0); diff --git a/test/syscalls/linux/socket_inet_loopback.cc b/test/syscalls/linux/socket_inet_loopback.cc index 5d114d460..2f9821555 100644 --- a/test/syscalls/linux/socket_inet_loopback.cc +++ b/test/syscalls/linux/socket_inet_loopback.cc @@ -533,7 +533,7 @@ TEST_P(SocketInetLoopbackTest, TCPFinWait2Test_NoRandomSave) { // Sleep for a little over the linger timeout to reduce flakiness in // save/restore tests. - absl::SleepFor(absl::Seconds(kTCPLingerTimeout + 1)); + absl::SleepFor(absl::Seconds(kTCPLingerTimeout + 2)); ds.reset(); diff --git a/test/syscalls/linux/socket_ip_udp_generic.cc b/test/syscalls/linux/socket_ip_udp_generic.cc index 66eb68857..53290bed7 100644 --- a/test/syscalls/linux/socket_ip_udp_generic.cc +++ b/test/syscalls/linux/socket_ip_udp_generic.cc @@ -209,6 +209,46 @@ TEST_P(UDPSocketPairTest, SetMulticastLoopChar) { EXPECT_EQ(get, kSockOptOn); } +// Ensure that Receiving TOS is off by default. +TEST_P(UDPSocketPairTest, RecvTosDefault) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + int get = -1; + socklen_t get_len = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS, &get, &get_len), + SyscallSucceedsWithValue(0)); + EXPECT_EQ(get_len, sizeof(get)); + EXPECT_EQ(get, kSockOptOff); +} + +// Test that setting and getting IP_RECVTOS works as expected. +TEST_P(UDPSocketPairTest, SetRecvTos) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS, + &kSockOptOff, sizeof(kSockOptOff)), + SyscallSucceeds()); + + int get = -1; + socklen_t get_len = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS, &get, &get_len), + SyscallSucceedsWithValue(0)); + EXPECT_EQ(get_len, sizeof(get)); + EXPECT_EQ(get, kSockOptOff); + + ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS, + &kSockOptOn, sizeof(kSockOptOn)), + SyscallSucceeds()); + + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS, &get, &get_len), + SyscallSucceedsWithValue(0)); + EXPECT_EQ(get_len, sizeof(get)); + EXPECT_EQ(get, kSockOptOn); +} + TEST_P(UDPSocketPairTest, ReuseAddrDefault) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); diff --git a/test/syscalls/linux/tcp_socket.cc b/test/syscalls/linux/tcp_socket.cc index 6b99c021d..33a5ac66c 100644 --- a/test/syscalls/linux/tcp_socket.cc +++ b/test/syscalls/linux/tcp_socket.cc @@ -814,6 +814,20 @@ TEST_P(TcpSocketTest, FullBuffer) { t_ = -1; } +TEST_P(TcpSocketTest, PollAfterShutdown) { + ScopedThread client_thread([this]() { + EXPECT_THAT(shutdown(s_, SHUT_WR), SyscallSucceedsWithValue(0)); + struct pollfd poll_fd = {s_, POLLIN | POLLERR | POLLHUP, 0}; + EXPECT_THAT(RetryEINTR(poll)(&poll_fd, 1, 10000), + SyscallSucceedsWithValue(1)); + }); + + EXPECT_THAT(shutdown(t_, SHUT_WR), SyscallSucceedsWithValue(0)); + struct pollfd poll_fd = {t_, POLLIN | POLLERR | POLLHUP, 0}; + EXPECT_THAT(RetryEINTR(poll)(&poll_fd, 1, 10000), + SyscallSucceedsWithValue(1)); +} + TEST_P(SimpleTcpSocketTest, NonBlockingConnectNoListener) { // Initialize address to the loopback one. sockaddr_storage addr = diff --git a/test/syscalls/linux/udp_socket_errqueue_test_case.cc b/test/syscalls/linux/udp_socket_errqueue_test_case.cc index 147978f46..9a24e1df0 100644 --- a/test/syscalls/linux/udp_socket_errqueue_test_case.cc +++ b/test/syscalls/linux/udp_socket_errqueue_test_case.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#ifndef __fuchsia__ + #include "test/syscalls/linux/udp_socket_test_cases.h" #include <arpa/inet.h> @@ -52,3 +54,5 @@ TEST_P(UdpSocketTest, ErrorQueue) { } // namespace testing } // namespace gvisor + +#endif // __fuchsia__ diff --git a/test/syscalls/linux/udp_socket_test_cases.cc b/test/syscalls/linux/udp_socket_test_cases.cc index dc35c2f50..a2f6ef8cc 100644 --- a/test/syscalls/linux/udp_socket_test_cases.cc +++ b/test/syscalls/linux/udp_socket_test_cases.cc @@ -1349,8 +1349,9 @@ TEST_P(UdpSocketTest, TimestampIoctlPersistence) { // outgoing packets, and that a receiving socket with IP_RECVTOS or // IPV6_RECVTCLASS will create the corresponding control message. TEST_P(UdpSocketTest, SetAndReceiveTOS) { - // TODO(b/68320120): IP_RECVTOS/IPV6_RECVTCLASS not supported for netstack. - SKIP_IF(IsRunningOnGvisor() && !IsRunningWithHostinet()); + // TODO(b/144868438): IPV6_RECVTCLASS not supported for netstack. + SKIP_IF((GetParam() != AddressFamily::kIpv4) && IsRunningOnGvisor() && + !IsRunningWithHostinet()); ASSERT_THAT(bind(s_, addr_[0], addrlen_), SyscallSucceeds()); ASSERT_THAT(connect(t_, addr_[0], addrlen_), SyscallSucceeds()); @@ -1421,7 +1422,8 @@ TEST_P(UdpSocketTest, SetAndReceiveTOS) { // TOS byte on outgoing packets, and that a receiving socket with IP_RECVTOS or // IPV6_RECVTCLASS will create the corresponding control message. TEST_P(UdpSocketTest, SendAndReceiveTOS) { - // TODO(b/68320120): IP_RECVTOS/IPV6_RECVTCLASS not supported for netstack. + // TODO(b/144868438): IPV6_RECVTCLASS not supported for netstack. + // TODO(b/146661005): Setting TOS via cmsg not supported for netstack. SKIP_IF(IsRunningOnGvisor() && !IsRunningWithHostinet()); ASSERT_THAT(bind(s_, addr_[0], addrlen_), SyscallSucceeds()); ASSERT_THAT(connect(t_, addr_[0], addrlen_), SyscallSucceeds()); diff --git a/test/syscalls/linux/utimes.cc b/test/syscalls/linux/utimes.cc index 12b925a51..3a927a430 100644 --- a/test/syscalls/linux/utimes.cc +++ b/test/syscalls/linux/utimes.cc @@ -163,12 +163,12 @@ TEST(FutimesatTest, OnRelPath) { TEST(FutimesatTest, InvalidNsec) { auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); struct timeval times[4][2] = {{ - {0, 1}, // Valid + {0, 1}, // Valid {1, static_cast<int64_t>(1e7)} // Invalid }, { {1, static_cast<int64_t>(1e7)}, // Invalid - {0, 1} // Valid + {0, 1} // Valid }, { {0, 1}, // Valid @@ -288,14 +288,15 @@ TEST(UtimeTest, ZeroAtimeandMtime) { TEST(UtimensatTest, InvalidNsec) { auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); - struct timespec times[2][2] = {{ - {0, UTIME_OMIT}, // Valid - {2, static_cast<int64_t>(1e10)} // Invalid - }, - { - {2, static_cast<int64_t>(1e10)}, // Invalid - {0, UTIME_OMIT} // Valid - }}; + struct timespec times[2][2] = { + { + {0, UTIME_OMIT}, // Valid + {2, static_cast<int64_t>(1e10)} // Invalid + }, + { + {2, static_cast<int64_t>(1e10)}, // Invalid + {0, UTIME_OMIT} // Valid + }}; for (unsigned int i = 0; i < sizeof(times) / sizeof(times[0]); i++) { std::cout << "test:" << i << "\n"; diff --git a/test/syscalls/linux/xattr.cc b/test/syscalls/linux/xattr.cc index 75740238c..ab21d68c6 100644 --- a/test/syscalls/linux/xattr.cc +++ b/test/syscalls/linux/xattr.cc @@ -26,6 +26,7 @@ #include "gtest/gtest.h" #include "test/syscalls/linux/file_base.h" #include "test/util/capability_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" @@ -59,7 +60,8 @@ TEST_F(XattrTest, XattrLargeName) { std::string name = "user."; name += std::string(XATTR_NAME_MAX - name.length(), 'a'); - // TODO(b/127675828): Support setxattr and getxattr. + // An xattr should be whitelisted before it can be accessed--do not allow + // arbitrary xattrs to be read/written in gVisor. if (!IsRunningOnGvisor()) { EXPECT_THAT(setxattr(path, name.c_str(), nullptr, 0, /*flags=*/0), SyscallSucceeds()); @@ -83,59 +85,53 @@ TEST_F(XattrTest, XattrInvalidPrefix) { SyscallFailsWithErrno(EOPNOTSUPP)); } -TEST_F(XattrTest, XattrReadOnly) { +// Do not allow save/restore cycles after making the test file read-only, as +// the restore will fail to open it with r/w permissions. +TEST_F(XattrTest, XattrReadOnly_NoRandomSave) { // Drop capabilities that allow us to override file and directory permissions. ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false)); ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false)); const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; char val = 'a'; size_t size = sizeof(val); - // TODO(b/127675828): Support setxattr and getxattr. - if (!IsRunningOnGvisor()) { - EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), - SyscallSucceeds()); - } + EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds()); + DisableSave ds; ASSERT_NO_ERRNO(testing::Chmod(test_file_name_, S_IRUSR)); EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallFailsWithErrno(EACCES)); - // TODO(b/127675828): Support setxattr and getxattr. - if (!IsRunningOnGvisor()) { - char buf = '-'; - EXPECT_THAT(getxattr(path, name, &buf, size), - SyscallSucceedsWithValue(size)); - EXPECT_EQ(buf, val); - } + char buf = '-'; + EXPECT_THAT(getxattr(path, name, &buf, size), SyscallSucceedsWithValue(size)); + EXPECT_EQ(buf, val); } -TEST_F(XattrTest, XattrWriteOnly) { +// Do not allow save/restore cycles after making the test file write-only, as +// the restore will fail to open it with r/w permissions. +TEST_F(XattrTest, XattrWriteOnly_NoRandomSave) { // Drop capabilities that allow us to override file and directory permissions. ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false)); ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false)); + DisableSave ds; ASSERT_NO_ERRNO(testing::Chmod(test_file_name_, S_IWUSR)); const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; char val = 'a'; size_t size = sizeof(val); - // TODO(b/127675828): Support setxattr and getxattr. - if (!IsRunningOnGvisor()) { - EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), - SyscallSucceeds()); - } + EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds()); EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(EACCES)); } TEST_F(XattrTest, XattrTrustedWithNonadmin) { - // TODO(b/127675828): Support setxattr and getxattr. + // TODO(b/148380782): Support setxattr and getxattr with "trusted" prefix. SKIP_IF(IsRunningOnGvisor()); SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); @@ -147,11 +143,8 @@ TEST_F(XattrTest, XattrTrustedWithNonadmin) { } TEST_F(XattrTest, XattrOnDirectory) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); - char name[] = "user.abc"; + const char name[] = "user.test"; EXPECT_THAT(setxattr(dir.path().c_str(), name, NULL, 0, /*flags=*/0), SyscallSucceeds()); EXPECT_THAT(getxattr(dir.path().c_str(), name, NULL, 0), @@ -159,13 +152,10 @@ TEST_F(XattrTest, XattrOnDirectory) { } TEST_F(XattrTest, XattrOnSymlink) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); TempPath link = ASSERT_NO_ERRNO_AND_VALUE( TempPath::CreateSymlinkTo(dir.path(), test_file_name_)); - char name[] = "user.abc"; + const char name[] = "user.test"; EXPECT_THAT(setxattr(link.path().c_str(), name, NULL, 0, /*flags=*/0), SyscallSucceeds()); EXPECT_THAT(getxattr(link.path().c_str(), name, NULL, 0), @@ -173,7 +163,7 @@ TEST_F(XattrTest, XattrOnSymlink) { } TEST_F(XattrTest, XattrOnInvalidFileTypes) { - char name[] = "user.abc"; + const char name[] = "user.test"; char char_device[] = "/dev/zero"; EXPECT_THAT(setxattr(char_device, name, NULL, 0, /*flags=*/0), @@ -191,11 +181,8 @@ TEST_F(XattrTest, XattrOnInvalidFileTypes) { } TEST_F(XattrTest, SetxattrSizeSmallerThanValue) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; std::vector<char> val = {'a', 'a'}; size_t size = 1; EXPECT_THAT(setxattr(path, name, val.data(), size, /*flags=*/0), @@ -209,11 +196,8 @@ TEST_F(XattrTest, SetxattrSizeSmallerThanValue) { } TEST_F(XattrTest, SetxattrZeroSize) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; char val = 'a'; EXPECT_THAT(setxattr(path, name, &val, 0, /*flags=*/0), SyscallSucceeds()); @@ -225,7 +209,7 @@ TEST_F(XattrTest, SetxattrZeroSize) { TEST_F(XattrTest, SetxattrSizeTooLarge) { const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; // Note that each particular fs implementation may stipulate a lower size // limit, in which case we actually may fail (e.g. error with ENOSPC) for @@ -235,43 +219,29 @@ TEST_F(XattrTest, SetxattrSizeTooLarge) { EXPECT_THAT(setxattr(path, name, val.data(), size, /*flags=*/0), SyscallFailsWithErrno(E2BIG)); - // TODO(b/127675828): Support setxattr and getxattr. - if (!IsRunningOnGvisor()) { - EXPECT_THAT(getxattr(path, name, nullptr, 0), - SyscallFailsWithErrno(ENODATA)); - } + EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENODATA)); } TEST_F(XattrTest, SetxattrNullValueAndNonzeroSize) { const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; EXPECT_THAT(setxattr(path, name, nullptr, 1, /*flags=*/0), SyscallFailsWithErrno(EFAULT)); - // TODO(b/127675828): Support setxattr and getxattr. - if (!IsRunningOnGvisor()) { - EXPECT_THAT(getxattr(path, name, nullptr, 0), - SyscallFailsWithErrno(ENODATA)); - } + EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENODATA)); } TEST_F(XattrTest, SetxattrNullValueAndZeroSize) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0), SyscallSucceeds()); EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallSucceedsWithValue(0)); } TEST_F(XattrTest, SetxattrValueTooLargeButOKSize) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; std::vector<char> val(XATTR_SIZE_MAX + 1); std::fill(val.begin(), val.end(), 'a'); size_t size = 1; @@ -286,11 +256,8 @@ TEST_F(XattrTest, SetxattrValueTooLargeButOKSize) { } TEST_F(XattrTest, SetxattrReplaceWithSmaller) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; std::vector<char> val = {'a', 'a'}; EXPECT_THAT(setxattr(path, name, val.data(), 2, /*flags=*/0), SyscallSucceeds()); @@ -304,11 +271,8 @@ TEST_F(XattrTest, SetxattrReplaceWithSmaller) { } TEST_F(XattrTest, SetxattrReplaceWithLarger) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; std::vector<char> val = {'a', 'a'}; EXPECT_THAT(setxattr(path, name, val.data(), 1, /*flags=*/0), SyscallSucceeds()); @@ -321,11 +285,8 @@ TEST_F(XattrTest, SetxattrReplaceWithLarger) { } TEST_F(XattrTest, SetxattrCreateFlag) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; EXPECT_THAT(setxattr(path, name, nullptr, 0, XATTR_CREATE), SyscallSucceeds()); EXPECT_THAT(setxattr(path, name, nullptr, 0, XATTR_CREATE), @@ -335,11 +296,8 @@ TEST_F(XattrTest, SetxattrCreateFlag) { } TEST_F(XattrTest, SetxattrReplaceFlag) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; EXPECT_THAT(setxattr(path, name, nullptr, 0, XATTR_REPLACE), SyscallFailsWithErrno(ENODATA)); EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0), SyscallSucceeds()); @@ -357,11 +315,8 @@ TEST_F(XattrTest, SetxattrInvalidFlags) { } TEST_F(XattrTest, Getxattr) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; int val = 1234; size_t size = sizeof(val); EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds()); @@ -372,11 +327,8 @@ TEST_F(XattrTest, Getxattr) { } TEST_F(XattrTest, GetxattrSizeSmallerThanValue) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; std::vector<char> val = {'a', 'a'}; size_t size = val.size(); EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds()); @@ -387,11 +339,8 @@ TEST_F(XattrTest, GetxattrSizeSmallerThanValue) { } TEST_F(XattrTest, GetxattrSizeLargerThanValue) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; char val = 'a'; EXPECT_THAT(setxattr(path, name, &val, 1, /*flags=*/0), SyscallSucceeds()); @@ -405,11 +354,8 @@ TEST_F(XattrTest, GetxattrSizeLargerThanValue) { } TEST_F(XattrTest, GetxattrZeroSize) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; char val = 'a'; EXPECT_THAT(setxattr(path, name, &val, sizeof(val), /*flags=*/0), SyscallSucceeds()); @@ -421,11 +367,8 @@ TEST_F(XattrTest, GetxattrZeroSize) { } TEST_F(XattrTest, GetxattrSizeTooLarge) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; char val = 'a'; EXPECT_THAT(setxattr(path, name, &val, sizeof(val), /*flags=*/0), SyscallSucceeds()); @@ -440,11 +383,8 @@ TEST_F(XattrTest, GetxattrSizeTooLarge) { } TEST_F(XattrTest, GetxattrNullValue) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; char val = 'a'; size_t size = sizeof(val); EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds()); @@ -454,11 +394,8 @@ TEST_F(XattrTest, GetxattrNullValue) { } TEST_F(XattrTest, GetxattrNullValueAndZeroSize) { - // TODO(b/127675828): Support setxattr and getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - char name[] = "user.abc"; + const char name[] = "user.test"; char val = 'a'; size_t size = sizeof(val); // Set value with zero size. @@ -473,15 +410,51 @@ TEST_F(XattrTest, GetxattrNullValueAndZeroSize) { } TEST_F(XattrTest, GetxattrNonexistentName) { - // TODO(b/127675828): Support getxattr. - SKIP_IF(IsRunningOnGvisor()); - const char* path = test_file_name_.c_str(); - std::string name = "user.nonexistent"; - EXPECT_THAT(getxattr(path, name.c_str(), nullptr, 0), + const char name[] = "user.test"; + EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENODATA)); +} + +TEST_F(XattrTest, LGetSetxattrOnSymlink) { + TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + TempPath link = ASSERT_NO_ERRNO_AND_VALUE( + TempPath::CreateSymlinkTo(dir.path(), test_file_name_)); + + EXPECT_THAT(lsetxattr(link.path().c_str(), nullptr, nullptr, 0, 0), + SyscallFailsWithErrno(EPERM)); + EXPECT_THAT(lgetxattr(link.path().c_str(), nullptr, nullptr, 0), SyscallFailsWithErrno(ENODATA)); } +TEST_F(XattrTest, LGetSetxattrOnNonsymlink) { + const char* path = test_file_name_.c_str(); + const char name[] = "user.test"; + int val = 1234; + size_t size = sizeof(val); + EXPECT_THAT(lsetxattr(path, name, &val, size, /*flags=*/0), + SyscallSucceeds()); + + int buf = 0; + EXPECT_THAT(lgetxattr(path, name, &buf, size), + SyscallSucceedsWithValue(size)); + EXPECT_EQ(buf, val); +} + +TEST_F(XattrTest, FGetSetxattr) { + const FileDescriptor fd = + ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_.c_str(), 0)); + const char name[] = "user.test"; + int val = 1234; + size_t size = sizeof(val); + EXPECT_THAT(fsetxattr(fd.get(), name, &val, size, /*flags=*/0), + SyscallSucceeds()); + + int buf = 0; + EXPECT_THAT(fgetxattr(fd.get(), name, &buf, size), + SyscallSucceedsWithValue(size)); + EXPECT_EQ(buf, val); +} + } // namespace } // namespace testing diff --git a/test/uds/BUILD b/test/uds/BUILD index a3843e699..51e2c7ce8 100644 --- a/test/uds/BUILD +++ b/test/uds/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("//tools:defs.bzl", "go_library") package( default_visibility = ["//:sandbox"], @@ -9,7 +9,6 @@ go_library( name = "uds", testonly = 1, srcs = ["uds.go"], - importpath = "gvisor.dev/gvisor/test/uds", deps = [ "//pkg/log", "//pkg/unet", diff --git a/test/util/BUILD b/test/util/BUILD index cbc728159..3c732be62 100644 --- a/test/util/BUILD +++ b/test/util/BUILD @@ -1,5 +1,4 @@ -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//test/syscalls:build_defs.bzl", "select_for_linux") +load("//tools:defs.bzl", "cc_library", "cc_test", "select_system") package( default_visibility = ["//:sandbox"], @@ -142,12 +141,13 @@ cc_library( cc_library( name = "save_util", testonly = 1, - srcs = ["save_util.cc"] + - select_for_linux( - ["save_util_linux.cc"], - ["save_util_other.cc"], - ), + srcs = [ + "save_util.cc", + "save_util_linux.cc", + "save_util_other.cc", + ], hdrs = ["save_util.h"], + defines = select_system(), ) cc_library( @@ -234,13 +234,16 @@ cc_library( testonly = 1, srcs = [ "test_util.cc", - ] + select_for_linux( - [ - "test_util_impl.cc", - "test_util_runfiles.cc", + "test_util_impl.cc", + "test_util_runfiles.cc", + ], + hdrs = ["test_util.h"], + defines = select_system( + fuchsia = [ + "__opensource__", + "__fuchsia__", ], ), - hdrs = ["test_util.h"], deps = [ ":fs_util", ":logging", diff --git a/test/util/mount_util.h b/test/util/mount_util.h index 484de560e..23eea51a2 100644 --- a/test/util/mount_util.h +++ b/test/util/mount_util.h @@ -33,8 +33,8 @@ namespace testing { // destroyed. inline PosixErrorOr<Cleanup> Mount(const std::string &source, const std::string &target, - const std::string &fstype, uint64_t mountflags, - const std::string &data, + const std::string &fstype, + uint64_t mountflags, const std::string &data, uint64_t umountflags) { if (mount(source.c_str(), target.c_str(), fstype.c_str(), mountflags, data.c_str()) == -1) { diff --git a/test/util/multiprocess_util.h b/test/util/multiprocess_util.h index 61526b4e7..3e736261b 100644 --- a/test/util/multiprocess_util.h +++ b/test/util/multiprocess_util.h @@ -103,7 +103,8 @@ inline PosixErrorOr<Cleanup> ForkAndExec(const std::string& filename, } // Equivalent to ForkAndExec, except using dirfd and flags with execveat. -PosixErrorOr<Cleanup> ForkAndExecveat(int32_t dirfd, const std::string& pathname, +PosixErrorOr<Cleanup> ForkAndExecveat(int32_t dirfd, + const std::string& pathname, const ExecveArray& argv, const ExecveArray& envv, int flags, const std::function<void()>& fn, diff --git a/test/util/save_util_linux.cc b/test/util/save_util_linux.cc index 7a0f14342..d0aea8e6a 100644 --- a/test/util/save_util_linux.cc +++ b/test/util/save_util_linux.cc @@ -12,22 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. +#ifdef __linux__ + #include <errno.h> #include <sys/syscall.h> #include <unistd.h> #include "test/util/save_util.h" +#if defined(__x86_64__) || defined(__i386__) +#define SYS_TRIGGER_SAVE SYS_create_module +#elif defined(__aarch64__) +#define SYS_TRIGGER_SAVE SYS_finit_module +#else +#error "Unknown architecture" +#endif + namespace gvisor { namespace testing { void MaybeSave() { if (internal::ShouldSave()) { int orig_errno = errno; - syscall(SYS_create_module, nullptr, 0); + // We use it to trigger saving the sentry state + // when this syscall is called. + // Notice: this needs to be a valid syscall + // that is not used in any of the syscall tests. + syscall(SYS_TRIGGER_SAVE, nullptr, 0); errno = orig_errno; } } } // namespace testing } // namespace gvisor + +#endif diff --git a/test/util/save_util_other.cc b/test/util/save_util_other.cc index 1aca663b7..931af2c29 100644 --- a/test/util/save_util_other.cc +++ b/test/util/save_util_other.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#ifndef __linux__ + namespace gvisor { namespace testing { @@ -21,3 +23,5 @@ void MaybeSave() { } // namespace testing } // namespace gvisor + +#endif diff --git a/test/util/test_util_runfiles.cc b/test/util/test_util_runfiles.cc index 7210094eb..694d21692 100644 --- a/test/util/test_util_runfiles.cc +++ b/test/util/test_util_runfiles.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#ifndef __fuchsia__ + #include <iostream> #include <string> @@ -44,3 +46,5 @@ std::string RunfilePath(std::string path) { } // namespace testing } // namespace gvisor + +#endif // __fuchsia__ |