On Tue, Sep 07, 2021 at 02:06:33PM +0200, Anton Lindqvist wrote:
> On Tue, Sep 07, 2021 at 03:56:00AM -0600, Vitaliy Makkoveev wrote:
> > CVSROOT:    /cvs
> > Module name:        src
> > Changes by: m...@cvs.openbsd.org    2021/09/07 03:56:00
> > 
> > Modified files:
> >     sys/net        : rtsock.c 
> > 
> > Log message:
> > Fix the race between if_detach() and rtm_output().
> > 
> > When the dying network interface descriptor has if_get(9) obtained
> > reference owned by foreign thread, the if_detach() thread will sleep
> > just after it removed this interface from the interface index map.
> > 
> > The data related to this interface is still in routing table, so
> > if_get(9) called by concurrent rtm_output() thread will return NULL and
> > the following "ifp != NULL" assertion will be triggered.
> > 
> > So remove the "ifp != NULL" assertions from rtm_output() and try to grab
> > `ifp' as early as possible then hold it until we finish the work. In the
> > case we won the race and we have `ifp' non NULL, concurrent if_detach()
> > thread will wait us. In the case we lost we just return ESRCH.
> > 
> > The problem reported by danj@.
> > Diff tested by danj@.
> > 
> > ok mpi@
> > 
> 
> syzkaller just found what looks like a NULL pointer derefence in
> rtm_output(). Regression introduced in this commit?
> 
>       https://syzkaller.appspot.com/bug?extid=684597dbbb9b516e76ae

Unfortunately yes. `rt' could be set to NULL before I call if_get(9) in
'RTM_CHANGE' path. I have a fix for this:

Index: sys/net/rtsock.c
===================================================================
RCS file: /cvs/src/sys/net/rtsock.c,v
retrieving revision 1.320
diff -u -p -r1.320 rtsock.c
--- sys/net/rtsock.c    7 Sep 2021 09:56:00 -0000       1.320
+++ sys/net/rtsock.c    7 Sep 2021 13:21:01 -0000
@@ -1032,14 +1032,6 @@ rtm_output(struct rt_msghdr *rtm, struct
                        rt = NULL;
                }
 
-               ifp = if_get(rt->rt_ifidx);
-               if (ifp == NULL) {
-                       rtfree(rt);
-                       rt = NULL;
-                       error = ESRCH;
-                       break;
-               }
-
                /*
                 * If RTAX_GATEWAY is the argument we're trying to
                 * change, try to find a compatible route.
@@ -1065,6 +1057,14 @@ rtm_output(struct rt_msghdr *rtm, struct
                 */
                if (ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST)) {
                        error = EINVAL;
+                       break;
+               }
+
+               ifp = if_get(rt->rt_ifidx);
+               if (ifp == NULL) {
+                       rtfree(rt);
+                       rt = NULL;
+                       error = ESRCH;
                        break;
                }
 

Reply via email to