sandboxed-api/sandboxed_api/sandbox2/util_test.cc

171 lines
5.4 KiB
C++

// Copyright 2019 Google LLC
//
// 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
//
// https://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 "sandboxed_api/sandbox2/util.h"
#include <sched.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/cleanup/cleanup.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "sandboxed_api/util/status_matchers.h"
namespace sandbox2::util {
namespace {
using ::sapi::IsOk;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Gt;
using ::testing::IsEmpty;
using ::testing::IsTrue;
using ::testing::Ne;
using ::testing::Not;
using ::testing::StrEq;
constexpr absl::string_view kTestString = "This is a test string";
TEST(UtilTest, TestCreateMemFd) {
int fd = 0;
ASSERT_THAT(CreateMemFd(&fd), IsTrue());
EXPECT_THAT(fd, Gt(1));
close(fd);
}
TEST(CharPtrArrayTest, FromStringVector) {
std::vector<std::string> strings = {"a", "b", "c"};
CharPtrArray array = CharPtrArray::FromStringVector(strings);
EXPECT_THAT(array.ToStringVector(), Eq(strings));
EXPECT_THAT(array.array(),
ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), nullptr));
EXPECT_THAT(array.data(), Eq(array.array().data()));
}
TEST(CharPtrArrayTest, FromCharPtrArray) {
std::vector<std::string> strings = {"a", "b", "c"};
std::vector<char*> string_arr;
for (std::string& s : strings) {
string_arr.push_back(s.data());
}
string_arr.push_back(nullptr);
CharPtrArray array(string_arr.data());
EXPECT_THAT(array.ToStringVector(), Eq(strings));
EXPECT_THAT(array.array(),
ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), nullptr));
EXPECT_THAT(array.data(), Eq(array.array().data()));
}
TEST(GetProcStatusLineTest, Pid) {
std::string line = GetProcStatusLine(getpid(), "Pid");
EXPECT_THAT(line, Eq(absl::StrCat(getpid())));
}
TEST(GetProcStatusLineTest, NonExisting) {
std::string line =
GetProcStatusLine(getpid(), "__N_o_n_ExistingStatusSetting");
EXPECT_THAT(line, IsEmpty());
}
TEST(ForkWithFlagsTest, DoesForkNormally) {
int pfds[2];
ASSERT_THAT(pipe(pfds), Eq(0));
pid_t child = ForkWithFlags(SIGCHLD);
ASSERT_THAT(child, Ne(-1));
if (child == 0) {
char c = 'a';
if (!write(pfds[1], &c, 1)) {
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
close(pfds[1]);
char c = ' ';
EXPECT_THAT(read(pfds[0], &c, 1), Eq(1));
close(pfds[0]);
EXPECT_THAT(c, Eq('a'));
int status;
ASSERT_THAT(TEMP_FAILURE_RETRY(waitpid(child, &status, 0)), Eq(child));
EXPECT_TRUE(WIFEXITED(status));
EXPECT_THAT(WEXITSTATUS(status), Eq(0));
}
TEST(ForkWithFlagsTest, UnsupportedFlag) {
EXPECT_THAT(ForkWithFlags(CLONE_CHILD_CLEARTID), Eq(-1));
}
TEST(ReadCPathFromPidSplitPageTest, Normal) {
std::string test_str(kTestString);
absl::StatusOr<std::string> read =
ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(test_str.data()));
ASSERT_THAT(read, IsOk());
EXPECT_THAT(*read, Eq(kTestString));
}
TEST(ReadCPathFromPidSplitPageTest, Overlong) {
std::string test_str(PATH_MAX + 1, 'a');
absl::StatusOr<std::string> read =
ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(test_str.data()));
EXPECT_THAT(read, Not(IsOk()));
}
TEST(ReadCPathFromPidSplitPageTest, SplitPage) {
const uintptr_t page_size = getpagesize();
char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
ASSERT_THAT(res, Ne(MAP_FAILED));
absl::Cleanup cleanup = [res, page_size]() {
ASSERT_THAT(munmap(res, 2 * page_size), Eq(0));
};
char* str = &res[page_size - kTestString.size() / 2];
memcpy(str, kTestString.data(), kTestString.size());
absl::StatusOr<std::string> read =
ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(str));
ASSERT_THAT(read, IsOk());
EXPECT_THAT(*read, Eq(kTestString));
}
TEST(ReadCPathFromPidSplitPageTest, NearUnreadableMemory) {
const uintptr_t page_size = getpagesize();
char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
ASSERT_THAT(res, Ne(MAP_FAILED));
absl::Cleanup cleanup = [res, page_size]() {
ASSERT_THAT(munmap(res, 2 * page_size), Eq(0));
};
ASSERT_THAT(mprotect(&res[page_size], page_size, PROT_NONE), Eq(0));
char* str = &res[page_size - kTestString.size() - 1];
memcpy(str, kTestString.data(), kTestString.size());
absl::StatusOr<std::string> read =
ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(str));
ASSERT_THAT(read, IsOk());
EXPECT_THAT(*read, Eq(kTestString));
}
} // namespace
} // namespace sandbox2::util