|  | /* | 
|  | * Copyright (C) 2019 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 <stddef.h> | 
|  | #include <stdint.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | #include "perfetto/ext/base/file_utils.h" | 
|  | #include "perfetto/ext/base/temp_file.h" | 
|  | #include "src/profiling/memory/shared_ring_buffer.h" | 
|  |  | 
|  | namespace perfetto { | 
|  | namespace profiling { | 
|  | namespace { | 
|  |  | 
|  | size_t RoundToPow2(size_t v) { | 
|  | uint64_t x = static_cast<uint64_t>(v); | 
|  | if (x < 2) | 
|  | return 2; | 
|  |  | 
|  | x--; | 
|  | x |= x >> 1; | 
|  | x |= x >> 2; | 
|  | x |= x >> 4; | 
|  | x |= x >> 8; | 
|  | x |= x >> 16; | 
|  | x |= x >> 32; | 
|  | x++; | 
|  | return static_cast<size_t>(x); | 
|  | } | 
|  |  | 
|  | int FuzzRingBuffer(const uint8_t* data, size_t size) { | 
|  | if (size <= sizeof(SharedRingBuffer::MetadataPage)) | 
|  | return 0; | 
|  |  | 
|  | auto fd = base::TempFile::CreateUnlinked().ReleaseFD(); | 
|  | PERFETTO_CHECK(fd); | 
|  |  | 
|  | // Use fuzzer input to first fill the SharedRingBuffer::MetadataPage in the | 
|  | // first page, and then put the remainder into the data portion of the ring | 
|  | // buffer (2nd+ pages). | 
|  | size_t payload_size = size - sizeof(SharedRingBuffer::MetadataPage); | 
|  | const uint8_t* payload = data + sizeof(SharedRingBuffer::MetadataPage); | 
|  | size_t payload_size_pages = | 
|  | (payload_size + base::kPageSize - 1) / base::kPageSize; | 
|  | // Upsize test buffer to be 2^n data pages (precondition of the impl) + 1 page | 
|  | // for the metadata. | 
|  | size_t total_size_pages = 1 + RoundToPow2(payload_size_pages); | 
|  |  | 
|  | // Clear spinlock field, as otherwise the read will wait indefinitely (it | 
|  | // defaults to indefinite blocking mode). | 
|  | SharedRingBuffer::MetadataPage header = {}; | 
|  | memcpy(&header, data, sizeof(header)); | 
|  | header.spinlock.locked = false; | 
|  | header.spinlock.poisoned = false; | 
|  |  | 
|  | PERFETTO_CHECK(ftruncate(*fd, static_cast<off_t>(total_size_pages * | 
|  | base::kPageSize)) == 0); | 
|  | PERFETTO_CHECK(base::WriteAll(*fd, &header, sizeof(header)) != -1); | 
|  | PERFETTO_CHECK(lseek(*fd, base::kPageSize, SEEK_SET) != -1); | 
|  | PERFETTO_CHECK(base::WriteAll(*fd, payload, payload_size) != -1); | 
|  |  | 
|  | auto buf = SharedRingBuffer::Attach(std::move(fd)); | 
|  | PERFETTO_CHECK(!!buf); | 
|  |  | 
|  | bool did_read; | 
|  | do { | 
|  | auto read_buf = buf->BeginRead(); | 
|  | did_read = bool(read_buf); | 
|  | if (did_read) { | 
|  | volatile uint8_t* v_data = read_buf.data; | 
|  | // Assert we get a reference to valid memory. | 
|  | for (size_t i = 0; i < read_buf.size; ++i) | 
|  | v_data[i] = v_data[i]; | 
|  | } | 
|  | buf->EndRead(std::move(read_buf)); | 
|  | } while (did_read); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace profiling | 
|  | }  // namespace perfetto | 
|  |  | 
|  | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); | 
|  |  | 
|  | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { | 
|  | return perfetto::profiling::FuzzRingBuffer(data, size); | 
|  | } |