Loading libs/binder/RecordedTransaction.cpp +42 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/scopeguard.h> #include <android-base/unique_fd.h> #include <binder/RecordedTransaction.h> #include <sys/mman.h> Loading Loading @@ -176,13 +177,33 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd RecordedTransaction t; ChunkDescriptor chunk; const long pageSize = sysconf(_SC_PAGE_SIZE); struct stat fileStat; if (fstat(fd.get(), &fileStat) != 0) { LOG(ERROR) << "Unable to get file information"; return std::nullopt; } off_t fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR); if (fdCurrentPosition == -1) { LOG(ERROR) << "Invalid offset in file descriptor."; return std::nullopt; } do { if (fileStat.st_size < (fdCurrentPosition + (off_t)sizeof(ChunkDescriptor))) { LOG(ERROR) << "Not enough file remains to contain expected chunk descriptor"; return std::nullopt; } transaction_checksum_t checksum = 0; if (NO_ERROR != readChunkDescriptor(fd, &chunk, &checksum)) { LOG(ERROR) << "Failed to read chunk descriptor."; return std::nullopt; } off_t fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR); fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR); if (fdCurrentPosition == -1) { LOG(ERROR) << "Invalid offset in file descriptor."; return std::nullopt; } off_t mmapPageAlignedStart = (fdCurrentPosition / pageSize) * pageSize; off_t mmapPayloadStartOffset = fdCurrentPosition - mmapPageAlignedStart; Loading @@ -194,14 +215,24 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd size_t chunkPayloadSize = chunk.dataSize + PADDING8(chunk.dataSize) + sizeof(transaction_checksum_t); if (chunkPayloadSize > (size_t)(fileStat.st_size - fdCurrentPosition)) { LOG(ERROR) << "Chunk payload exceeds remaining file size."; return std::nullopt; } if (PADDING8(chunkPayloadSize) != 0) { LOG(ERROR) << "Invalid chunk size, not aligned " << chunkPayloadSize; return std::nullopt; } transaction_checksum_t* payloadMap = reinterpret_cast<transaction_checksum_t*>( mmap(NULL, chunkPayloadSize + mmapPayloadStartOffset, PROT_READ, MAP_SHARED, fd.get(), mmapPageAlignedStart)); size_t memoryMappedSize = chunkPayloadSize + mmapPayloadStartOffset; void* mappedMemory = mmap(NULL, memoryMappedSize, PROT_READ, MAP_SHARED, fd.get(), mmapPageAlignedStart); auto mmap_guard = android::base::make_scope_guard( [mappedMemory, memoryMappedSize] { munmap(mappedMemory, memoryMappedSize); }); transaction_checksum_t* payloadMap = reinterpret_cast<transaction_checksum_t*>(mappedMemory); payloadMap += mmapPayloadStartOffset / sizeof(transaction_checksum_t); // Skip chunk descriptor and required mmap // page-alignment Loading @@ -218,7 +249,12 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd LOG(ERROR) << "Checksum failed."; return std::nullopt; } lseek(fd.get(), chunkPayloadSize, SEEK_CUR); fdCurrentPosition = lseek(fd.get(), chunkPayloadSize, SEEK_CUR); if (fdCurrentPosition == -1) { LOG(ERROR) << "Invalid offset in file descriptor."; return std::nullopt; } switch (chunk.chunkType) { case HEADER_CHUNK: { Loading Loading @@ -255,7 +291,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd break; default: LOG(INFO) << "Unrecognized chunk."; continue; break; } } while (chunk.chunkType != END_CHUNK); Loading libs/binder/tests/unit_fuzzers/Android.bp +39 −0 Original line number Diff line number Diff line Loading @@ -104,3 +104,42 @@ cc_fuzz { defaults: ["binder_fuzz_defaults"], srcs: ["MemoryDealerFuzz.cpp"], } cc_fuzz { name: "binder_recordedTransactionFileFuzz", defaults: ["binder_fuzz_defaults"], srcs: ["RecordedTransactionFileFuzz.cpp"], corpus: [ "recorded_transaction_corpus/*", ], } cc_fuzz { name: "binder_recordedTransactionFuzz", defaults: ["binder_fuzz_defaults"], srcs: ["RecordedTransactionFuzz.cpp"], target: { android: { shared_libs: [ "libcutils", "libutils", "libbase", "libbinder", ], static_libs: ["libbinder_random_parcel"], }, host: { static_libs: [ "libcutils", "liblog", "libutils", "libbase", "libbinder", "libbinder_random_parcel", ], }, darwin: { enabled: false, }, }, } libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp 0 → 100644 +45 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 <android-base/macros.h> #include <binder/RecordedTransaction.h> #include <filesystem> #include "fuzzer/FuzzedDataProvider.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { std::FILE* intermediateFile = std::tmpfile(); fwrite(data, sizeof(uint8_t), size, intermediateFile); rewind(intermediateFile); int fileNumber = fileno(intermediateFile); android::base::unique_fd fd(fileNumber); auto transaction = android::binder::debug::RecordedTransaction::fromFile(fd); std::fclose(intermediateFile); if (transaction.has_value()) { intermediateFile = std::tmpfile(); android::base::unique_fd fdForWriting(fileno(intermediateFile)); auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting); std::fclose(intermediateFile); } return 0; } libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp 0 → 100644 +64 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 <android-base/macros.h> #include <binder/RecordedTransaction.h> #include <fuzzbinder/random_parcel.h> #include <filesystem> #include <string> #include "fuzzer/FuzzedDataProvider.h" using android::fillRandomParcel; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider provider = FuzzedDataProvider(data, size); android::String16 interfaceName = android::String16(provider.ConsumeRandomLengthString().c_str()); uint32_t code = provider.ConsumeIntegral<uint32_t>(); uint32_t flags = provider.ConsumeIntegral<uint32_t>(); time_t sec = provider.ConsumeIntegral<time_t>(); long nsec = provider.ConsumeIntegral<long>(); timespec timestamp = {.tv_sec = sec, .tv_nsec = nsec}; android::status_t transactionStatus = provider.ConsumeIntegral<android::status_t>(); std::vector<uint8_t> bytes = provider.ConsumeBytes<uint8_t>( provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes())); // same options so that FDs and binders could be shared in both Parcels android::RandomParcelOptions options; android::Parcel p0, p1; fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()), &options); fillRandomParcel(&p1, std::move(provider), &options); auto transaction = android::binder::debug::RecordedTransaction::fromDetails(interfaceName, code, flags, timestamp, p0, p1, transactionStatus); if (transaction.has_value()) { std::FILE* intermediateFile = std::tmpfile(); android::base::unique_fd fdForWriting(fileno(intermediateFile)); auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting); std::fclose(intermediateFile); } return 0; } libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/power_recording 0 → 100644 +928 B File added.No diff preview for this file type. View file Loading
libs/binder/RecordedTransaction.cpp +42 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/scopeguard.h> #include <android-base/unique_fd.h> #include <binder/RecordedTransaction.h> #include <sys/mman.h> Loading Loading @@ -176,13 +177,33 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd RecordedTransaction t; ChunkDescriptor chunk; const long pageSize = sysconf(_SC_PAGE_SIZE); struct stat fileStat; if (fstat(fd.get(), &fileStat) != 0) { LOG(ERROR) << "Unable to get file information"; return std::nullopt; } off_t fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR); if (fdCurrentPosition == -1) { LOG(ERROR) << "Invalid offset in file descriptor."; return std::nullopt; } do { if (fileStat.st_size < (fdCurrentPosition + (off_t)sizeof(ChunkDescriptor))) { LOG(ERROR) << "Not enough file remains to contain expected chunk descriptor"; return std::nullopt; } transaction_checksum_t checksum = 0; if (NO_ERROR != readChunkDescriptor(fd, &chunk, &checksum)) { LOG(ERROR) << "Failed to read chunk descriptor."; return std::nullopt; } off_t fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR); fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR); if (fdCurrentPosition == -1) { LOG(ERROR) << "Invalid offset in file descriptor."; return std::nullopt; } off_t mmapPageAlignedStart = (fdCurrentPosition / pageSize) * pageSize; off_t mmapPayloadStartOffset = fdCurrentPosition - mmapPageAlignedStart; Loading @@ -194,14 +215,24 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd size_t chunkPayloadSize = chunk.dataSize + PADDING8(chunk.dataSize) + sizeof(transaction_checksum_t); if (chunkPayloadSize > (size_t)(fileStat.st_size - fdCurrentPosition)) { LOG(ERROR) << "Chunk payload exceeds remaining file size."; return std::nullopt; } if (PADDING8(chunkPayloadSize) != 0) { LOG(ERROR) << "Invalid chunk size, not aligned " << chunkPayloadSize; return std::nullopt; } transaction_checksum_t* payloadMap = reinterpret_cast<transaction_checksum_t*>( mmap(NULL, chunkPayloadSize + mmapPayloadStartOffset, PROT_READ, MAP_SHARED, fd.get(), mmapPageAlignedStart)); size_t memoryMappedSize = chunkPayloadSize + mmapPayloadStartOffset; void* mappedMemory = mmap(NULL, memoryMappedSize, PROT_READ, MAP_SHARED, fd.get(), mmapPageAlignedStart); auto mmap_guard = android::base::make_scope_guard( [mappedMemory, memoryMappedSize] { munmap(mappedMemory, memoryMappedSize); }); transaction_checksum_t* payloadMap = reinterpret_cast<transaction_checksum_t*>(mappedMemory); payloadMap += mmapPayloadStartOffset / sizeof(transaction_checksum_t); // Skip chunk descriptor and required mmap // page-alignment Loading @@ -218,7 +249,12 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd LOG(ERROR) << "Checksum failed."; return std::nullopt; } lseek(fd.get(), chunkPayloadSize, SEEK_CUR); fdCurrentPosition = lseek(fd.get(), chunkPayloadSize, SEEK_CUR); if (fdCurrentPosition == -1) { LOG(ERROR) << "Invalid offset in file descriptor."; return std::nullopt; } switch (chunk.chunkType) { case HEADER_CHUNK: { Loading Loading @@ -255,7 +291,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd break; default: LOG(INFO) << "Unrecognized chunk."; continue; break; } } while (chunk.chunkType != END_CHUNK); Loading
libs/binder/tests/unit_fuzzers/Android.bp +39 −0 Original line number Diff line number Diff line Loading @@ -104,3 +104,42 @@ cc_fuzz { defaults: ["binder_fuzz_defaults"], srcs: ["MemoryDealerFuzz.cpp"], } cc_fuzz { name: "binder_recordedTransactionFileFuzz", defaults: ["binder_fuzz_defaults"], srcs: ["RecordedTransactionFileFuzz.cpp"], corpus: [ "recorded_transaction_corpus/*", ], } cc_fuzz { name: "binder_recordedTransactionFuzz", defaults: ["binder_fuzz_defaults"], srcs: ["RecordedTransactionFuzz.cpp"], target: { android: { shared_libs: [ "libcutils", "libutils", "libbase", "libbinder", ], static_libs: ["libbinder_random_parcel"], }, host: { static_libs: [ "libcutils", "liblog", "libutils", "libbase", "libbinder", "libbinder_random_parcel", ], }, darwin: { enabled: false, }, }, }
libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp 0 → 100644 +45 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 <android-base/macros.h> #include <binder/RecordedTransaction.h> #include <filesystem> #include "fuzzer/FuzzedDataProvider.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { std::FILE* intermediateFile = std::tmpfile(); fwrite(data, sizeof(uint8_t), size, intermediateFile); rewind(intermediateFile); int fileNumber = fileno(intermediateFile); android::base::unique_fd fd(fileNumber); auto transaction = android::binder::debug::RecordedTransaction::fromFile(fd); std::fclose(intermediateFile); if (transaction.has_value()) { intermediateFile = std::tmpfile(); android::base::unique_fd fdForWriting(fileno(intermediateFile)); auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting); std::fclose(intermediateFile); } return 0; }
libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp 0 → 100644 +64 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 <android-base/macros.h> #include <binder/RecordedTransaction.h> #include <fuzzbinder/random_parcel.h> #include <filesystem> #include <string> #include "fuzzer/FuzzedDataProvider.h" using android::fillRandomParcel; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider provider = FuzzedDataProvider(data, size); android::String16 interfaceName = android::String16(provider.ConsumeRandomLengthString().c_str()); uint32_t code = provider.ConsumeIntegral<uint32_t>(); uint32_t flags = provider.ConsumeIntegral<uint32_t>(); time_t sec = provider.ConsumeIntegral<time_t>(); long nsec = provider.ConsumeIntegral<long>(); timespec timestamp = {.tv_sec = sec, .tv_nsec = nsec}; android::status_t transactionStatus = provider.ConsumeIntegral<android::status_t>(); std::vector<uint8_t> bytes = provider.ConsumeBytes<uint8_t>( provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes())); // same options so that FDs and binders could be shared in both Parcels android::RandomParcelOptions options; android::Parcel p0, p1; fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()), &options); fillRandomParcel(&p1, std::move(provider), &options); auto transaction = android::binder::debug::RecordedTransaction::fromDetails(interfaceName, code, flags, timestamp, p0, p1, transactionStatus); if (transaction.has_value()) { std::FILE* intermediateFile = std::tmpfile(); android::base::unique_fd fdForWriting(fileno(intermediateFile)); auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting); std::fclose(intermediateFile); } return 0; }
libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/power_recording 0 → 100644 +928 B File added.No diff preview for this file type. View file