|  | /* | 
|  | * Copyright 2020 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. | 
|  | */ | 
|  | // Authors: corbin.souffrant@leviathansecurity.com | 
|  | //          brian.balling@leviathansecurity.com | 
|  |  | 
|  | #ifndef LEV_FUZZERS_LIBPDX_HELPERS_H_ | 
|  | #define LEV_FUZZERS_LIBPDX_HELPERS_H_ | 
|  |  | 
|  | #define UNUSED(expr) \ | 
|  | do {               \ | 
|  | (void)(expr);    \ | 
|  | } while (0) | 
|  |  | 
|  | #include <fuzzer/FuzzedDataProvider.h> | 
|  | #include <pdx/client.h> | 
|  | #include <pdx/service.h> | 
|  | #include <pdx/service_dispatcher.h> | 
|  | #include <pdx/service_endpoint.h> | 
|  | #include <sys/eventfd.h> | 
|  | #include <memory> | 
|  | #include <vector> | 
|  |  | 
|  | using namespace android::pdx; | 
|  |  | 
|  | // Vector of operations we can call in the dispatcher. | 
|  | static const std::vector<std::function<void( | 
|  | const std::unique_ptr<ServiceDispatcher>&, FuzzedDataProvider*)>> | 
|  | dispatcher_operations = { | 
|  | [](const std::unique_ptr<ServiceDispatcher>& dispatcher, | 
|  | FuzzedDataProvider*) -> void { dispatcher->EnterDispatchLoop(); }, | 
|  | [](const std::unique_ptr<ServiceDispatcher>& dispatcher, | 
|  | FuzzedDataProvider*) -> void { dispatcher->ReceiveAndDispatch(); }, | 
|  | [](const std::unique_ptr<ServiceDispatcher>& dispatcher, | 
|  | FuzzedDataProvider* fdp) -> void { | 
|  | dispatcher->ReceiveAndDispatch(fdp->ConsumeIntegral<int>()); | 
|  | }}; | 
|  |  | 
|  | // Most of the fuzzing occurs within the endpoint, which is derived from an | 
|  | // abstract class. So we are returning garbage data for most functions besides | 
|  | // the ones we added or need to actually use. | 
|  | class FuzzEndpoint : public Endpoint { | 
|  | public: | 
|  | explicit FuzzEndpoint(FuzzedDataProvider* fdp) { | 
|  | _fdp = fdp; | 
|  | _epoll_fd = eventfd(0, 0); | 
|  | } | 
|  |  | 
|  | ~FuzzEndpoint() { close(_epoll_fd); } | 
|  |  | 
|  | // Returns an fd that can be used with epoll() to wait for incoming messages | 
|  | // from this endpoint. | 
|  | int epoll_fd() const { return _epoll_fd; } | 
|  |  | 
|  | // Associates a Service instance with an endpoint by setting the service | 
|  | // context pointer to the address of the Service. Only one Service may be | 
|  | // associated with a given endpoint. | 
|  | Status<void> SetService(Service* service) { | 
|  | _service = service; | 
|  | return Status<void>(0); | 
|  | } | 
|  |  | 
|  | // Set the channel context for the given channel. | 
|  | Status<void> SetChannel(int channel_id, Channel* channel) { | 
|  | UNUSED(channel_id); | 
|  | _channel = std::shared_ptr<Channel>(channel); | 
|  | return Status<void>(0); | 
|  | } | 
|  |  | 
|  | // Receives a message on the given endpoint file descriptor. | 
|  | // This is called by the dispatcher to determine what operations | 
|  | // to make, so we are fuzzing the response. | 
|  | Status<void> MessageReceive(Message* message) { | 
|  | // Create a randomized MessageInfo struct. | 
|  | MessageInfo info; | 
|  | eventfd_t wakeup_val = 0; | 
|  | info.pid = _fdp->ConsumeIntegral<int>(); | 
|  | info.tid = _fdp->ConsumeIntegral<int>(); | 
|  | info.cid = _fdp->ConsumeIntegral<int>(); | 
|  | info.mid = _fdp->ConsumeIntegral<int>(); | 
|  | info.euid = _fdp->ConsumeIntegral<int>(); | 
|  | info.egid = _fdp->ConsumeIntegral<int>(); | 
|  | info.op = _fdp->ConsumeIntegral<int32_t>(); | 
|  | info.flags = _fdp->ConsumeIntegral<uint32_t>(); | 
|  | info.service = _service; | 
|  | info.channel = _channel.get(); | 
|  | info.send_len = _fdp->ConsumeIntegral<size_t>(); | 
|  | info.recv_len = _fdp->ConsumeIntegral<size_t>(); | 
|  | info.fd_count = _fdp->ConsumeIntegral<size_t>(); | 
|  | if (_fdp->remaining_bytes() >= 32) { | 
|  | std::vector<uint8_t> impulse_vec = _fdp->ConsumeBytes<uint8_t>(32); | 
|  | memcpy(info.impulse, impulse_vec.data(), 32); | 
|  | } | 
|  |  | 
|  | *message = Message(info); | 
|  | eventfd_read(_epoll_fd, &wakeup_val); | 
|  |  | 
|  | return Status<void>(); | 
|  | } | 
|  |  | 
|  | // Returns a tag that uniquely identifies a specific underlying IPC | 
|  | // transport. | 
|  | uint32_t GetIpcTag() const { return 0; } | 
|  |  | 
|  | // Close a channel, signaling the client file object and freeing the channel | 
|  | // id. Once closed, the client side of the channel always returns the error | 
|  | // ESHUTDOWN and signals the poll/epoll events POLLHUP and POLLFREE. | 
|  | Status<void> CloseChannel(int channel_id) { | 
|  | UNUSED(channel_id); | 
|  | return Status<void>(); | 
|  | } | 
|  |  | 
|  | // Update the event bits for the given channel (given by id), using the | 
|  | // given clear and set masks. | 
|  | Status<void> ModifyChannelEvents(int channel_id, int clear_mask, | 
|  | int set_mask) { | 
|  | UNUSED(channel_id); | 
|  | UNUSED(clear_mask); | 
|  | UNUSED(set_mask); | 
|  | return Status<void>(); | 
|  | } | 
|  |  | 
|  | // Create a new channel and push it as a file descriptor to the process | 
|  | // sending the |message|. |flags| may be set to O_NONBLOCK and/or | 
|  | // O_CLOEXEC to control the initial behavior of the new file descriptor (the | 
|  | // sending process may change these later using fcntl()). The internal | 
|  | // Channel instance associated with this channel is set to |channel|, | 
|  | // which may be nullptr. The new channel id allocated for this channel is | 
|  | // returned in |channel_id|, which may also be nullptr if not needed. | 
|  | Status<RemoteChannelHandle> PushChannel(Message* message, int flags, | 
|  | Channel* channel, int* channel_id) { | 
|  | UNUSED(message); | 
|  | UNUSED(flags); | 
|  | UNUSED(channel); | 
|  | UNUSED(channel_id); | 
|  | return Status<RemoteChannelHandle>(); | 
|  | } | 
|  |  | 
|  | // Check whether the |ref| is a reference to a channel to the service | 
|  | // represented by the |endpoint|. If the channel reference in question is | 
|  | // valid, the Channel object is returned in |channel| when non-nullptr and | 
|  | // the channel ID is returned through the Status object. | 
|  | Status<int> CheckChannel(const Message* message, ChannelReference ref, | 
|  | Channel** channel) { | 
|  | UNUSED(message); | 
|  | UNUSED(ref); | 
|  | UNUSED(channel); | 
|  | return Status<int>(); | 
|  | } | 
|  |  | 
|  | // Replies to the message with a return code. | 
|  | Status<void> MessageReply(Message* message, int return_code) { | 
|  | UNUSED(message); | 
|  | UNUSED(return_code); | 
|  | return Status<void>(); | 
|  | } | 
|  |  | 
|  | // Replies to the message with a file descriptor. | 
|  | Status<void> MessageReplyFd(Message* message, unsigned int push_fd) { | 
|  | UNUSED(message); | 
|  | UNUSED(push_fd); | 
|  | return Status<void>(); | 
|  | } | 
|  |  | 
|  | // Replies to the message with a local channel handle. | 
|  | Status<void> MessageReplyChannelHandle(Message* message, | 
|  | const LocalChannelHandle& handle) { | 
|  | UNUSED(message); | 
|  | UNUSED(handle); | 
|  | return Status<void>(); | 
|  | } | 
|  |  | 
|  | // Replies to the message with a borrowed local channel handle. | 
|  | Status<void> MessageReplyChannelHandle(Message* message, | 
|  | const BorrowedChannelHandle& handle) { | 
|  | UNUSED(message); | 
|  | UNUSED(handle); | 
|  | return Status<void>(); | 
|  | } | 
|  |  | 
|  | // Replies to the message with a remote channel handle. | 
|  | Status<void> MessageReplyChannelHandle(Message* message, | 
|  | const RemoteChannelHandle& handle) { | 
|  | UNUSED(message); | 
|  | UNUSED(handle); | 
|  | return Status<void>(); | 
|  | } | 
|  |  | 
|  | // Reads message data into an array of memory buffers. | 
|  | Status<size_t> ReadMessageData(Message* message, const iovec* vector, | 
|  | size_t vector_length) { | 
|  | UNUSED(message); | 
|  | UNUSED(vector); | 
|  | UNUSED(vector_length); | 
|  | return Status<size_t>(); | 
|  | } | 
|  |  | 
|  | // Sends reply data for message. | 
|  | Status<size_t> WriteMessageData(Message* message, const iovec* vector, | 
|  | size_t vector_length) { | 
|  | UNUSED(message); | 
|  | UNUSED(vector); | 
|  | UNUSED(vector_length); | 
|  | return Status<size_t>(); | 
|  | } | 
|  |  | 
|  | // Records a file descriptor into the message buffer and returns the | 
|  | // remapped reference to be sent to the remote process. | 
|  | Status<FileReference> PushFileHandle(Message* message, | 
|  | const LocalHandle& handle) { | 
|  | UNUSED(message); | 
|  | UNUSED(handle); | 
|  | return Status<FileReference>(); | 
|  | } | 
|  |  | 
|  | Status<FileReference> PushFileHandle(Message* message, | 
|  | const BorrowedHandle& handle) { | 
|  | UNUSED(message); | 
|  | UNUSED(handle); | 
|  | return Status<FileReference>(); | 
|  | } | 
|  |  | 
|  | Status<FileReference> PushFileHandle(Message* message, | 
|  | const RemoteHandle& handle) { | 
|  | UNUSED(message); | 
|  | UNUSED(handle); | 
|  | return Status<FileReference>(); | 
|  | } | 
|  |  | 
|  | Status<ChannelReference> PushChannelHandle(Message* message, | 
|  | const LocalChannelHandle& handle) { | 
|  | UNUSED(message); | 
|  | UNUSED(handle); | 
|  | return Status<ChannelReference>(); | 
|  | } | 
|  |  | 
|  | Status<ChannelReference> PushChannelHandle( | 
|  | Message* message, const BorrowedChannelHandle& handle) { | 
|  | UNUSED(message); | 
|  | UNUSED(handle); | 
|  | return Status<ChannelReference>(); | 
|  | } | 
|  |  | 
|  | Status<ChannelReference> PushChannelHandle( | 
|  | Message* message, const RemoteChannelHandle& handle) { | 
|  | UNUSED(message); | 
|  | UNUSED(handle); | 
|  | return Status<ChannelReference>(); | 
|  | } | 
|  |  | 
|  | // Obtains a file descriptor/channel handle from a message for the given | 
|  | // reference. | 
|  | LocalHandle GetFileHandle(Message* message, FileReference ref) const { | 
|  | UNUSED(message); | 
|  | UNUSED(ref); | 
|  | return LocalHandle(); | 
|  | } | 
|  |  | 
|  | LocalChannelHandle GetChannelHandle(Message* message, | 
|  | ChannelReference ref) const { | 
|  | UNUSED(message); | 
|  | UNUSED(ref); | 
|  | return LocalChannelHandle(); | 
|  | } | 
|  |  | 
|  | // Transport-specific message state management. | 
|  | void* AllocateMessageState() { return nullptr; } | 
|  |  | 
|  | void FreeMessageState(void* state) { UNUSED(state); } | 
|  |  | 
|  | // Cancels the endpoint, unblocking any receiver threads waiting for a | 
|  | // message. | 
|  | Status<void> Cancel() { return Status<void>(); } | 
|  |  | 
|  | private: | 
|  | FuzzedDataProvider* _fdp; | 
|  | std::shared_ptr<Channel> _channel; | 
|  | Service* _service; | 
|  | int _epoll_fd; | 
|  | }; | 
|  |  | 
|  | #endif  // LEV_FUZZERS_LIBPDX_HELPERS_H_ |