diff options
| -rw-r--r-- | libs/binder/RecordedTransaction.cpp | 48 | ||||
| -rw-r--r-- | libs/binder/tests/unit_fuzzers/Android.bp | 39 | ||||
| -rw-r--r-- | libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp | 45 | ||||
| -rw-r--r-- | libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp | 64 | ||||
| -rw-r--r-- | libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/power_recording | bin | 0 -> 928 bytes | |||
| -rw-r--r-- | libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/recorded_binder_transaction | bin | 0 -> 32 bytes |
6 files changed, 190 insertions, 6 deletions
diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp index 2e7030437c..51b971651d 100644 --- a/libs/binder/RecordedTransaction.cpp +++ b/libs/binder/RecordedTransaction.cpp @@ -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> @@ -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; @@ -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 @@ -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: { @@ -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); diff --git a/libs/binder/tests/unit_fuzzers/Android.bp b/libs/binder/tests/unit_fuzzers/Android.bp index 8ea948cc15..a88158299e 100644 --- a/libs/binder/tests/unit_fuzzers/Android.bp +++ b/libs/binder/tests/unit_fuzzers/Android.bp @@ -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, + }, + }, +} diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp new file mode 100644 index 0000000000..73790fae49 --- /dev/null +++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp @@ -0,0 +1,45 @@ +/* + * 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; +} diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp new file mode 100644 index 0000000000..943fb9f285 --- /dev/null +++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp @@ -0,0 +1,64 @@ +/* + * 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; +} diff --git a/libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/power_recording b/libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/power_recording Binary files differnew file mode 100644 index 0000000000..79442078c2 --- /dev/null +++ b/libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/power_recording diff --git a/libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/recorded_binder_transaction b/libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/recorded_binder_transaction Binary files differnew file mode 100644 index 0000000000..658addbed5 --- /dev/null +++ b/libs/binder/tests/unit_fuzzers/recorded_transaction_corpus/recorded_binder_transaction |