Hi,

syzkaller and witness found the same bug I introduced in UDP also
for Raw IP.  Fix it the same was for rip and rip6.

https://syzkaller.appspot.com/bug?extid=9bac6356a881dc644265
https://syzkaller.appspot.com/bug?extid=5b2679ee9be0895d26f9

ok?

bluhm

Index: netinet/raw_ip.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/raw_ip.c,v
retrieving revision 1.125
diff -u -p -r1.125 raw_ip.c
--- netinet/raw_ip.c    21 Mar 2022 09:12:34 -0000      1.125
+++ netinet/raw_ip.c    22 Mar 2022 12:59:05 -0000
@@ -122,9 +122,9 @@ rip_input(struct mbuf **mp, int *offp, i
 {
        struct mbuf *m = *mp;
        struct ip *ip = mtod(m, struct ip *);
-       struct inpcb *inp, *last = NULL;
+       struct inpcb *inp;
+       SIMPLEQ_HEAD(, inpcb) inpcblist;
        struct in_addr *key;
-       struct mbuf *opts = NULL;
        struct counters_ref ref;
        uint64_t *counters;
 
@@ -150,7 +150,8 @@ rip_input(struct mbuf **mp, int *offp, i
                }
        }
 #endif
-       NET_ASSERT_LOCKED();
+       NET_ASSERT_WLOCKED();
+       SIMPLEQ_INIT(&inpcblist);
        mtx_enter(&rawcbtable.inpt_mtx);
        TAILQ_FOREACH(inp, &rawcbtable.inpt_queue, inp_queue) {
                if (inp->inp_socket->so_state & SS_CANTRCVMORE)
@@ -171,41 +172,16 @@ rip_input(struct mbuf **mp, int *offp, i
                if (inp->inp_faddr.s_addr &&
                    inp->inp_faddr.s_addr != ip->ip_src.s_addr)
                        continue;
-               if (last) {
-                       struct mbuf *n;
 
-                       if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) {
-                               if (last->inp_flags & INP_CONTROLOPTS ||
-                                   last->inp_socket->so_options & SO_TIMESTAMP)
-                                       ip_savecontrol(last, &opts, ip, n);
-                               if (sbappendaddr(last->inp_socket,
-                                   &last->inp_socket->so_rcv,
-                                   sintosa(&ripsrc), n, opts) == 0) {
-                                       /* should notify about lost packet */
-                                       m_freem(n);
-                                       m_freem(opts);
-                               } else
-                                       sorwakeup(last->inp_socket);
-                               opts = NULL;
-                       }
-               }
-               last = inp;
+               in_pcbref(inp);
+               SIMPLEQ_INSERT_TAIL(&inpcblist, inp, inp_notify);
        }
        mtx_leave(&rawcbtable.inpt_mtx);
 
-       if (last) {
-               if (last->inp_flags & INP_CONTROLOPTS ||
-                   last->inp_socket->so_options & SO_TIMESTAMP)
-                       ip_savecontrol(last, &opts, ip, m);
-               if (sbappendaddr(last->inp_socket, &last->inp_socket->so_rcv,
-                   sintosa(&ripsrc), m, opts) == 0) {
-                       m_freem(m);
-                       m_freem(opts);
-               } else
-                       sorwakeup(last->inp_socket);
-       } else {
+       if (SIMPLEQ_EMPTY(&inpcblist)) {
                if (ip->ip_p != IPPROTO_ICMP)
-                       icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 
0);
+                       icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL,
+                           0, 0);
                else
                        m_freem(m);
 
@@ -213,6 +189,30 @@ rip_input(struct mbuf **mp, int *offp, i
                counters[ips_noproto]++;
                counters[ips_delivered]--;
                counters_leave(&ref, ipcounters);
+       }
+
+       while ((inp = SIMPLEQ_FIRST(&inpcblist)) != NULL) {
+               struct mbuf *n, *opts = NULL;
+
+               SIMPLEQ_REMOVE_HEAD(&inpcblist, inp_notify);
+               if (SIMPLEQ_EMPTY(&inpcblist))
+                       n = m;
+               else
+                       n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
+               if (n != NULL) {
+                       if (inp->inp_flags & INP_CONTROLOPTS ||
+                           inp->inp_socket->so_options & SO_TIMESTAMP)
+                               ip_savecontrol(inp, &opts, ip, n);
+                       if (sbappendaddr(inp->inp_socket,
+                           &inp->inp_socket->so_rcv,
+                           sintosa(&ripsrc), n, opts) == 0) {
+                               /* should notify about lost packet */
+                               m_freem(n);
+                               m_freem(opts);
+                       } else
+                               sorwakeup(inp->inp_socket);
+               }
+               in_pcbunref(inp);
        }
        return IPPROTO_DONE;
 }
