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: [email protected] 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;
}