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