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: FuzzEndpoint(FuzzedDataProvider * fdp)56 explicit FuzzEndpoint(FuzzedDataProvider* fdp) { 57 _fdp = fdp; 58 _epoll_fd = eventfd(0, 0); 59 } 60 ~FuzzEndpoint()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. epoll_fd()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. SetService(Service * service)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. SetChannel(int channel_id,Channel * 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. MessageReceive(Message * message)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. GetIpcTag()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. CloseChannel(int channel_id)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. ModifyChannelEvents(int channel_id,int clear_mask,int set_mask)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. PushChannel(Message * message,int flags,Channel * channel,int * channel_id)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. CheckChannel(const Message * message,ChannelReference ref,Channel ** channel)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. MessageReply(Message * message,int 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. MessageReplyFd(Message * message,unsigned int push_fd)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. MessageReplyChannelHandle(Message * message,const LocalChannelHandle & 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. MessageReplyChannelHandle(Message * message,const BorrowedChannelHandle & 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. MessageReplyChannelHandle(Message * message,const RemoteChannelHandle & 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. ReadMessageData(Message * message,const iovec * vector,size_t vector_length)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. WriteMessageData(Message * message,const iovec * vector,size_t vector_length)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. PushFileHandle(Message * message,const LocalHandle & handle)221 Status<FileReference> PushFileHandle(Message* message, 222 const LocalHandle& handle) { 223 UNUSED(message); 224 UNUSED(handle); 225 return Status<FileReference>(); 226 } 227 PushFileHandle(Message * message,const BorrowedHandle & handle)228 Status<FileReference> PushFileHandle(Message* message, 229 const BorrowedHandle& handle) { 230 UNUSED(message); 231 UNUSED(handle); 232 return Status<FileReference>(); 233 } 234 PushFileHandle(Message * message,const RemoteHandle & handle)235 Status<FileReference> PushFileHandle(Message* message, 236 const RemoteHandle& handle) { 237 UNUSED(message); 238 UNUSED(handle); 239 return Status<FileReference>(); 240 } 241 PushChannelHandle(Message * message,const LocalChannelHandle & handle)242 Status<ChannelReference> PushChannelHandle(Message* message, 243 const LocalChannelHandle& handle) { 244 UNUSED(message); 245 UNUSED(handle); 246 return Status<ChannelReference>(); 247 } 248 PushChannelHandle(Message * message,const BorrowedChannelHandle & handle)249 Status<ChannelReference> PushChannelHandle( 250 Message* message, const BorrowedChannelHandle& handle) { 251 UNUSED(message); 252 UNUSED(handle); 253 return Status<ChannelReference>(); 254 } 255 PushChannelHandle(Message * message,const RemoteChannelHandle & handle)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. GetFileHandle(Message * message,FileReference ref)265 LocalHandle GetFileHandle(Message* message, FileReference ref) const { 266 UNUSED(message); 267 UNUSED(ref); 268 return LocalHandle(); 269 } 270 GetChannelHandle(Message * message,ChannelReference ref)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. AllocateMessageState()279 void* AllocateMessageState() { return nullptr; } 280 FreeMessageState(void * state)281 void FreeMessageState(void* state) { UNUSED(state); } 282 283 // Cancels the endpoint, unblocking any receiver threads waiting for a 284 // message. Cancel()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_ 295