From 5b40e898947e33968f75b4e6e57a43038ab181e5 Mon Sep 17 00:00:00 2001 From: Tri Vo Date: Sun, 1 Nov 2020 13:01:29 -0800 Subject: [PATCH] trusty: coverage: Coverage client library Bug: 169776499 Test: /data/nativetest64/libtrusty_coverage_test/libtrusty_coverage_test Change-Id: I5f432a3df04fe7b0e2940a12f8d28b3d0655791f --- trusty/coverage/Android.bp | 45 +++++ trusty/coverage/coverage.cpp | 172 ++++++++++++++++++ trusty/coverage/coverage_test.cpp | 95 ++++++++++ .../include/trusty/coverage/coverage.h | 55 ++++++ .../coverage/include/trusty/coverage/tipc.h | 68 +++++++ 5 files changed, 435 insertions(+) create mode 100644 trusty/coverage/Android.bp create mode 100644 trusty/coverage/coverage.cpp create mode 100644 trusty/coverage/coverage_test.cpp create mode 100644 trusty/coverage/include/trusty/coverage/coverage.h create mode 100644 trusty/coverage/include/trusty/coverage/tipc.h diff --git a/trusty/coverage/Android.bp b/trusty/coverage/Android.bp new file mode 100644 index 000000000..a4adf81be --- /dev/null +++ b/trusty/coverage/Android.bp @@ -0,0 +1,45 @@ +// Copyright (C) 2020 The Android Open-Source Project +// +// 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. + +cc_library { + name: "libtrusty_coverage", + srcs: [ + "coverage.cpp", + ], + export_include_dirs: [ + "include", + ], + static_libs: [ + "libtrusty_test", + ], + shared_libs: [ + "libbase", + "liblog", + ], +} + +cc_test { + name: "libtrusty_coverage_test", + srcs: [ + "coverage_test.cpp", + ], + static_libs: [ + "libtrusty_coverage", + "libtrusty_test", + ], + shared_libs: [ + "libbase", + "liblog", + ], +} diff --git a/trusty/coverage/coverage.cpp b/trusty/coverage/coverage.cpp new file mode 100644 index 000000000..1162f42aa --- /dev/null +++ b/trusty/coverage/coverage.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2020 The Android Open Sourete Project + * + * 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. + */ + +#define LOG_TAG "coverage" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define COVERAGE_CLIENT_PORT "com.android.trusty.coverage.client" + +namespace android { +namespace trusty { +namespace coverage { + +using android::base::ErrnoError; +using android::base::Error; +using std::string; + +static inline uintptr_t RoundPageUp(uintptr_t val) { + return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); +} + +CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid) + : tipc_dev_(std::move(tipc_dev)), + coverage_srv_fd_(-1), + uuid_(*uuid), + record_len_(0), + shm_(NULL), + shm_len_(0) {} + +CoverageRecord::~CoverageRecord() { + if (shm_) { + munmap((void*)shm_, shm_len_); + } +} + +Result CoverageRecord::Rpc(coverage_client_req* req, int req_fd, coverage_client_resp* resp) { + int rc; + + if (req_fd < 0) { + rc = write(coverage_srv_fd_, req, sizeof(*req)); + } else { + iovec iov = { + .iov_base = req, + .iov_len = sizeof(*req), + }; + + trusty_shm shm = { + .fd = req_fd, + .transfer = TRUSTY_SHARE, + }; + + rc = tipc_send(coverage_srv_fd_, &iov, 1, &shm, 1); + } + + if (rc != (int)sizeof(*req)) { + return ErrnoError() << "failed to send request to coverage server: "; + } + + rc = read(coverage_srv_fd_, resp, sizeof(*resp)); + if (rc != (int)sizeof(*resp)) { + return ErrnoError() << "failed to read reply from coverage server: "; + } + + if (resp->hdr.cmd != (req->hdr.cmd | COVERAGE_CLIENT_CMD_RESP_BIT)) { + return ErrnoError() << "unknown response cmd: " << resp->hdr.cmd; + } + + return {}; +} + +Result CoverageRecord::Open() { + coverage_client_req req; + coverage_client_resp resp; + + if (shm_) { + return {}; /* already initialized */ + } + + int fd = tipc_connect(tipc_dev_.c_str(), COVERAGE_CLIENT_PORT); + if (fd < 0) { + return ErrnoError() << "failed to connect to Trusty coverarge server: "; + } + coverage_srv_fd_.reset(fd); + + req.hdr.cmd = COVERAGE_CLIENT_CMD_OPEN; + req.open_args.uuid = uuid_; + auto ret = Rpc(&req, -1, &resp); + if (!ret.ok()) { + return Error() << "failed to open coverage client: "; + } + record_len_ = resp.open_args.record_len; + shm_len_ = RoundPageUp(record_len_); + + fd = memfd_create("trusty-coverage", 0); + if (fd < 0) { + return ErrnoError() << "failed to create memfd: "; + } + unique_fd memfd(fd); + + if (ftruncate(memfd, shm_len_) < 0) { + return ErrnoError() << "failed to resize memfd: "; + } + + void* shm = mmap(0, shm_len_, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, 0); + if (shm == MAP_FAILED) { + return ErrnoError() << "failed to map memfd: "; + } + + req.hdr.cmd = COVERAGE_CLIENT_CMD_SHARE_RECORD; + req.share_record_args.shm_len = shm_len_; + ret = Rpc(&req, memfd, &resp); + if (!ret.ok()) { + return Error() << "failed to send shared memory: "; + } + + shm_ = shm; + return {}; +} + +void CoverageRecord::Reset() { + for (size_t i = 0; i < shm_len_; i++) { + *((volatile uint8_t*)shm_ + i) = 0; + } +} + +void CoverageRecord::GetRawData(volatile void** begin, volatile void** end) { + assert(shm_); + + *begin = shm_; + *end = (uint8_t*)(*begin) + record_len_; +} + +uint64_t CoverageRecord::CountEdges() { + assert(shm_); + + uint64_t counter = 0; + + volatile uint8_t* begin = NULL; + volatile uint8_t* end = NULL; + + GetRawData((volatile void**)&begin, (volatile void**)&end); + + for (volatile uint8_t* x = begin; x < end; x++) { + counter += *x; + } + + return counter; +} + +} // namespace coverage +} // namespace trusty +} // namespace android diff --git a/trusty/coverage/coverage_test.cpp b/trusty/coverage/coverage_test.cpp new file mode 100644 index 000000000..d8df7a46f --- /dev/null +++ b/trusty/coverage/coverage_test.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * 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 +#include +#include +#include +#include + +using android::base::unique_fd; +using std::array; +using std::make_unique; +using std::unique_ptr; + +#define TIPC_DEV "/dev/trusty-ipc-dev0" +#define TEST_SRV_PORT "com.android.trusty.sancov.test.srv" + +namespace android { +namespace trusty { +namespace coverage { + +/* Test server's UUID is 77f68803-c514-43ba-bdce-3254531c3d24 */ +static struct uuid test_srv_uuid = { + 0x77f68803, + 0xc514, + 0x43ba, + {0xbd, 0xce, 0x32, 0x54, 0x53, 0x1c, 0x3d, 0x24}, +}; + +class CoverageTest : public ::testing::Test { + public: + void SetUp() override { + record_ = make_unique(TIPC_DEV, &test_srv_uuid); + auto ret = record_->Open(); + ASSERT_TRUE(ret.ok()) << ret.error(); + } + + void TearDown() override { record_.reset(); } + + unique_ptr record_; +}; + +TEST_F(CoverageTest, CoverageReset) { + record_->Reset(); + auto counter = record_->CountEdges(); + ASSERT_EQ(counter, 0); +} + +TEST_F(CoverageTest, TestServerCoverage) { + unique_fd test_srv(tipc_connect(TIPC_DEV, TEST_SRV_PORT)); + ASSERT_GE(test_srv, 0); + + uint32_t mask = (uint32_t)-1; + uint32_t magic = 0xdeadbeef; + uint64_t high_watermark = 0; + + for (size_t i = 1; i < sizeof(magic) * 8; i++) { + /* Reset coverage */ + record_->Reset(); + + /* Send message to test server */ + uint32_t msg = magic & ~(mask << i); + int rc = write(test_srv, &msg, sizeof(msg)); + ASSERT_EQ(rc, sizeof(msg)); + + /* Read message from test server */ + rc = read(test_srv, &msg, sizeof(msg)); + ASSERT_EQ(rc, sizeof(msg)); + + /* Count number of non-unique blocks executed */ + auto counter = record_->CountEdges(); + /* Each consecutive input should exercise more or same blocks */ + ASSERT_GE(counter, high_watermark); + high_watermark = counter; + } + + ASSERT_GT(high_watermark, 0); +} + +} // namespace coverage +} // namespace trusty +} // namespace android diff --git a/trusty/coverage/include/trusty/coverage/coverage.h b/trusty/coverage/include/trusty/coverage/coverage.h new file mode 100644 index 000000000..b61b95930 --- /dev/null +++ b/trusty/coverage/include/trusty/coverage/coverage.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace android { +namespace trusty { +namespace coverage { + +using android::base::Result; +using android::base::unique_fd; + +class CoverageRecord { + public: + CoverageRecord(std::string tipc_dev, struct uuid* uuid); + ~CoverageRecord(); + Result Open(); + void Reset(); + void GetRawData(volatile void** begin, volatile void** end); + uint64_t CountEdges(); + + private: + Result Rpc(coverage_client_req* req, int req_fd, coverage_client_resp* resp); + + std::string tipc_dev_; + unique_fd coverage_srv_fd_; + struct uuid uuid_; + size_t record_len_; + volatile void* shm_; + size_t shm_len_; +}; + +} // namespace coverage +} // namespace trusty +} // namespace android diff --git a/trusty/coverage/include/trusty/coverage/tipc.h b/trusty/coverage/include/trusty/coverage/tipc.h new file mode 100644 index 000000000..c4157c4d6 --- /dev/null +++ b/trusty/coverage/include/trusty/coverage/tipc.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * 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. + */ + +/* This file needs to be kept in-sync with it's counterpart on Trusty side */ + +#pragma once + +#include + +#define COVERAGE_CLIENT_PORT "com.android.trusty.coverage.client" + +struct uuid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_and_node[8]; +}; + +enum coverage_client_cmd { + COVERAGE_CLIENT_CMD_RESP_BIT = 1U, + COVERAGE_CLIENT_CMD_SHIFT = 1U, + COVERAGE_CLIENT_CMD_OPEN = (1U << COVERAGE_CLIENT_CMD_SHIFT), + COVERAGE_CLIENT_CMD_SHARE_RECORD = (2U << COVERAGE_CLIENT_CMD_SHIFT), +}; + +struct coverage_client_hdr { + uint32_t cmd; +}; + +struct coverage_client_open_req { + struct uuid uuid; +}; + +struct coverage_client_open_resp { + uint32_t record_len; +}; + +struct coverage_client_share_record_req { + uint32_t shm_len; +}; + +struct coverage_client_req { + struct coverage_client_hdr hdr; + union { + struct coverage_client_open_req open_args; + struct coverage_client_share_record_req share_record_args; + }; +}; + +struct coverage_client_resp { + struct coverage_client_hdr hdr; + union { + struct coverage_client_open_resp open_args; + }; +};