• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2021 Google LLC
2 Licensed under the Apache License, Version 2.0 (the "License");
3 you may not use this file except in compliance with the License.
4 You may obtain a copy of the License at
5       http://www.apache.org/licenses/LICENSE-2.0
6 Unless required by applicable law or agreed to in writing, software
7 distributed under the License is distributed on an "AS IS" BASIS,
8 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 See the License for the specific language governing permissions and
10 limitations under the License.
11 */
12 
13 #include "dnsmasq.h"
14 
15 extern void fuzz_blockdata_cleanup();
16 
17 // Simple garbage collector
18 #define GB_SIZE 100
19 
20 void *pointer_arr[GB_SIZE];
21 static int pointer_idx = 0;
22 
23 // If the garbage collector is used then this must be called as first thing
24 // during a fuzz run.
gb_init()25 void gb_init() {
26   pointer_idx = 0;
27 
28    for (int i = 0; i < GB_SIZE; i++) {
29      pointer_arr[i] = NULL;
30    }
31 }
32 
gb_cleanup()33 void gb_cleanup() {
34   for(int i = 0; i < GB_SIZE; i++) {
35     if (pointer_arr[i] != NULL) {
36       free(pointer_arr[i]);
37     }
38   }
39 }
40 
get_null_terminated(const uint8_t ** data,size_t * size)41 char *get_null_terminated(const uint8_t **data, size_t *size) {
42 #define STR_SIZE 75
43   if (*size < STR_SIZE || (int)*size < 0) {
44     return NULL;
45   }
46 
47   char *new_s = malloc(STR_SIZE + 1);
48   memcpy(new_s, *data, STR_SIZE);
49   new_s[STR_SIZE] = '\0';
50 
51   *data = *data+STR_SIZE;
52   *size -= STR_SIZE;
53   return new_s;
54 }
55 
gb_get_random_data(const uint8_t ** data,size_t * size,size_t to_get)56 char *gb_get_random_data(const uint8_t **data, size_t *size, size_t to_get) {
57   if (*size < to_get || (int)*size < 0) {
58     return NULL;
59   }
60 
61   char *new_s = malloc(to_get);
62   memcpy(new_s, *data, to_get);
63 
64   pointer_arr[pointer_idx++] = (void*)new_s;
65 
66   *data = *data + to_get;
67   *size -= to_get;
68 
69   return new_s;
70 }
71 
gb_get_null_terminated(const uint8_t ** data,size_t * size)72 char *gb_get_null_terminated(const uint8_t **data, size_t *size) {
73 
74   char *nstr = get_null_terminated(data, size);
75   if (nstr == NULL) {
76     return NULL;
77   }
78   pointer_arr[pointer_idx++] = (void*)nstr;
79   return nstr;
80 }
81 
gb_alloc_data(size_t len)82 char *gb_alloc_data(size_t len) {
83   char *ptr = calloc(1, len);
84   pointer_arr[pointer_idx++] = (void*)ptr;
85 
86   return ptr;
87 }
88 
get_short(const uint8_t ** data,size_t * size)89 short get_short(const uint8_t **data, size_t *size) {
90   if (*size <= 0) return 0;
91   short c = (short)(*data)[0];
92   *data += 1;
93   *size-=1;
94   return c;
95 }
96 
get_int(const uint8_t ** data,size_t * size)97 int get_int(const uint8_t **data, size_t *size) {
98   if (*size <= 4) return 0;
99   const uint8_t *ptr = *data;
100   int val = *((int*)ptr);
101   *data += 4;
102   *size -= 4;
103   return val;
104 }
105 // end simple garbage collector.
106 
107 const uint8_t *syscall_data = NULL;
108 size_t syscall_size = 0;
109 
110 
fuzz_ioctl(int fd,unsigned long request,void * arg)111 int fuzz_ioctl(int fd, unsigned long request, void *arg) {
112   int fd2 = fd;
113   unsigned long request2 = request;
114   void *arg_ptr = arg;
115 
116   // SIOCGSTAMP
117   if (request == SIOCGSTAMP) {
118     struct timeval *tv = (struct timeval*)arg_ptr;
119     if (tv == NULL) {
120       return 0;
121     }
122 
123     char *rand_tv = gb_get_random_data(&syscall_data, &syscall_size, sizeof(struct timeval));
124     if (rand_tv == NULL) {
125       return -1;
126     }
127 
128     memcpy(tv, rand_tv, sizeof(struct timeval));
129     return 0;
130   }
131 
132   if (request == SIOCGIFNAME) {
133     //printf("We got a SIOCGIFNAME\n");
134     struct ifreq *ifr = (struct ifreq*)arg_ptr;
135     if (ifr == NULL) {
136       return -1;
137     }
138     for (int i = 0; i < IF_NAMESIZE; i++) {
139       if (syscall_size > 0 && syscall_data != NULL) {
140         ifr->ifr_name[i] = (char)*syscall_data;
141         syscall_data += 1;
142         syscall_size -= 1;
143       }
144       else {
145         ifr->ifr_name[i] = 'A';
146       }
147     }
148     ifr->ifr_name[IF_NAMESIZE-1] = '\0';
149     return 0;
150     //return -1;
151   }
152   if (request == SIOCGIFFLAGS) {
153     return 0;
154   }
155   if (request == SIOCGIFADDR) {
156     return 0;
157   }
158 
159   //
160   int retval = ioctl(fd2, request2, arg_ptr);
161   return retval;
162 }
163 
164 
165 // Sysytem call wrappers
166 static char v = 0;
fuzz_recvmsg(int sockfd,struct msghdr * msg,int flags)167 ssize_t fuzz_recvmsg(int sockfd, struct msghdr *msg, int flags) {
168 
169   struct iovec *target = msg->msg_iov;
170 
171   //printf("recvmsg 1 \n");
172   if (syscall_size > 1) {
173     char r = *syscall_data;
174     syscall_data += 1;
175     syscall_size -= 1;
176 
177     if (r == 12) {
178       //printf("recvmsg 2\n");
179       return -1;
180     }
181   }
182 
183   int j = 0;
184   if (msg->msg_control != NULL) {
185     for (;j < CMSG_SPACE(sizeof(struct in_pktinfo)); j++)
186     {
187       if (syscall_size > 0 && syscall_data != NULL) {
188         ((char*)msg->msg_control)[j] = *syscall_data;
189         syscall_data += 1;
190         syscall_size -= 1;
191       }
192       else {
193         ((char*)msg->msg_control)[j] = 'A';
194       }
195     }
196   }
197 
198   int i = 0;
199   for (; i < target->iov_len; i++) {
200     if (syscall_size > 0 && syscall_data != NULL) {
201       ((char*)target->iov_base)[i] = *syscall_data;
202       syscall_data += 1;
203       syscall_size -= 1;
204     }
205     else {
206       ((char*)target->iov_base)[i] = 'A';
207     }
208   }
209 
210   if (msg->msg_namelen > 0) {
211     memset(msg->msg_name, 0, msg->msg_namelen);
212   }
213 
214   return i;
215 }
216 
217 
218 // dnsmasq specific stuff
init_daemon(const uint8_t ** data2,size_t * size2)219 int init_daemon(const uint8_t **data2, size_t *size2) {
220   const uint8_t *data = *data2;
221   size_t size = *size2;
222 
223   int retval = 0;
224 
225 #define CLEAN_IF_NULL(arg) if (arg == NULL) goto cleanup;
226 
227   // Initialize daemon
228   daemon = (struct daemon*)gb_alloc_data(sizeof(struct daemon));
229   CLEAN_IF_NULL(daemon)
230 
231   // daemon misc
232   daemon->max_ttl = get_int(&data, &size);
233   daemon->neg_ttl = get_int(&data, &size);
234   daemon->local_ttl = get_int(&data, &size);
235   daemon->min_cache_ttl = get_int(&data, &size);
236 
237   // daemon->namebuff.
238   char *daemon_namebuff = gb_get_null_terminated(&data, &size);
239   daemon->namebuff = daemon_namebuff;
240 
241   // daemon->naptr
242   struct naptr *naptr_ptr = (struct naptr*)gb_alloc_data(sizeof(struct naptr));
243   char *naptr_name = gb_get_null_terminated(&data, &size);
244   char *naptr_replace = gb_get_null_terminated(&data, &size);
245   char *naptr_regexp = gb_get_null_terminated(&data, &size);
246   char *naptr_services = gb_get_null_terminated(&data, &size);
247   char *naptr_flags = gb_get_null_terminated(&data, &size);
248 
249   CLEAN_IF_NULL(naptr_ptr)
250   CLEAN_IF_NULL(naptr_name)
251   CLEAN_IF_NULL(naptr_replace)
252   CLEAN_IF_NULL(naptr_regexp)
253   CLEAN_IF_NULL(naptr_services)
254   CLEAN_IF_NULL(naptr_flags)
255 
256   naptr_ptr->name = naptr_name;
257   naptr_ptr->replace = naptr_replace;
258   naptr_ptr->regexp = naptr_regexp;
259   naptr_ptr->services = naptr_services;
260   naptr_ptr->flags = naptr_flags;
261 
262   daemon->naptr = naptr_ptr;
263 
264   // daemon->int_names
265   struct interface_name *int_namses = (struct interface_name*)gb_alloc_data(sizeof(struct interface_name));
266 
267   char *int_name = gb_get_null_terminated(&data, &size);
268   char *int_intr = gb_get_null_terminated(&data, &size);
269   CLEAN_IF_NULL(int_namses)
270   CLEAN_IF_NULL(int_name)
271   CLEAN_IF_NULL(int_intr)
272   int_namses->name = int_name;
273   int_namses->intr = int_intr;
274 
275   struct addrlist *d_addrlist = (struct addrlist*)gb_alloc_data(sizeof(struct addrlist));
276   CLEAN_IF_NULL(d_addrlist)
277   d_addrlist->flags = get_int(&data, &size);
278   d_addrlist->prefixlen = get_int(&data, &size);
279   int_namses->addr = d_addrlist;
280 
281   daemon->int_names = int_namses;
282 
283   if (size > *size2) {
284     goto cleanup;
285   }
286 
287   // daemon->addrbuf
288   char *adbuf = gb_alloc_data(200);
289   CLEAN_IF_NULL(adbuf)
290   daemon->addrbuff = adbuf;
291 
292   // daemon->auth_zones
293   struct auth_zone *d_az = (struct auth_zone*)gb_alloc_data(sizeof(struct auth_zone));
294   char *auth_domain = gb_get_null_terminated(&data, &size);
295 
296   CLEAN_IF_NULL(d_az)
297   CLEAN_IF_NULL(auth_domain)
298   d_az->domain = auth_domain;
299   daemon->auth_zones = d_az;
300 
301   // deamon->mxnames
302   struct mx_srv_record *mx_srv_rec = (struct mx_srv_record*)gb_alloc_data(sizeof(struct mx_srv_record));
303   char *mx_name = gb_get_null_terminated(&data, &size);
304   char *mx_target = gb_get_null_terminated(&data, &size);
305 
306   CLEAN_IF_NULL(mx_srv_rec)
307   CLEAN_IF_NULL(mx_target)
308   CLEAN_IF_NULL(mx_name)
309 
310   mx_srv_rec->next = daemon->mxnames;
311   daemon->mxnames = mx_srv_rec;
312   mx_srv_rec->name = mx_name;
313   mx_srv_rec->target = mx_target;
314   mx_srv_rec->issrv = get_int(&data, &size);
315   mx_srv_rec->weight = get_int(&data, &size);
316   mx_srv_rec->priority = get_int(&data, &size);
317   mx_srv_rec->srvport = get_int(&data, &size);
318   //data += 40;
319   //size -= 40;
320 
321   if (size > *size2) {
322     goto cleanup;
323   }
324 
325   // daemon->txt
326   struct txt_record *txt_record = (struct txt_record *)gb_alloc_data(sizeof(struct txt_record));
327   char *txt_record_name =  gb_get_null_terminated(&data, &size);
328   char *txt_record_txt = gb_get_null_terminated(&data, &size);
329 
330   CLEAN_IF_NULL(txt_record)
331   CLEAN_IF_NULL(txt_record_name)
332   CLEAN_IF_NULL(txt_record_txt)
333 
334   txt_record->name = txt_record_name;
335   txt_record->txt = (unsigned char*)txt_record_txt;
336   txt_record->class2 = (get_short(&data, &size) % 10);
337   daemon->txt = txt_record;
338 
339   // daemon->rr
340   struct txt_record *rr_record = (struct txt_record *)gb_alloc_data(sizeof(struct txt_record));
341   char *rr_record_name =  gb_get_null_terminated(&data, &size);
342   char *rr_record_txt = gb_get_null_terminated(&data, &size);
343 
344   CLEAN_IF_NULL(rr_record)
345   CLEAN_IF_NULL(rr_record_name)
346   CLEAN_IF_NULL(rr_record_txt)
347 
348   rr_record->name = rr_record_name;
349   rr_record->txt = (unsigned char*)rr_record_txt;
350   rr_record->class2 = (get_short(&data, &size) % 10);
351   daemon->rr = rr_record;
352 
353   if (size > *size2) {
354     goto cleanup;
355   }
356 
357   // daemon->relay4
358   //struct dhcp_relay *dr = (struct dhcp_relay*)gb_alloc_data(sizeof(struct dhcp_relay));
359   struct dhcp_relay *dr = (struct dhcp_relay*)gb_get_random_data(&data, &size, sizeof(struct dhcp_relay));
360   char *dr_interface = gb_get_null_terminated(&data, &size);
361 
362   CLEAN_IF_NULL(dr)
363   CLEAN_IF_NULL(dr_interface)
364   dr->interface = dr_interface;
365   dr->next = NULL;
366   dr->current = NULL;
367   daemon->relay4 = dr;
368 
369   // deamon->bridges
370   struct dhcp_bridge *db = (struct dhcp_bridge*)gb_alloc_data(sizeof(struct dhcp_bridge));
371   char *db_interface = gb_get_null_terminated(&data, &size);
372 
373   CLEAN_IF_NULL(db)
374   CLEAN_IF_NULL(db_interface)
375 
376   if (strlen(db_interface) > IF_NAMESIZE) {
377     for (int i = 0; i < IF_NAMESIZE; i++) {
378       db->iface[i] = db_interface[i];
379     }
380   } else {
381     for (int i = 0; i < strlen(db_interface); i++) {
382       db->iface[i] = db_interface[i];
383     }
384   }
385 
386 
387   struct dhcp_bridge *db_alias = (struct dhcp_bridge*)gb_alloc_data(sizeof(struct dhcp_bridge));
388   //struct dhcp_bridge *db_alias = (struct dhcp_bridge*)gb_get_random_data(&data, &size, sizeof(struct dhcp_bridge));
389   char *db_alias_interface = gb_get_null_terminated(&data, &size);
390 
391   CLEAN_IF_NULL(db_alias)
392   CLEAN_IF_NULL(db_alias_interface)
393 
394   if (strlen(db_alias_interface) > IF_NAMESIZE) {
395     for (int i = 0; i < IF_NAMESIZE; i++) {
396       db_alias->iface[i] = db_alias_interface[i];
397     }
398   } else {
399     for (int i = 0; i < strlen(db_alias_interface); i++) {
400       db_alias->iface[i] = db_alias_interface[i];
401     }
402   }
403   db->alias = db_alias;
404   daemon->bridges = db;
405 
406   // daemon->if_names
407   struct iname *in = (struct iname*)gb_get_random_data(&data, &size, sizeof(struct iname));
408   char *iname_name = gb_get_null_terminated(&data, &size);
409 
410   CLEAN_IF_NULL(in)
411   CLEAN_IF_NULL(iname_name)
412 
413   in->name = iname_name;
414   in->next = NULL;
415 
416   daemon->if_names = in;
417 
418   // daemon->if_addrs
419   struct iname *in_addr = (struct iname*)gb_get_random_data(&data, &size, sizeof(struct iname));
420   char *iname_name_addr = gb_get_null_terminated(&data, &size);
421 
422   CLEAN_IF_NULL(in_addr)
423   CLEAN_IF_NULL(iname_name_addr)
424 
425   in_addr->name = iname_name_addr;
426   in_addr->next = NULL;
427 
428   daemon->if_addrs = in_addr;
429 
430   // daemon->if_except
431   struct iname *in_except = (struct iname*)gb_get_random_data(&data, &size, sizeof(struct iname));
432   char *iname_name_except = gb_get_null_terminated(&data, &size);
433 
434   CLEAN_IF_NULL(in_except)
435   CLEAN_IF_NULL(iname_name_except)
436 
437   in_except->name = iname_name_except;
438   in_except->next = NULL;
439 
440   daemon->if_except = in_except;
441 
442   // daemon->dhcp_except
443   struct iname *except = (struct iname*)gb_get_random_data(&data, &size, sizeof(struct iname));
444   char *name_except = gb_get_null_terminated(&data, &size);
445 
446   CLEAN_IF_NULL(except)
447   CLEAN_IF_NULL(name_except)
448 
449   except->name = name_except;
450   except->next = NULL;
451 
452   daemon->dhcp_except = except;
453 
454   // daemon->authinterface
455   struct iname *auth_interface = (struct iname*)gb_get_random_data(&data, &size, sizeof(struct iname));
456   char *auth_name = gb_get_null_terminated(&data, &size);
457 
458   CLEAN_IF_NULL(auth_interface)
459   CLEAN_IF_NULL(auth_name)
460 
461   auth_interface->name = auth_name;
462   auth_interface->next = NULL;
463 
464   daemon->authinterface = auth_interface;
465 
466 
467   // daemon->cnames
468   struct cname *cn = (struct cname*)gb_alloc_data(sizeof(struct cname));
469   char *cname_alias = gb_get_null_terminated(&data, &size);
470   char *cname_target = gb_get_null_terminated(&data, &size);
471 
472   CLEAN_IF_NULL(cn)
473   CLEAN_IF_NULL(cname_alias)
474   CLEAN_IF_NULL(cname_target)
475 
476   cn->alias = cname_alias;
477   cn->target = cname_target;
478   daemon->cnames = cn;
479 
480 
481   // daemon->ptr
482   struct ptr_record *ptr = (struct ptr_record *)gb_alloc_data(sizeof(struct ptr_record));
483   CLEAN_IF_NULL(ptr)
484 
485   char *ptr_name = gb_get_null_terminated(&data, &size);
486   CLEAN_IF_NULL(ptr_name)
487   ptr->name = ptr_name;
488   daemon->ptr = ptr;
489 
490   if (size > *size2) {
491     goto cleanup;
492   }
493 
494   // daemon->dhcp
495   struct dhcp_context *dhcp_c = (struct dhcp_context *) gb_get_random_data(&data, &size, sizeof(struct dhcp_context));
496 
497   char *dhcp_c_temp_in = gb_get_null_terminated(&data, &size);
498 
499   struct dhcp_netid *dhcp_c_netid = (struct dhcp_netid *) gb_alloc_data(sizeof(struct dhcp_netid));
500   char *dhcp_netid_net = gb_get_null_terminated(&data, &size);
501 
502   CLEAN_IF_NULL(dhcp_c)
503   CLEAN_IF_NULL(dhcp_c_temp_in)
504   CLEAN_IF_NULL(dhcp_c_netid)
505   CLEAN_IF_NULL(dhcp_netid_net)
506 
507   dhcp_c->next = NULL;
508   dhcp_c->current = NULL;
509   dhcp_c_netid->net = dhcp_netid_net;
510   dhcp_c->filter = dhcp_c_netid;
511   dhcp_c->template_interface = dhcp_c_temp_in;
512 
513   daemon->dhcp = dhcp_c;
514 
515 
516   // daemon->dhcp6
517   struct dhcp_context *dhcp6_c = (struct dhcp_context *) gb_get_random_data(&data, &size, sizeof(struct dhcp_context));
518 
519   char *dhcp6_c_temp_in = gb_get_null_terminated(&data, &size);
520 
521   struct dhcp_netid *dhcp6_c_netid = (struct dhcp_netid *) gb_alloc_data(sizeof(struct dhcp_netid));
522   char *dhcp6_netid_net = gb_get_null_terminated(&data, &size);
523 
524   CLEAN_IF_NULL(dhcp6_c)
525   CLEAN_IF_NULL(dhcp6_c_temp_in)
526   CLEAN_IF_NULL(dhcp6_c_netid)
527   CLEAN_IF_NULL(dhcp6_netid_net)
528 
529   dhcp6_c->next = NULL;
530   dhcp6_c->current = NULL;
531   dhcp6_c_netid->net = dhcp6_netid_net;
532   dhcp6_c->filter = dhcp6_c_netid;
533   dhcp6_c->template_interface = dhcp6_c_temp_in;
534 
535   daemon->dhcp6 = dhcp6_c;
536 
537   // daemon->doing_dhcp6
538   daemon->doing_dhcp6 = 1;
539 
540   // daemon->dhcp_buffs
541   char *dhcp_buff = gb_alloc_data(DHCP_BUFF_SZ);
542   char *dhcp_buff2 = gb_alloc_data(DHCP_BUFF_SZ);
543   char *dhcp_buff3 = gb_alloc_data(DHCP_BUFF_SZ);
544 
545   CLEAN_IF_NULL(dhcp_buff)
546   CLEAN_IF_NULL(dhcp_buff2)
547   CLEAN_IF_NULL(dhcp_buff3)
548 
549   daemon->dhcp_buff = dhcp_buff;
550   daemon->dhcp_buff2 = dhcp_buff2;
551   daemon->dhcp_buff3 = dhcp_buff3;
552 
553 
554 
555   // daemon->ignore_addr
556   struct bogus_addr *bb = (struct bogus_addr *)gb_alloc_data(sizeof(struct bogus_addr));
557   CLEAN_IF_NULL(bb)
558 
559   daemon->ignore_addr = bb;
560 
561   // daemon->doctors
562   if (size > *size2) {
563     goto cleanup;
564   }
565 
566   struct doctor *doctors = (struct doctor *)gb_alloc_data(sizeof(struct doctor));
567   CLEAN_IF_NULL(doctors)
568 
569   doctors->next = NULL;
570   daemon->doctors = doctors;
571 
572   retval = 0;
573   goto ret;
574 cleanup:
575   retval = -1;
576 
577 ret:
578   return retval;
579 }
580