Index: netinet6/raw_ip6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/raw_ip6.c,v
retrieving revision 1.145
diff -u -p -r1.145 raw_ip6.c
--- netinet6/raw_ip6.c  21 Mar 2022 09:12:34 -0000      1.145
+++ netinet6/raw_ip6.c  22 Mar 2022 12:59:05 -0000
@@ -121,10 +121,9 @@ rip6_input(struct mbuf **mp, int *offp, 
        struct mbuf *m = *mp;
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        struct inpcb *in6p;
-       struct inpcb *last = NULL;
+       SIMPLEQ_HEAD(, inpcb) inpcblist;
        struct in6_addr *key;
        struct sockaddr_in6 rip6src;
-       struct mbuf *opts = NULL;
 
        KASSERT(af == AF_INET6);
 
@@ -156,7 +155,8 @@ rip6_input(struct mbuf **mp, int *offp, 
                }
        }
 #endif
-       NET_ASSERT_LOCKED();
+       NET_ASSERT_WLOCKED();
+       SIMPLEQ_INIT(&inpcblist);
        mtx_enter(&rawin6pcbtable.inpt_mtx);
        TAILQ_FOREACH(in6p, &rawin6pcbtable.inpt_queue, inp_queue) {
                if (in6p->inp_socket->so_state & SS_CANTRCVMORE)
@@ -183,7 +183,7 @@ rip6_input(struct mbuf **mp, int *offp, 
                            sizeof(*icmp6));
                        if (icmp6 == NULL) {
                                mtx_leave(&rawin6pcbtable.inpt_mtx);
-                               return IPPROTO_DONE;
+                               goto bad;
                        }
                        if (ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
                            in6p->inp_icmp6filt))
@@ -206,42 +206,13 @@ rip6_input(struct mbuf **mp, int *offp, 
                                continue;
                        }
                }
-               if (last) {
-                       struct  mbuf *n;
-                       if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) {
-                               if (last->inp_flags & IN6P_CONTROLOPTS)
-                                       ip6_savecontrol(last, n, &opts);
-                               /* strip intermediate headers */
-                               m_adj(n, *offp);
-                               if (sbappendaddr(last->inp_socket,
-                                   &last->inp_socket->so_rcv,
-                                   sin6tosa(&rip6src), n, opts) == 0) {
-                                       /* should notify about lost packet */
-                                       m_freem(n);
-                                       m_freem(opts);
-                                       rip6stat_inc(rip6s_fullsock);
-                               } else
-                                       sorwakeup(last->inp_socket);
-                               opts = NULL;
-                       }
-               }
-               last = in6p;
+
+               in_pcbref(in6p);
+               SIMPLEQ_INSERT_TAIL(&inpcblist, in6p, inp_notify);
        }
        mtx_leave(&rawin6pcbtable.inpt_mtx);
 
-       if (last) {
-               if (last->inp_flags & IN6P_CONTROLOPTS)
-                       ip6_savecontrol(last, m, &opts);
-               /* strip intermediate headers */
-               m_adj(m, *offp);
-               if (sbappendaddr(last->inp_socket, &last->inp_socket->so_rcv,
-                   sin6tosa(&rip6src), m, opts) == 0) {
-                       m_freem(m);
-                       m_freem(opts);
-                       rip6stat_inc(rip6s_fullsock);
-               } else
-                       sorwakeup(last->inp_socket);
-       } else {
+       if (SIMPLEQ_EMPTY(&inpcblist)) {
                struct counters_ref ref;
                uint64_t *counters;
 
@@ -261,6 +232,39 @@ rip6_input(struct mbuf **mp, int *offp, 
                counters = counters_enter(&ref, ip6counters);
                counters[ip6s_delivered]--;
                counters_leave(&ref, ip6counters);
+       }
+
+       while ((in6p = SIMPLEQ_FIRST(&inpcblist)) != NULL) {
+               struct mbuf *n, *opts = NULL;
+
+               SIMPLEQ_REMOVE_HEAD(&inpcblist, inp_notify);
+               if (SIMPLEQ_EMPTY(&inpcblist))
+                       n = m;
+               else
+                       n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
+               if (n != NULL) {
+                       if (in6p->inp_flags & IN6P_CONTROLOPTS)
+                               ip6_savecontrol(in6p, n, &opts);
+                       /* strip intermediate headers */
+                       m_adj(n, *offp);
+                       if (sbappendaddr(in6p->inp_socket,
+                           &in6p->inp_socket->so_rcv,
+                           sin6tosa(&rip6src), n, opts) == 0) {
+                               /* should notify about lost packet */
+                               m_freem(n);
+                               m_freem(opts);
+                               rip6stat_inc(rip6s_fullsock);
+                       } else
+                               sorwakeup(in6p->inp_socket);
+               }
+               in_pcbunref(in6p);
+       }
+       return IPPROTO_DONE;
+
+ bad:
+       while ((in6p = SIMPLEQ_FIRST(&inpcblist)) != NULL) {
+               SIMPLEQ_REMOVE_HEAD(&inpcblist, inp_notify);
+               in_pcbunref(in6p);
        }
        return IPPROTO_DONE;
 }

Reply via email to