/* * 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 #include #include #include #include #include #include #include using namespace android::pdx; // Vector of operations we can call in the dispatcher. static const std::vector&, FuzzedDataProvider*)>> dispatcher_operations = { [](const std::unique_ptr& dispatcher, FuzzedDataProvider*) -> void { dispatcher->EnterDispatchLoop(); }, [](const std::unique_ptr& dispatcher, FuzzedDataProvider*) -> void { dispatcher->ReceiveAndDispatch(); }, [](const std::unique_ptr& dispatcher, FuzzedDataProvider* fdp) -> void { dispatcher->ReceiveAndDispatch(fdp->ConsumeIntegral()); }}; // 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 SetService(Service* service) { _service = service; return Status(0); } // Set the channel context for the given channel. Status SetChannel(int channel_id, Channel* channel) { UNUSED(channel_id); _channel = std::shared_ptr(channel); return Status(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 MessageReceive(Message* message) { // Create a randomized MessageInfo struct. MessageInfo info; eventfd_t wakeup_val = 0; info.pid = _fdp->ConsumeIntegral(); info.tid = _fdp->ConsumeIntegral(); info.cid = _fdp->ConsumeIntegral(); info.mid = _fdp->ConsumeIntegral(); info.euid = _fdp->ConsumeIntegral(); info.egid = _fdp->ConsumeIntegral(); info.op = _fdp->ConsumeIntegral(); info.flags = _fdp->ConsumeIntegral(); info.service = _service; info.channel = _channel.get(); info.send_len = _fdp->ConsumeIntegral(); info.recv_len = _fdp->ConsumeIntegral(); info.fd_count = _fdp->ConsumeIntegral(); if (_fdp->remaining_bytes() >= 32) { std::vector impulse_vec = _fdp->ConsumeBytes(32); memcpy(info.impulse, impulse_vec.data(), 32); } *message = Message(info); eventfd_read(_epoll_fd, &wakeup_val); return Status(); } // 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 CloseChannel(int channel_id) { UNUSED(channel_id); return Status(); } // Update the event bits for the given channel (given by id), using the // given clear and set masks. Status ModifyChannelEvents(int channel_id, int clear_mask, int set_mask) { UNUSED(channel_id); UNUSED(clear_mask); UNUSED(set_mask); return Status(); } // 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 PushChannel(Message* message, int flags, Channel* channel, int* channel_id) { UNUSED(message); UNUSED(flags); UNUSED(channel); UNUSED(channel_id); return Status(); } // 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 CheckChannel(const Message* message, ChannelReference ref, Channel** channel) { UNUSED(message); UNUSED(ref); UNUSED(channel); return Status(); } // Replies to the message with a return code. Status MessageReply(Message* message, int return_code) { UNUSED(message); UNUSED(return_code); return Status(); } // Replies to the message with a file descriptor. Status MessageReplyFd(Message* message, unsigned int push_fd) { UNUSED(message); UNUSED(push_fd); return Status(); } // Replies to the message with a local channel handle. Status MessageReplyChannelHandle(Message* message, const LocalChannelHandle& handle) { UNUSED(message); UNUSED(handle); return Status(); } // Replies to the message with a borrowed local channel handle. Status MessageReplyChannelHandle(Message* message, const BorrowedChannelHandle& handle) { UNUSED(message); UNUSED(handle); return Status(); } // Replies to the message with a remote channel handle. Status MessageReplyChannelHandle(Message* message, const RemoteChannelHandle& handle) { UNUSED(message); UNUSED(handle); return Status(); } // Reads message data into an array of memory buffers. Status ReadMessageData(Message* message, const iovec* vector, size_t vector_length) { UNUSED(message); UNUSED(vector); UNUSED(vector_length); return Status(); } // Sends reply data for message. Status WriteMessageData(Message* message, const iovec* vector, size_t vector_length) { UNUSED(message); UNUSED(vector); UNUSED(vector_length); return Status(); } // Records a file descriptor into the message buffer and returns the // remapped reference to be sent to the remote process. Status PushFileHandle(Message* message, const LocalHandle& handle) { UNUSED(message); UNUSED(handle); return Status(); } Status PushFileHandle(Message* message, const BorrowedHandle& handle) { UNUSED(message); UNUSED(handle); return Status(); } Status PushFileHandle(Message* message, const RemoteHandle& handle) { UNUSED(message); UNUSED(handle); return Status(); } Status PushChannelHandle(Message* message, const LocalChannelHandle& handle) { UNUSED(message); UNUSED(handle); return Status(); } Status PushChannelHandle( Message* message, const BorrowedChannelHandle& handle) { UNUSED(message); UNUSED(handle); return Status(); } Status PushChannelHandle( Message* message, const RemoteChannelHandle& handle) { UNUSED(message); UNUSED(handle); return Status(); } // 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 Cancel() { return Status(); } private: FuzzedDataProvider* _fdp; std::shared_ptr _channel; Service* _service; int _epoll_fd; }; #endif // LEV_FUZZERS_LIBPDX_HELPERS_H_