Add CloseAllFDsExcept test.

Move VecStringToCharPtrArr before fork, so that it cannot deadlock when other thread holds allocation lock.

PiperOrigin-RevId: 414661912
Change-Id: Ie8aa5c36693e6f86c69d67a1da51b7e7ff1ec30b
This commit is contained in:
Wiktor Garbacz 2021-12-07 02:22:46 -08:00 committed by Copybara-Service
parent 4061666f44
commit 8562306c97
6 changed files with 90 additions and 5 deletions

View File

@ -774,7 +774,10 @@ cc_test(
name = "sanitizer_test", name = "sanitizer_test",
srcs = ["sanitizer_test.cc"], srcs = ["sanitizer_test.cc"],
copts = sapi_platform_copts(), copts = sapi_platform_copts(),
data = ["//sandboxed_api/sandbox2/testcases:sanitizer"], data = [
"//sandboxed_api/sandbox2/testcases:close_fds",
"//sandboxed_api/sandbox2/testcases:sanitizer",
],
tags = ["no_qemu_user_mode"], tags = ["no_qemu_user_mode"],
deps = [ deps = [
":comms", ":comms",

View File

@ -874,6 +874,7 @@ if(SAPI_ENABLE_TESTS)
) )
add_dependencies(sandbox2_sanitizer_test add_dependencies(sandbox2_sanitizer_test
sandbox2::testcase_sanitizer sandbox2::testcase_sanitizer
sandbox2::testcase_close_fds
) )
target_link_libraries(sandbox2_sanitizer_test PRIVATE target_link_libraries(sandbox2_sanitizer_test PRIVATE
absl::memory absl::memory

View File

@ -15,7 +15,6 @@
#include "sandboxed_api/sandbox2/sanitizer.h" #include "sandboxed_api/sandbox2/sanitizer.h"
#include <fcntl.h> #include <fcntl.h>
#include <linux/fs.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
@ -45,8 +44,6 @@
using ::sapi::GetTestSourcePath; using ::sapi::GetTestSourcePath;
using ::testing::Eq; using ::testing::Eq;
using ::testing::Gt; using ::testing::Gt;
using ::testing::IsFalse;
using ::testing::IsTrue;
using ::testing::Ne; using ::testing::Ne;
namespace sandbox2 { namespace sandbox2 {
@ -59,12 +56,13 @@ int RunTestcase(const std::string& path, const std::vector<std::string>& args) {
PLOG(ERROR) << "fork()"; PLOG(ERROR) << "fork()";
return 1; return 1;
} }
const char** argv = util::VecStringToCharPtrArr(args);
if (pid == 0) { if (pid == 0) {
const char** argv = util::VecStringToCharPtrArr(args);
execv(path.c_str(), const_cast<char**>(argv)); execv(path.c_str(), const_cast<char**>(argv));
PLOG(ERROR) << "execv('" << path << "')"; PLOG(ERROR) << "execv('" << path << "')";
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
delete[] argv;
for (;;) { for (;;) {
int status; int status;
@ -135,6 +133,26 @@ TEST(SanitizerTest, TestSandboxedBinary) {
EXPECT_THAT(result.reason_code(), Eq(0)); EXPECT_THAT(result.reason_code(), Eq(0));
} }
// Test that sanitizer::CloseAllFDsExcept() closes all file descriptors except
// the ones listed.
TEST(SanitizerTest, TestCloseFDs) {
// Open a few file descriptors in non-close-on-exec mode.
int sock_fd[2];
ASSERT_THAT(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fd), Ne(-1));
ASSERT_THAT(open("/dev/full", O_RDONLY), Ne(-1));
int null_fd = open("/dev/null", O_RDWR);
ASSERT_THAT(null_fd, Ne(-1));
const std::string path = GetTestSourcePath("sandbox2/testcases/close_fds");
std::vector<std::string> args;
std::vector<int> exceptions = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
null_fd};
for (auto fd : exceptions) {
args.push_back(absl::StrCat(fd));
}
EXPECT_THAT(RunTestcase(path, args), Eq(0));
}
TEST(SanitizerTest, TestGetProcStatusLine) { TEST(SanitizerTest, TestGetProcStatusLine) {
// Test indirectly, GetNumberOfThreads() looks for the "Threads" value. // Test indirectly, GetNumberOfThreads() looks for the "Threads" value.
EXPECT_THAT(sanitizer::GetNumberOfThreads(getpid()), Gt(0)); EXPECT_THAT(sanitizer::GetNumberOfThreads(getpid()), Gt(0));

View File

@ -164,6 +164,19 @@ cc_binary(
linkstatic = 1, linkstatic = 1,
) )
cc_binary(
name = "close_fds",
testonly = 1,
srcs = ["close_fds.cc"],
copts = sapi_platform_copts(),
deps = [
"//sandboxed_api/sandbox2:sanitizer",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/strings",
"@com_google_glog//:glog",
],
)
# security: disable=cc-static-no-pie # security: disable=cc-static-no-pie
cc_binary( cc_binary(
name = "sleep", name = "sleep",

View File

@ -185,6 +185,24 @@ target_link_libraries(sandbox2_testcase_sanitizer PRIVATE
${_sandbox2_linkopts} ${_sandbox2_linkopts}
) )
# sandboxed_api/sandbox2/testcases:close_fds
add_executable(sandbox2_testcase_close_fds
close_fds.cc
)
add_executable(sandbox2::testcase_close_fds ALIAS sandbox2_testcase_close_fds)
set_target_properties(sandbox2_testcase_close_fds PROPERTIES
OUTPUT_NAME close_fds
)
target_link_libraries(sandbox2_testcase_close_fds PRIVATE
sapi::base
${_sandbox2_linkopts}
absl::strings
absl::flat_hash_set
glog::glog
sandbox2::sanitizer
)
# sandboxed_api/sandbox2/testcases:sleep # sandboxed_api/sandbox2/testcases:sleep
add_executable(sandbox2_testcase_sleep add_executable(sandbox2_testcase_sleep
sleep.cc sleep.cc

View File

@ -0,0 +1,32 @@
#include <fcntl.h>
#include <linux/fs.h>
#include <unistd.h>
#include <cerrno>
#include <glog/logging.h>
#include "absl/container/flat_hash_set.h"
#include "absl/strings/numbers.h"
#include "sandboxed_api/sandbox2/sanitizer.h"
bool IsFdOpen(int fd) {
int ret = fcntl(fd, F_GETFD);
if (ret == -1) {
CHECK(errno == EBADF);
return false;
}
return true;
}
int main(int argc, char* argv[]) {
absl::flat_hash_set<int> exceptions;
for (int i = 0; i < argc; ++i) {
int fd;
CHECK(absl::SimpleAtoi(argv[i], &fd));
exceptions.insert(fd);
}
CHECK(sandbox2::sanitizer::CloseAllFDsExcept(exceptions).ok());
for (int i = 0; i < INR_OPEN_MAX; i++) {
CHECK_EQ(IsFdOpen(i), exceptions.find(i) != exceptions.end());
}
}