mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
37a7432178
PiperOrigin-RevId: 568510723 Change-Id: I517d739e44cb61eec8b0fd9fe6aa473e1bb8ec06
375 lines
10 KiB
C++
375 lines
10 KiB
C++
//
|
|
// 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.
|
|
|
|
// Unittest for the sandbox2::Comms class.
|
|
|
|
#include "sandboxed_api/sandbox2/comms.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <thread> // NOLINT(build/c++11)
|
|
#include <vector>
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
#include "absl/container/fixed_array.h"
|
|
#include "absl/log/check.h"
|
|
#include "absl/log/log.h"
|
|
#include "absl/status/status.h"
|
|
#include "absl/strings/string_view.h"
|
|
#include "sandboxed_api/sandbox2/comms_test.pb.h"
|
|
#include "sandboxed_api/util/status_matchers.h"
|
|
|
|
using ::sapi::IsOk;
|
|
using ::sapi::StatusIs;
|
|
using ::testing::Eq;
|
|
using ::testing::IsFalse;
|
|
using ::testing::IsTrue;
|
|
|
|
namespace sandbox2 {
|
|
|
|
using CommunicationHandler = std::function<void(Comms* comms)>;
|
|
|
|
constexpr char kProtoStr[] = "ABCD";
|
|
static absl::string_view NullTestString() {
|
|
static constexpr char kHelperStr[] = "test\0\n\r\t\x01\x02";
|
|
return absl::string_view(kHelperStr, sizeof(kHelperStr) - 1);
|
|
}
|
|
|
|
// Helper function that handles the communication between the two handler
|
|
// functions.
|
|
void HandleCommunication(const CommunicationHandler& a,
|
|
const CommunicationHandler& b) {
|
|
int sv[2];
|
|
CHECK_NE(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), -1);
|
|
Comms comms(sv[0]);
|
|
|
|
// Start handler a.
|
|
std::thread remote([sv, &a]() {
|
|
Comms my_comms(sv[1]);
|
|
a(&my_comms);
|
|
});
|
|
|
|
// Accept connection and run handler b.
|
|
b(&comms);
|
|
remote.join();
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecv8) {
|
|
auto a = [](Comms* comms) {
|
|
// Send Uint8.
|
|
ASSERT_THAT(comms->SendUint8(192), IsTrue());
|
|
|
|
// Recv Int8.
|
|
int8_t tmp8;
|
|
ASSERT_THAT(comms->RecvInt8(&tmp8), IsTrue());
|
|
EXPECT_THAT(tmp8, Eq(-7));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Recv Uint8.
|
|
uint8_t tmpu8;
|
|
ASSERT_THAT(comms->RecvUint8(&tmpu8), IsTrue());
|
|
EXPECT_THAT(tmpu8, Eq(192));
|
|
|
|
// Send Int8.
|
|
ASSERT_THAT(comms->SendInt8(-7), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecv16) {
|
|
auto a = [](Comms* comms) {
|
|
// Send Uint16.
|
|
ASSERT_THAT(comms->SendUint16(40001), IsTrue());
|
|
|
|
// Recv Int16.
|
|
int16_t tmp16;
|
|
ASSERT_THAT(comms->RecvInt16(&tmp16), IsTrue());
|
|
EXPECT_THAT(tmp16, Eq(-22050));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Recv Uint16.
|
|
uint16_t tmpu16;
|
|
ASSERT_THAT(comms->RecvUint16(&tmpu16), IsTrue());
|
|
EXPECT_THAT(tmpu16, Eq(40001));
|
|
|
|
// Send Int16.
|
|
ASSERT_THAT(comms->SendInt16(-22050), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecv32) {
|
|
auto a = [](Comms* comms) {
|
|
// SendUint32.
|
|
ASSERT_THAT(comms->SendUint32(3221225472UL), IsTrue());
|
|
|
|
// Recv Int32.
|
|
int32_t tmp32;
|
|
ASSERT_THAT(comms->RecvInt32(&tmp32), IsTrue());
|
|
EXPECT_THAT(tmp32, Eq(-1073741824));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Recv Uint32.
|
|
uint32_t tmpu32;
|
|
ASSERT_THAT(comms->RecvUint32(&tmpu32), IsTrue());
|
|
EXPECT_THAT(tmpu32, Eq(3221225472UL));
|
|
|
|
// Send Int32.
|
|
ASSERT_THAT(comms->SendInt32(-1073741824), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecv64) {
|
|
auto a = [](Comms* comms) {
|
|
// SendUint64.
|
|
ASSERT_THAT(comms->SendUint64(1099511627776ULL), IsTrue());
|
|
|
|
// Recv Int64.
|
|
int64_t tmp64;
|
|
ASSERT_THAT(comms->RecvInt64(&tmp64), IsTrue());
|
|
EXPECT_THAT(tmp64, Eq(-1099511627776LL));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Recv Uint64.
|
|
uint64_t tmpu64;
|
|
ASSERT_THAT(comms->RecvUint64(&tmpu64), IsTrue());
|
|
EXPECT_THAT(tmpu64, Eq(1099511627776ULL));
|
|
|
|
// Send Int64.
|
|
ASSERT_THAT(comms->SendInt64(-1099511627776LL), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestTypeMismatch) {
|
|
auto a = [](Comms* comms) {
|
|
uint8_t tmpu8;
|
|
// Receive Int8 (but Uint8 expected).
|
|
EXPECT_THAT(comms->RecvUint8(&tmpu8), IsFalse());
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send Int8 (but Uint8 expected).
|
|
ASSERT_THAT(comms->SendInt8(-93), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvString) {
|
|
auto a = [](Comms* comms) {
|
|
std::string tmps;
|
|
ASSERT_THAT(comms->RecvString(&tmps), IsTrue());
|
|
EXPECT_TRUE(tmps == NullTestString());
|
|
EXPECT_THAT(tmps.size(), Eq(NullTestString().size()));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
ASSERT_THAT(comms->SendString(std::string(NullTestString())), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvArray) {
|
|
auto a = [](Comms* comms) {
|
|
// Receive 1M bytes.
|
|
std::vector<uint8_t> buffer;
|
|
ASSERT_THAT(comms->RecvBytes(&buffer), IsTrue());
|
|
EXPECT_THAT(buffer.size(), Eq(1024 * 1024));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send 1M bytes.
|
|
std::vector<uint8_t> buffer(1024 * 1024);
|
|
memset(buffer.data(), 0, buffer.size());
|
|
ASSERT_THAT(comms->SendBytes(buffer), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvFD) {
|
|
auto a = [](Comms* comms) {
|
|
// Receive FD and test it.
|
|
int fd = -1;
|
|
ASSERT_THAT(comms->RecvFD(&fd), IsTrue());
|
|
EXPECT_GE(fd, 0);
|
|
EXPECT_NE(fcntl(fd, F_GETFD), -1);
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send our STDERR to the thread.
|
|
ASSERT_THAT(comms->SendFD(STDERR_FILENO), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvEmptyTLV) {
|
|
auto a = [](Comms* comms) {
|
|
// Receive TLV without a value.
|
|
uint32_t tag;
|
|
std::vector<uint8_t> value;
|
|
ASSERT_THAT(comms->RecvTLV(&tag, &value), IsTrue()); // NOLINT
|
|
EXPECT_THAT(tag, Eq(0x00DEADBE));
|
|
EXPECT_THAT(value.size(), Eq(0));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send TLV without a value.
|
|
ASSERT_THAT(comms->SendTLV(0x00DEADBE, 0, nullptr), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvEmptyTLV2) {
|
|
auto a = [](Comms* comms) {
|
|
// Receive TLV without a value.
|
|
uint32_t tag;
|
|
std::vector<uint8_t> data;
|
|
ASSERT_THAT(comms->RecvTLV(&tag, &data), IsTrue());
|
|
EXPECT_THAT(tag, Eq(0x00DEADBE));
|
|
EXPECT_THAT(data.size(), Eq(0));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send TLV without a value.
|
|
ASSERT_THAT(comms->SendTLV(0x00DEADBE, 0, nullptr), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvProto) {
|
|
auto a = [](Comms* comms) {
|
|
// Receive a ProtoBuf.
|
|
std::unique_ptr<CommsTestMsg> comms_msg(new CommsTestMsg());
|
|
ASSERT_THAT(comms->RecvProtoBuf(comms_msg.get()), IsTrue());
|
|
ASSERT_THAT(comms_msg->value_size(), Eq(1));
|
|
EXPECT_THAT(comms_msg->value(0), Eq(kProtoStr));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send a ProtoBuf.
|
|
std::unique_ptr<CommsTestMsg> comms_msg(new CommsTestMsg());
|
|
comms_msg->add_value(kProtoStr);
|
|
ASSERT_THAT(comms_msg->value_size(), Eq(1));
|
|
ASSERT_THAT(comms->SendProtoBuf(*comms_msg), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvStatusOK) {
|
|
auto a = [](Comms* comms) {
|
|
// Receive a good status.
|
|
absl::Status status;
|
|
ASSERT_THAT(comms->RecvStatus(&status), IsTrue());
|
|
EXPECT_THAT(status, IsOk());
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send a good status.
|
|
ASSERT_THAT(comms->SendStatus(absl::OkStatus()), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvStatusFailing) {
|
|
auto a = [](Comms* comms) {
|
|
// Receive a failing status.
|
|
absl::Status status;
|
|
ASSERT_THAT(comms->RecvStatus(&status), IsTrue());
|
|
EXPECT_THAT(status, Not(IsOk()));
|
|
EXPECT_THAT(status, StatusIs(absl::StatusCode::kInternal, "something odd"));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send a failing status.
|
|
ASSERT_THAT(comms->SendStatus(
|
|
absl::Status{absl::StatusCode::kInternal, "something odd"}),
|
|
IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestUsesDistinctBuffers) {
|
|
auto a = [](Comms* comms) {
|
|
// Receive 1M bytes.
|
|
std::vector<uint8_t> buffer1, buffer2;
|
|
ASSERT_THAT(comms->RecvBytes(&buffer1), IsTrue()); // NOLINT
|
|
EXPECT_THAT(buffer1.size(), Eq(1024 * 1024));
|
|
|
|
ASSERT_THAT(comms->RecvBytes(&buffer2), IsTrue()); // NOLINT
|
|
EXPECT_THAT(buffer2.size(), Eq(1024 * 1024));
|
|
|
|
// Make sure we can access the buffer (memory was not free'd).
|
|
// Probably only useful when running with ASAN/MSAN.
|
|
EXPECT_THAT(buffer1[1024 * 1024 - 1], Eq(buffer1[1024 * 1024 - 1]));
|
|
EXPECT_THAT(buffer2[1024 * 1024 - 1], Eq(buffer2[1024 * 1024 - 1]));
|
|
EXPECT_NE(buffer1.data(), buffer2.data());
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send 1M bytes.
|
|
absl::FixedArray<uint8_t> buf(1024 * 1024);
|
|
memset(buf.data(), 0, buf.size());
|
|
ASSERT_THAT(comms->SendBytes(buf.data(), buf.size()), IsTrue());
|
|
ASSERT_THAT(comms->SendBytes(buf.data(), buf.size()), IsTrue());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvCredentials) {
|
|
auto a = [](Comms* comms) {
|
|
// Check credentials.
|
|
pid_t pid;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
ASSERT_THAT(comms->RecvCreds(&pid, &uid, &gid), IsTrue());
|
|
EXPECT_THAT(pid, Eq(getpid()));
|
|
EXPECT_THAT(uid, Eq(getuid()));
|
|
EXPECT_THAT(gid, Eq(getgid()));
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Nothing to do here.
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendTooMuchData) {
|
|
auto a = [](Comms* comms) {
|
|
// Nothing to do here.
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
// Send too much data.
|
|
ASSERT_THAT(comms->SendBytes(nullptr, comms->GetMaxMsgSize() + 1),
|
|
IsFalse());
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
TEST(CommsTest, TestSendRecvBytes) {
|
|
auto a = [](Comms* comms) {
|
|
std::vector<uint8_t> buffer;
|
|
ASSERT_THAT(comms->RecvBytes(&buffer), IsTrue());
|
|
ASSERT_THAT(comms->SendBytes(buffer), IsTrue());
|
|
};
|
|
auto b = [](Comms* comms) {
|
|
const std::vector<uint8_t> request = {0, 1, 2, 3, 7};
|
|
ASSERT_THAT(comms->SendBytes(request), IsTrue());
|
|
|
|
std::vector<uint8_t> response;
|
|
ASSERT_THAT(comms->RecvBytes(&response), IsTrue());
|
|
EXPECT_THAT(request, Eq(response));
|
|
};
|
|
HandleCommunication(a, b);
|
|
}
|
|
|
|
} // namespace sandbox2
|