226 lines
5.9 KiB
C++
226 lines
5.9 KiB
C++
/*
|
|
* Copyright (C) 2021 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 <BufferAllocator/BufferAllocator.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mman.h>
|
|
#include <trusty/coverage/coverage.h>
|
|
#include <trusty/fuzz/counters.h>
|
|
#include <trusty/fuzz/utils.h>
|
|
#include <trusty/tipc.h>
|
|
#include <unistd.h>
|
|
#include <iostream>
|
|
|
|
using android::trusty::coverage::CoverageRecord;
|
|
using android::trusty::fuzz::ExtraCounters;
|
|
using android::trusty::fuzz::TrustyApp;
|
|
|
|
#define countof(arr) (sizeof(arr) / sizeof(arr[0]))
|
|
|
|
#define TIPC_DEV "/dev/trusty-ipc-dev0"
|
|
#define WIDEVINE_PORT "com.android.trusty.widevine"
|
|
#define WIDEVINE_MODULE_NAME "widevine.syms.elf"
|
|
|
|
#define WV_IPC_BUFFER_SIZE (32)
|
|
#define WV_MESSAGE_BUFFER_SIZE (32 * 1024)
|
|
#define WV_SHARED_BUFFER_SIZE (16 * 1024 * 1024)
|
|
|
|
struct wv_ipc_header {
|
|
uint16_t tag;
|
|
};
|
|
|
|
enum wv_tag : uint16_t {
|
|
WV_TAG_ACK = 0u,
|
|
WV_TAG_BIND = 1u,
|
|
WV_TAG_WIDEVINE = 2u,
|
|
};
|
|
|
|
struct bind_message {
|
|
uint32_t protocol_version;
|
|
uint32_t message_buffer_size;
|
|
uint32_t shared_buffer_size;
|
|
};
|
|
|
|
struct widevine_message {
|
|
uint32_t message_size;
|
|
};
|
|
|
|
/* Widevine TA's UUID is 08d3ed40-bde2-448c-a91d-75f1989c57ef */
|
|
static struct uuid widevine_uuid = {
|
|
0x08d3ed40,
|
|
0xbde2,
|
|
0x448c,
|
|
{0xa9, 0x1d, 0x75, 0xf1, 0x98, 0x9c, 0x57, 0xef},
|
|
};
|
|
|
|
static android::base::unique_fd wv_msg_buf_fd;
|
|
static void* wv_msg_buf_base;
|
|
|
|
static android::base::unique_fd wv_shared_buf_fd;
|
|
static void* wv_shared_buf_base;
|
|
|
|
static TrustyApp trusty_app(TIPC_DEV, WIDEVINE_PORT);
|
|
static CoverageRecord record(TIPC_DEV, &widevine_uuid, WIDEVINE_MODULE_NAME);
|
|
|
|
extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
|
|
auto ret = trusty_app.Connect();
|
|
if (!ret.ok()) {
|
|
std::cerr << ret.error() << std::endl;
|
|
exit(-1);
|
|
}
|
|
|
|
ret = record.Open();
|
|
if (!ret.ok()) {
|
|
std::cerr << ret.error() << std::endl;
|
|
exit(-1);
|
|
}
|
|
|
|
BufferAllocator allocator;
|
|
|
|
wv_msg_buf_fd.reset(allocator.Alloc(kDmabufSystemHeapName, WV_MESSAGE_BUFFER_SIZE));
|
|
if (wv_msg_buf_fd < 0) {
|
|
std::cerr << "Failed to allocate message buffer." << std::endl;
|
|
exit(-1);
|
|
}
|
|
|
|
wv_msg_buf_base = mmap(0, WV_MESSAGE_BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
wv_msg_buf_fd, 0);
|
|
if (wv_msg_buf_base == MAP_FAILED) {
|
|
std::cerr << "Failed to mmap() message buffer." << std::endl;
|
|
exit(-1);
|
|
}
|
|
|
|
wv_shared_buf_fd.reset(allocator.Alloc(kDmabufSystemHeapName, WV_SHARED_BUFFER_SIZE));
|
|
if (wv_shared_buf_fd < 0) {
|
|
std::cerr << "Failed to allocate shared buffer." << std::endl;
|
|
exit(-1);
|
|
}
|
|
|
|
wv_shared_buf_base = mmap(0, WV_SHARED_BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
wv_shared_buf_fd, 0);
|
|
if (wv_shared_buf_base == MAP_FAILED) {
|
|
std::cerr << "Failed to mmap() shared buffer." << std::endl;
|
|
exit(-1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool Bind() {
|
|
wv_ipc_header hdr = {
|
|
.tag = WV_TAG_BIND,
|
|
};
|
|
bind_message args = {
|
|
.protocol_version = 0,
|
|
.message_buffer_size = WV_MESSAGE_BUFFER_SIZE,
|
|
.shared_buffer_size = WV_SHARED_BUFFER_SIZE,
|
|
};
|
|
iovec iov[] = {
|
|
{
|
|
.iov_base = &hdr,
|
|
.iov_len = sizeof(hdr),
|
|
},
|
|
{
|
|
.iov_base = &args,
|
|
.iov_len = sizeof(args),
|
|
},
|
|
};
|
|
trusty_shm handles[] = {
|
|
{
|
|
.fd = wv_msg_buf_fd,
|
|
.transfer = TRUSTY_SHARE,
|
|
},
|
|
{
|
|
.fd = wv_shared_buf_fd,
|
|
.transfer = TRUSTY_SHARE,
|
|
},
|
|
};
|
|
int chan = *trusty_app.GetRawFd();
|
|
|
|
int rc = tipc_send(chan, iov, countof(iov), handles, countof(handles));
|
|
if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
|
|
return false;
|
|
}
|
|
|
|
rc = read(chan, &hdr, sizeof(hdr));
|
|
if (rc != static_cast<int>(sizeof(hdr))) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool Msg(const uint8_t* data, size_t size) {
|
|
size = std::min((size_t)WV_MESSAGE_BUFFER_SIZE, size);
|
|
wv_ipc_header hdr = {
|
|
.tag = WV_TAG_WIDEVINE,
|
|
};
|
|
widevine_message args = {
|
|
.message_size = static_cast<uint32_t>(size),
|
|
};
|
|
iovec iov[] = {
|
|
{
|
|
.iov_base = &hdr,
|
|
.iov_len = sizeof(hdr),
|
|
},
|
|
{
|
|
.iov_base = &args,
|
|
.iov_len = sizeof(args),
|
|
},
|
|
};
|
|
int chan = *trusty_app.GetRawFd();
|
|
|
|
memset(wv_msg_buf_base, 0, WV_MESSAGE_BUFFER_SIZE);
|
|
memcpy(wv_msg_buf_base, data, size);
|
|
|
|
int rc = tipc_send(chan, iov, countof(iov), NULL, 0);
|
|
if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
|
|
return false;
|
|
}
|
|
|
|
rc = readv(chan, iov, countof(iov));
|
|
if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|
ExtraCounters counters(&record);
|
|
counters.Reset();
|
|
|
|
bool success = Bind();
|
|
if (!success) {
|
|
android::trusty::fuzz::Abort();
|
|
}
|
|
|
|
success = Msg(data, size);
|
|
if (!success) {
|
|
android::trusty::fuzz::Abort();
|
|
}
|
|
|
|
// Reconnect to ensure that the service is still up.
|
|
trusty_app.Disconnect();
|
|
auto ret = trusty_app.Connect();
|
|
if (!ret.ok()) {
|
|
std::cerr << ret.error() << std::endl;
|
|
android::trusty::fuzz::Abort();
|
|
}
|
|
|
|
return 0;
|
|
}
|