Corbin Souffrant | d3c7684 | 2020-06-05 18:54:11 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2020 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | // Authors: corbin.souffrant@leviathansecurity.com |
| 17 | // brian.balling@leviathansecurity.com |
| 18 | |
| 19 | #ifndef LEV_FUZZERS_LIBPDX_HELPERS_H_ |
| 20 | #define LEV_FUZZERS_LIBPDX_HELPERS_H_ |
| 21 | |
| 22 | #define UNUSED(expr) \ |
| 23 | do { \ |
| 24 | (void)(expr); \ |
| 25 | } while (0) |
| 26 | |
| 27 | #include <fuzzer/FuzzedDataProvider.h> |
| 28 | #include <pdx/client.h> |
| 29 | #include <pdx/service.h> |
| 30 | #include <pdx/service_dispatcher.h> |
| 31 | #include <pdx/service_endpoint.h> |
| 32 | #include <sys/eventfd.h> |
| 33 | #include <memory> |
| 34 | #include <vector> |
| 35 | |
| 36 | using namespace android::pdx; |
| 37 | |
| 38 | // Vector of operations we can call in the dispatcher. |
| 39 | static const std::vector<std::function<void( |
| 40 | const std::unique_ptr<ServiceDispatcher>&, FuzzedDataProvider*)>> |
| 41 | dispatcher_operations = { |
| 42 | [](const std::unique_ptr<ServiceDispatcher>& dispatcher, |
| 43 | FuzzedDataProvider*) -> void { dispatcher->EnterDispatchLoop(); }, |
| 44 | [](const std::unique_ptr<ServiceDispatcher>& dispatcher, |
| 45 | FuzzedDataProvider*) -> void { dispatcher->ReceiveAndDispatch(); }, |
| 46 | [](const std::unique_ptr<ServiceDispatcher>& dispatcher, |
| 47 | FuzzedDataProvider* fdp) -> void { |
| 48 | dispatcher->ReceiveAndDispatch(fdp->ConsumeIntegral<int>()); |
| 49 | }}; |
| 50 | |
| 51 | // Most of the fuzzing occurs within the endpoint, which is derived from an |
| 52 | // abstract class. So we are returning garbage data for most functions besides |
| 53 | // the ones we added or need to actually use. |
| 54 | class FuzzEndpoint : public Endpoint { |
| 55 | public: |
| 56 | explicit FuzzEndpoint(FuzzedDataProvider* fdp) { |
| 57 | _fdp = fdp; |
| 58 | _epoll_fd = eventfd(0, 0); |
| 59 | } |
| 60 | |
| 61 | ~FuzzEndpoint() { close(_epoll_fd); } |
| 62 | |
| 63 | // Returns an fd that can be used with epoll() to wait for incoming messages |
| 64 | // from this endpoint. |
| 65 | int epoll_fd() const { return _epoll_fd; } |
| 66 | |
| 67 | // Associates a Service instance with an endpoint by setting the service |
| 68 | // context pointer to the address of the Service. Only one Service may be |
| 69 | // associated with a given endpoint. |
| 70 | Status<void> SetService(Service* service) { |
| 71 | _service = service; |
| 72 | return Status<void>(0); |
| 73 | } |
| 74 | |
| 75 | // Set the channel context for the given channel. |
| 76 | Status<void> SetChannel(int channel_id, Channel* channel) { |
| 77 | UNUSED(channel_id); |
| 78 | _channel = std::shared_ptr<Channel>(channel); |
| 79 | return Status<void>(0); |
| 80 | } |
| 81 | |
| 82 | // Receives a message on the given endpoint file descriptor. |
| 83 | // This is called by the dispatcher to determine what operations |
| 84 | // to make, so we are fuzzing the response. |
| 85 | Status<void> MessageReceive(Message* message) { |
| 86 | // Create a randomized MessageInfo struct. |
| 87 | MessageInfo info; |
| 88 | eventfd_t wakeup_val = 0; |
| 89 | info.pid = _fdp->ConsumeIntegral<int>(); |
| 90 | info.tid = _fdp->ConsumeIntegral<int>(); |
| 91 | info.cid = _fdp->ConsumeIntegral<int>(); |
| 92 | info.mid = _fdp->ConsumeIntegral<int>(); |
| 93 | info.euid = _fdp->ConsumeIntegral<int>(); |
| 94 | info.egid = _fdp->ConsumeIntegral<int>(); |
| 95 | info.op = _fdp->ConsumeIntegral<int32_t>(); |
| 96 | info.flags = _fdp->ConsumeIntegral<uint32_t>(); |
| 97 | info.service = _service; |
| 98 | info.channel = _channel.get(); |
| 99 | info.send_len = _fdp->ConsumeIntegral<size_t>(); |
| 100 | info.recv_len = _fdp->ConsumeIntegral<size_t>(); |
| 101 | info.fd_count = _fdp->ConsumeIntegral<size_t>(); |
| 102 | if (_fdp->remaining_bytes() >= 32) { |
| 103 | std::vector<uint8_t> impulse_vec = _fdp->ConsumeBytes<uint8_t>(32); |
| 104 | memcpy(info.impulse, impulse_vec.data(), 32); |
| 105 | } |
| 106 | |
| 107 | *message = Message(info); |
| 108 | eventfd_read(_epoll_fd, &wakeup_val); |
| 109 | |
| 110 | return Status<void>(); |
| 111 | } |
| 112 | |
| 113 | // Returns a tag that uniquely identifies a specific underlying IPC |
| 114 | // transport. |
| 115 | uint32_t GetIpcTag() const { return 0; } |
| 116 | |
| 117 | // Close a channel, signaling the client file object and freeing the channel |
| 118 | // id. Once closed, the client side of the channel always returns the error |
| 119 | // ESHUTDOWN and signals the poll/epoll events POLLHUP and POLLFREE. |
| 120 | Status<void> CloseChannel(int channel_id) { |
| 121 | UNUSED(channel_id); |
| 122 | return Status<void>(); |
| 123 | } |
| 124 | |
| 125 | // Update the event bits for the given channel (given by id), using the |
| 126 | // given clear and set masks. |
| 127 | Status<void> ModifyChannelEvents(int channel_id, int clear_mask, |
| 128 | int set_mask) { |
| 129 | UNUSED(channel_id); |
| 130 | UNUSED(clear_mask); |
| 131 | UNUSED(set_mask); |
| 132 | return Status<void>(); |
| 133 | } |
| 134 | |
| 135 | // Create a new channel and push it as a file descriptor to the process |
| 136 | // sending the |message|. |flags| may be set to O_NONBLOCK and/or |
| 137 | // O_CLOEXEC to control the initial behavior of the new file descriptor (the |
| 138 | // sending process may change these later using fcntl()). The internal |
| 139 | // Channel instance associated with this channel is set to |channel|, |
| 140 | // which may be nullptr. The new channel id allocated for this channel is |
| 141 | // returned in |channel_id|, which may also be nullptr if not needed. |
| 142 | Status<RemoteChannelHandle> PushChannel(Message* message, int flags, |
| 143 | Channel* channel, int* channel_id) { |
| 144 | UNUSED(message); |
| 145 | UNUSED(flags); |
| 146 | UNUSED(channel); |
| 147 | UNUSED(channel_id); |
| 148 | return Status<RemoteChannelHandle>(); |
| 149 | } |
| 150 | |
| 151 | // Check whether the |ref| is a reference to a channel to the service |
| 152 | // represented by the |endpoint|. If the channel reference in question is |
| 153 | // valid, the Channel object is returned in |channel| when non-nullptr and |
| 154 | // the channel ID is returned through the Status object. |
| 155 | Status<int> CheckChannel(const Message* message, ChannelReference ref, |
| 156 | Channel** channel) { |
| 157 | UNUSED(message); |
| 158 | UNUSED(ref); |
| 159 | UNUSED(channel); |
| 160 | return Status<int>(); |
| 161 | } |
| 162 | |
| 163 | // Replies to the message with a return code. |
| 164 | Status<void> MessageReply(Message* message, int return_code) { |
| 165 | UNUSED(message); |
| 166 | UNUSED(return_code); |
| 167 | return Status<void>(); |
| 168 | } |
| 169 | |
| 170 | // Replies to the message with a file descriptor. |
| 171 | Status<void> MessageReplyFd(Message* message, unsigned int push_fd) { |
| 172 | UNUSED(message); |
| 173 | UNUSED(push_fd); |
| 174 | return Status<void>(); |
| 175 | } |
| 176 | |
| 177 | // Replies to the message with a local channel handle. |
| 178 | Status<void> MessageReplyChannelHandle(Message* message, |
| 179 | const LocalChannelHandle& handle) { |
| 180 | UNUSED(message); |
| 181 | UNUSED(handle); |
| 182 | return Status<void>(); |
| 183 | } |
| 184 | |
| 185 | // Replies to the message with a borrowed local channel handle. |
| 186 | Status<void> MessageReplyChannelHandle(Message* message, |
| 187 | const BorrowedChannelHandle& handle) { |
| 188 | UNUSED(message); |
| 189 | UNUSED(handle); |
| 190 | return Status<void>(); |
| 191 | } |
| 192 | |
| 193 | // Replies to the message with a remote channel handle. |
| 194 | Status<void> MessageReplyChannelHandle(Message* message, |
| 195 | const RemoteChannelHandle& handle) { |
| 196 | UNUSED(message); |
| 197 | UNUSED(handle); |
| 198 | return Status<void>(); |
| 199 | } |
| 200 | |
| 201 | // Reads message data into an array of memory buffers. |
| 202 | Status<size_t> ReadMessageData(Message* message, const iovec* vector, |
| 203 | size_t vector_length) { |
| 204 | UNUSED(message); |
| 205 | UNUSED(vector); |
| 206 | UNUSED(vector_length); |
| 207 | return Status<size_t>(); |
| 208 | } |
| 209 | |
| 210 | // Sends reply data for message. |
| 211 | Status<size_t> WriteMessageData(Message* message, const iovec* vector, |
| 212 | size_t vector_length) { |
| 213 | UNUSED(message); |
| 214 | UNUSED(vector); |
| 215 | UNUSED(vector_length); |
| 216 | return Status<size_t>(); |
| 217 | } |
| 218 | |
| 219 | // Records a file descriptor into the message buffer and returns the |
| 220 | // remapped reference to be sent to the remote process. |
| 221 | Status<FileReference> PushFileHandle(Message* message, |
| 222 | const LocalHandle& handle) { |
| 223 | UNUSED(message); |
| 224 | UNUSED(handle); |
| 225 | return Status<FileReference>(); |
| 226 | } |
| 227 | |
| 228 | Status<FileReference> PushFileHandle(Message* message, |
| 229 | const BorrowedHandle& handle) { |
| 230 | UNUSED(message); |
| 231 | UNUSED(handle); |
| 232 | return Status<FileReference>(); |
| 233 | } |
| 234 | |
| 235 | Status<FileReference> PushFileHandle(Message* message, |
| 236 | const RemoteHandle& handle) { |
| 237 | UNUSED(message); |
| 238 | UNUSED(handle); |
| 239 | return Status<FileReference>(); |
| 240 | } |
| 241 | |
| 242 | Status<ChannelReference> PushChannelHandle(Message* message, |
| 243 | const LocalChannelHandle& handle) { |
| 244 | UNUSED(message); |
| 245 | UNUSED(handle); |
| 246 | return Status<ChannelReference>(); |
| 247 | } |
| 248 | |
| 249 | Status<ChannelReference> PushChannelHandle( |
| 250 | Message* message, const BorrowedChannelHandle& handle) { |
| 251 | UNUSED(message); |
| 252 | UNUSED(handle); |
| 253 | return Status<ChannelReference>(); |
| 254 | } |
| 255 | |
| 256 | Status<ChannelReference> PushChannelHandle( |
| 257 | Message* message, const RemoteChannelHandle& handle) { |
| 258 | UNUSED(message); |
| 259 | UNUSED(handle); |
| 260 | return Status<ChannelReference>(); |
| 261 | } |
| 262 | |
| 263 | // Obtains a file descriptor/channel handle from a message for the given |
| 264 | // reference. |
| 265 | LocalHandle GetFileHandle(Message* message, FileReference ref) const { |
| 266 | UNUSED(message); |
| 267 | UNUSED(ref); |
| 268 | return LocalHandle(); |
| 269 | } |
| 270 | |
| 271 | LocalChannelHandle GetChannelHandle(Message* message, |
| 272 | ChannelReference ref) const { |
| 273 | UNUSED(message); |
| 274 | UNUSED(ref); |
| 275 | return LocalChannelHandle(); |
| 276 | } |
| 277 | |
| 278 | // Transport-specific message state management. |
| 279 | void* AllocateMessageState() { return nullptr; } |
| 280 | |
| 281 | void FreeMessageState(void* state) { UNUSED(state); } |
| 282 | |
| 283 | // Cancels the endpoint, unblocking any receiver threads waiting for a |
| 284 | // message. |
| 285 | Status<void> Cancel() { return Status<void>(); } |
| 286 | |
| 287 | private: |
| 288 | FuzzedDataProvider* _fdp; |
| 289 | std::shared_ptr<Channel> _channel; |
| 290 | Service* _service; |
| 291 | int _epoll_fd; |
| 292 | }; |
| 293 | |
| 294 | #endif // LEV_FUZZERS_LIBPDX_HELPERS_H_ |