mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Create platform_util for tests.
PiperOrigin-RevId: 291869423
This commit is contained in:
committed by
gVisor bot
parent
2a2da5be31
commit
5d569408ef
@@ -15,10 +15,12 @@
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "test/util/memory_util.h"
|
||||
#include "test/util/platform_util.h"
|
||||
#include "test/util/posix_error.h"
|
||||
#include "test/util/test_util.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#ifndef __x86_64__
|
||||
#error "This test is x86-64 specific."
|
||||
@@ -30,7 +32,6 @@ namespace testing {
|
||||
namespace {
|
||||
|
||||
constexpr char kInt3 = '\xcc';
|
||||
|
||||
constexpr char kInt80[2] = {'\xcd', '\x80'};
|
||||
constexpr char kSyscall[2] = {'\x0f', '\x05'};
|
||||
constexpr char kSysenter[2] = {'\x0f', '\x34'};
|
||||
@@ -43,6 +44,7 @@ void ExitGroup32(const char instruction[2], int code) {
|
||||
// Fill with INT 3 in case we execute too far.
|
||||
memset(m.ptr(), kInt3, m.len());
|
||||
|
||||
// Copy in the actual instruction.
|
||||
memcpy(m.ptr(), instruction, 2);
|
||||
|
||||
// We're playing *extremely* fast-and-loose with the various syscall ABIs
|
||||
@@ -78,70 +80,87 @@ void ExitGroup32(const char instruction[2], int code) {
|
||||
constexpr int kExitCode = 42;
|
||||
|
||||
TEST(Syscall32Bit, Int80) {
|
||||
switch (GvisorPlatform()) {
|
||||
case Platform::kKVM:
|
||||
// TODO(b/111805002): 32-bit segments are broken (but not explictly
|
||||
// disabled).
|
||||
return;
|
||||
case Platform::kPtrace:
|
||||
// TODO(gvisor.dev/issue/167): The ptrace platform does not have a
|
||||
// consistent story here.
|
||||
return;
|
||||
case Platform::kNative:
|
||||
switch (PlatformSupport32Bit()) {
|
||||
case PlatformSupport::NotSupported:
|
||||
break;
|
||||
case PlatformSupport::Segfault:
|
||||
EXPECT_EXIT(ExitGroup32(kInt80, kExitCode),
|
||||
::testing::KilledBySignal(SIGSEGV), "");
|
||||
break;
|
||||
|
||||
case PlatformSupport::Ignored:
|
||||
// Since the call is ignored, we'll hit the int3 trap.
|
||||
EXPECT_EXIT(ExitGroup32(kInt80, kExitCode),
|
||||
::testing::KilledBySignal(SIGTRAP), "");
|
||||
break;
|
||||
|
||||
case PlatformSupport::Allowed:
|
||||
EXPECT_EXIT(ExitGroup32(kInt80, kExitCode), ::testing::ExitedWithCode(42),
|
||||
"");
|
||||
break;
|
||||
}
|
||||
|
||||
// Upstream Linux. 32-bit syscalls allowed.
|
||||
EXPECT_EXIT(ExitGroup32(kInt80, kExitCode), ::testing::ExitedWithCode(42),
|
||||
"");
|
||||
}
|
||||
|
||||
TEST(Syscall32Bit, Sysenter) {
|
||||
switch (GvisorPlatform()) {
|
||||
case Platform::kKVM:
|
||||
// TODO(b/111805002): See above.
|
||||
return;
|
||||
case Platform::kPtrace:
|
||||
// TODO(gvisor.dev/issue/167): See above.
|
||||
return;
|
||||
case Platform::kNative:
|
||||
break;
|
||||
}
|
||||
|
||||
if (GetCPUVendor() == CPUVendor::kAMD) {
|
||||
if (PlatformSupport32Bit() == PlatformSupport::Allowed &&
|
||||
GetCPUVendor() == CPUVendor::kAMD) {
|
||||
// SYSENTER is an illegal instruction in compatibility mode on AMD.
|
||||
EXPECT_EXIT(ExitGroup32(kSysenter, kExitCode),
|
||||
::testing::KilledBySignal(SIGILL), "");
|
||||
return;
|
||||
}
|
||||
|
||||
// Upstream Linux on !AMD, 32-bit syscalls allowed.
|
||||
EXPECT_EXIT(ExitGroup32(kSysenter, kExitCode), ::testing::ExitedWithCode(42),
|
||||
"");
|
||||
switch (PlatformSupport32Bit()) {
|
||||
case PlatformSupport::NotSupported:
|
||||
break;
|
||||
|
||||
case PlatformSupport::Segfault:
|
||||
EXPECT_EXIT(ExitGroup32(kSysenter, kExitCode),
|
||||
::testing::KilledBySignal(SIGSEGV), "");
|
||||
break;
|
||||
|
||||
case PlatformSupport::Ignored:
|
||||
// See above, except expected code is SIGSEGV.
|
||||
EXPECT_EXIT(ExitGroup32(kSysenter, kExitCode),
|
||||
::testing::KilledBySignal(SIGSEGV), "");
|
||||
break;
|
||||
|
||||
case PlatformSupport::Allowed:
|
||||
EXPECT_EXIT(ExitGroup32(kSysenter, kExitCode),
|
||||
::testing::ExitedWithCode(42), "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Syscall32Bit, Syscall) {
|
||||
switch (GvisorPlatform()) {
|
||||
case Platform::kKVM:
|
||||
// TODO(b/111805002): See above.
|
||||
return;
|
||||
case Platform::kPtrace:
|
||||
// TODO(gvisor.dev/issue/167): See above.
|
||||
return;
|
||||
case Platform::kNative:
|
||||
break;
|
||||
}
|
||||
|
||||
if (GetCPUVendor() == CPUVendor::kIntel) {
|
||||
if (PlatformSupport32Bit() == PlatformSupport::Allowed &&
|
||||
GetCPUVendor() == CPUVendor::kIntel) {
|
||||
// SYSCALL is an illegal instruction in compatibility mode on Intel.
|
||||
EXPECT_EXIT(ExitGroup32(kSyscall, kExitCode),
|
||||
::testing::KilledBySignal(SIGILL), "");
|
||||
return;
|
||||
}
|
||||
|
||||
// Upstream Linux on !Intel, 32-bit syscalls allowed.
|
||||
EXPECT_EXIT(ExitGroup32(kSyscall, kExitCode), ::testing::ExitedWithCode(42),
|
||||
"");
|
||||
switch (PlatformSupport32Bit()) {
|
||||
case PlatformSupport::NotSupported:
|
||||
break;
|
||||
|
||||
case PlatformSupport::Segfault:
|
||||
EXPECT_EXIT(ExitGroup32(kSyscall, kExitCode),
|
||||
::testing::KilledBySignal(SIGSEGV), "");
|
||||
break;
|
||||
|
||||
case PlatformSupport::Ignored:
|
||||
// See above.
|
||||
EXPECT_EXIT(ExitGroup32(kSyscall, kExitCode),
|
||||
::testing::KilledBySignal(SIGILL), "");
|
||||
break;
|
||||
|
||||
case PlatformSupport::Allowed:
|
||||
EXPECT_EXIT(ExitGroup32(kSyscall, kExitCode),
|
||||
::testing::ExitedWithCode(42), "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Far call code called below.
|
||||
@@ -205,19 +224,20 @@ void FarCall32() {
|
||||
}
|
||||
|
||||
TEST(Call32Bit, Disallowed) {
|
||||
switch (GvisorPlatform()) {
|
||||
case Platform::kKVM:
|
||||
// TODO(b/111805002): See above.
|
||||
return;
|
||||
case Platform::kPtrace:
|
||||
// The ptrace platform cannot prevent switching to compatibility mode.
|
||||
ABSL_FALLTHROUGH_INTENDED;
|
||||
case Platform::kNative:
|
||||
switch (PlatformSupport32Bit()) {
|
||||
case PlatformSupport::NotSupported:
|
||||
break;
|
||||
}
|
||||
|
||||
// Shouldn't crash.
|
||||
FarCall32();
|
||||
case PlatformSupport::Segfault:
|
||||
EXPECT_EXIT(FarCall32(), ::testing::KilledBySignal(SIGSEGV), "");
|
||||
break;
|
||||
|
||||
case PlatformSupport::Ignored:
|
||||
ABSL_FALLTHROUGH_INTENDED;
|
||||
case PlatformSupport::Allowed:
|
||||
// Shouldn't crash.
|
||||
FarCall32();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -197,9 +197,11 @@ cc_binary(
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
"//test/util:memory_util",
|
||||
"//test/util:platform_util",
|
||||
"//test/util:posix_error",
|
||||
"//test/util:test_main",
|
||||
"//test/util:test_util",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_googletest//:gtest",
|
||||
],
|
||||
)
|
||||
@@ -479,6 +481,7 @@ cc_binary(
|
||||
srcs = ["concurrency.cc"],
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
"//test/util:platform_util",
|
||||
"//test/util:test_main",
|
||||
"//test/util:test_util",
|
||||
"//test/util:thread_util",
|
||||
@@ -584,6 +587,7 @@ cc_binary(
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
"//test/util:logging",
|
||||
"//test/util:platform_util",
|
||||
"//test/util:signal_util",
|
||||
"//test/util:test_main",
|
||||
"//test/util:test_util",
|
||||
@@ -1658,6 +1662,7 @@ cc_binary(
|
||||
deps = [
|
||||
"//test/util:logging",
|
||||
"//test/util:multiprocess_util",
|
||||
"//test/util:platform_util",
|
||||
"//test/util:signal_util",
|
||||
"//test/util:test_util",
|
||||
"//test/util:thread_util",
|
||||
|
||||
@@ -14,10 +14,8 @@
|
||||
|
||||
#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.
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "test/util/platform_util.h"
|
||||
#include "test/util/test_util.h"
|
||||
#include "test/util/thread_util.h"
|
||||
|
||||
@@ -99,6 +100,7 @@ TEST(ConcurrencyTest, MultiProcessMultithreaded) {
|
||||
// Test that multiple processes can execute concurrently, even if one process
|
||||
// never yields.
|
||||
TEST(ConcurrencyTest, MultiProcessConcurrency) {
|
||||
SKIP_IF(PlatformSupportMultiProcess() == PlatformSupport::NotSupported);
|
||||
|
||||
pid_t child_pid = fork();
|
||||
if (child_pid == 0) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/util/logging.h"
|
||||
#include "test/util/platform_util.h"
|
||||
#include "test/util/signal_util.h"
|
||||
#include "test/util/test_util.h"
|
||||
|
||||
@@ -324,6 +325,7 @@ TEST(ExceptionTest, AlignmentHalt) {
|
||||
}
|
||||
|
||||
TEST(ExceptionTest, AlignmentCheck) {
|
||||
SKIP_IF(PlatformSupportAlignmentCheck() != PlatformSupport::Allowed);
|
||||
|
||||
// See above.
|
||||
struct sigaction sa = {};
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "absl/time/time.h"
|
||||
#include "test/util/logging.h"
|
||||
#include "test/util/multiprocess_util.h"
|
||||
#include "test/util/platform_util.h"
|
||||
#include "test/util/signal_util.h"
|
||||
#include "test/util/test_util.h"
|
||||
#include "test/util/thread_util.h"
|
||||
@@ -824,13 +825,8 @@ TEST(PtraceTest,
|
||||
// These tests requires knowledge of architecture-specific syscall convention.
|
||||
#ifdef __x86_64__
|
||||
TEST(PtraceTest, Int3) {
|
||||
switch (GvisorPlatform()) {
|
||||
case Platform::kKVM:
|
||||
// TODO(b/124248694): int3 isn't handled properly.
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SKIP_IF(PlatformSupportInt3() == PlatformSupport::NotSupported);
|
||||
|
||||
pid_t const child_pid = fork();
|
||||
if (child_pid == 0) {
|
||||
// In child process.
|
||||
|
||||
+9
-6
@@ -165,6 +165,14 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "platform_util",
|
||||
testonly = 1,
|
||||
srcs = ["platform_util.cc"],
|
||||
hdrs = ["platform_util.h"],
|
||||
deps = [":test_util"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "posix_error",
|
||||
testonly = 1,
|
||||
@@ -238,12 +246,7 @@ cc_library(
|
||||
"test_util_runfiles.cc",
|
||||
],
|
||||
hdrs = ["test_util.h"],
|
||||
defines = select_system(
|
||||
fuchsia = [
|
||||
"__opensource__",
|
||||
"__fuchsia__",
|
||||
],
|
||||
),
|
||||
defines = select_system(),
|
||||
deps = [
|
||||
":fs_util",
|
||||
":logging",
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// 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.
|
||||
|
||||
#include "test/util/platform_util.h"
|
||||
|
||||
#include "test/util/test_util.h"
|
||||
|
||||
namespace gvisor {
|
||||
namespace testing {
|
||||
|
||||
PlatformSupport PlatformSupport32Bit() {
|
||||
if (GvisorPlatform() == Platform::kPtrace) {
|
||||
return PlatformSupport::NotSupported;
|
||||
} else if (GvisorPlatform() == Platform::kKVM) {
|
||||
return PlatformSupport::Segfault;
|
||||
} else {
|
||||
return PlatformSupport::Allowed;
|
||||
}
|
||||
}
|
||||
|
||||
PlatformSupport PlatformSupportAlignmentCheck() {
|
||||
return PlatformSupport::Allowed;
|
||||
}
|
||||
|
||||
PlatformSupport PlatformSupportMultiProcess() {
|
||||
return PlatformSupport::Allowed;
|
||||
}
|
||||
|
||||
PlatformSupport PlatformSupportInt3() {
|
||||
if (GvisorPlatform() == Platform::kKVM) {
|
||||
return PlatformSupport::NotSupported;
|
||||
} else {
|
||||
return PlatformSupport::Allowed;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GVISOR_TEST_UTIL_PLATFORM_UTIL_H_
|
||||
#define GVISOR_TEST_UTIL_PLATFORM_UTIL_H_
|
||||
|
||||
namespace gvisor {
|
||||
namespace testing {
|
||||
|
||||
// PlatformSupport is a generic enumeration of classes of support.
|
||||
//
|
||||
// It is up to the individual functions and callers to agree on the precise
|
||||
// definition for each case. The document here generally refers to 32-bit
|
||||
// as an example. Many cases will use only NotSupported and Allowed.
|
||||
enum class PlatformSupport {
|
||||
// The feature is not supported on the current platform.
|
||||
//
|
||||
// In the case of 32-bit, this means that calls will generally be interpreted
|
||||
// as 64-bit calls, and there is no support for 32-bit binaries, long calls,
|
||||
// etc. This usually means that the underlying implementation just pretends
|
||||
// that 32-bit doesn't exist.
|
||||
NotSupported,
|
||||
|
||||
// Calls will be ignored by the kernel with a fixed error.
|
||||
Ignored,
|
||||
|
||||
// Calls will result in a SIGSEGV or similar fault.
|
||||
Segfault,
|
||||
|
||||
// The feature is supported as expected.
|
||||
//
|
||||
// In the case of 32-bit, this means that the system call or far call will be
|
||||
// handled properly.
|
||||
Allowed,
|
||||
};
|
||||
|
||||
PlatformSupport PlatformSupport32Bit();
|
||||
PlatformSupport PlatformSupportAlignmentCheck();
|
||||
PlatformSupport PlatformSupportMultiProcess();
|
||||
PlatformSupport PlatformSupportInt3();
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
#endif // GVISOR_TEST_UTIL_PLATFORM_UTL_H_
|
||||
@@ -45,20 +45,13 @@ namespace testing {
|
||||
|
||||
bool IsRunningOnGvisor() { return GvisorPlatform() != Platform::kNative; }
|
||||
|
||||
Platform GvisorPlatform() {
|
||||
const std::string GvisorPlatform() {
|
||||
// Set by runner.go.
|
||||
char* env = getenv(TEST_ON_GVISOR);
|
||||
if (!env) {
|
||||
return Platform::kNative;
|
||||
}
|
||||
if (strcmp(env, "ptrace") == 0) {
|
||||
return Platform::kPtrace;
|
||||
}
|
||||
if (strcmp(env, "kvm") == 0) {
|
||||
return Platform::kKVM;
|
||||
}
|
||||
std::cerr << "unknown platform " << env;
|
||||
abort();
|
||||
return std::string(env);
|
||||
}
|
||||
|
||||
bool IsRunningWithHostinet() {
|
||||
|
||||
+13
-14
@@ -26,16 +26,13 @@
|
||||
// IsRunningOnGvisor returns true if the test is known to be running on gVisor.
|
||||
// GvisorPlatform can be used to get more detail:
|
||||
//
|
||||
// switch (GvisorPlatform()) {
|
||||
// case Platform::kNative:
|
||||
// case Platform::kGvisor:
|
||||
// EXPECT_THAT(mmap(...), SyscallSucceeds());
|
||||
// break;
|
||||
// case Platform::kPtrace:
|
||||
// EXPECT_THAT(mmap(...), SyscallFailsWithErrno(ENOSYS));
|
||||
// break;
|
||||
// if (GvisorPlatform() == Platform::kPtrace) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// SetupGvisorDeathTest ensures that signal handling does not interfere with
|
||||
/// tests that rely on fatal signals.
|
||||
//
|
||||
// Matchers
|
||||
// ========
|
||||
//
|
||||
@@ -213,13 +210,15 @@ void TestInit(int* argc, char*** argv);
|
||||
if (expr) GTEST_SKIP() << #expr; \
|
||||
} while (0)
|
||||
|
||||
enum class Platform {
|
||||
kNative,
|
||||
kKVM,
|
||||
kPtrace,
|
||||
};
|
||||
// Platform contains platform names.
|
||||
namespace Platform {
|
||||
constexpr char kNative[] = "native";
|
||||
constexpr char kPtrace[] = "ptrace";
|
||||
constexpr char kKVM[] = "kvm";
|
||||
} // namespace Platform
|
||||
|
||||
bool IsRunningOnGvisor();
|
||||
Platform GvisorPlatform();
|
||||
const std::string GvisorPlatform();
|
||||
bool IsRunningWithHostinet();
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
Reference in New Issue
Block a user