Hey Simon,

today we discovered a segmentation fault in
forward.c:allocate_rfd().

It checks "if (serv->sfd)" before accessing "serv->sfd->fd".
However, we've seen that the value of serv->sfd can be arbitrary
nonsense (such as 0xa1), hence, the access causes a crash here.

The reason for this is that we allocate different amounts of
space in domain-match.c:add_update_server():

>       size_t size;
> 
>       if (flags & SERV_LITERAL_ADDRESS)
>       {
>         if (flags & SERV_6ADDR)
>           size = sizeof(struct serv_addr6);
>         else if (flags & SERV_4ADDR)
>           size = sizeof(struct serv_addr4);
>         else
>           size = sizeof(struct serv_local);
>       }
>       else
>       size = sizeof(struct server);
>       
>       if (!(serv = whine_malloc(size)))
>       return 0;

and store the result in daemon->servers as "struct server".

In the crash we've seen allocate_rfd() tried to access the struct
element ->sfd of an "struct serv_addr6" which obviously pointed
deeply into nowhere and sometimes happens to pick up some random
data eventually leading to a crash.

The attached patch tries to fix this by first checking if we are
really dealing with a full "struct server" here. I cannot get
dnsmasq to crash with it.

---

How to reproduce the crash yourself:

1. Use the attached config line.
2. Query "dig A mobile-ixanycast.ftl.netflix.com"
3. Repeat step no. 2 a few times until dnsmasq crashes.

---

Best,
Dominik
server=/netflix.com/#
address=/netflix.com/::
server=/netflix.net/#
address=/netflix.net/::
server=/nflxext.com/#
address=/nflxext.com/::
server=/nflximg.net/#
address=/nflximg.net/::
server=/nflxvideo.net/#
address=/nflxvideo.net/::
server=/swplus-aws.canal-plus.com/#
address=/swplus-aws.canal-plus.com/::
server=/canalplus-bo.net/#
address=/canalplus-bo.net/::
server=/canalplus-cdn.net/#
address=/canalplus-cdn.net/::
server=/apiwaka.azure-api.net/#
address=/apiwaka.azure-api.net/::
server=/wakanim-vid.akamaized.net/#
address=/wakanim-vid.akamaized.net/#
server=/wakanimksm.azurewebsites.net/#
address=/wakanimksm.azurewebsites.net/::
From 716387397b0e1cffc0238c4fc499478da08ade26 Mon Sep 17 00:00:00 2001
From: Dominik DL6ER <dl...@dl6er.de>
Date: Wed, 15 Sep 2021 17:50:43 +0200
Subject: [PATCH] allocate_rfd() tries to access the passed serv as struct
 server. However, the passed pointer may actually be a struct serv_addr4,
 serv_addr6, or serv_local. All of them are shorter and neither includes
 the field ->sfd. Hence, we first have to verify if serv really is of
 type struct server which can be done checking its flags.

Signed-off-by: DL6ER <dl...@dl6er.de>
---
 src/forward.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/forward.c b/src/forward.c
index f3c38d7..478258e 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -2229,7 +2229,9 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
   int fd = 0;
   
   /* If server has a pre-allocated fd, use that. */
-  if (serv->sfd)
+  /* Only do this when *serv is really a struct server pointer,
+     it could also be serv_addr4, serv_addr6, or serv_local */
+  if (!(serv->flags & SERV_LITERAL_ADDRESS) && serv->sfd)
     return serv->sfd->fd;
   
   /* existing suitable random port socket linked to this transaction? */
-- 
2.25.1

_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss

Reply via email to