/* * 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 #include #include #include #include #include #include #include #include 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(sizeof(hdr) + sizeof(args))) { return false; } rc = read(chan, &hdr, sizeof(hdr)); if (rc != static_cast(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(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(sizeof(hdr) + sizeof(args))) { return false; } rc = readv(chan, iov, countof(iov)); if (rc != static_cast(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; }