> On 22 Oct 2021, at 18:23, Alexander Bluhm <[email protected]> wrote:
> 
> On Thu, Oct 21, 2021 at 03:04:22PM +0300, Vitaliy Makkoveev wrote:
>> With this diff the `tdb' dereference after tdb_free() is safe enough and
>> I have no objections against your diff.
> 
> My diff did not make things worse, it counted the drops earlier.
> But I decided to drop that part, I would like just do commit the
> error cleanup.
> 
> Fixing the tdb destroy is another story.  I do not see how the
> NET_LOCK(); NET_UNLOCK() is a fix, it looks more like a hack.
> 

Yes, it’s a hack, but it works. We have the only thread which performs
tdb_destroy(). This thread holds exclusive netlock, so adding this
NET_LOCK(); NET_UNLOCK(); sequence to tdb_reaper() enforces it to wait
until the tdb_destroy() thread releases netlock. When tdb_destroy()
thread released netlock this “destroyed” `tdb’ will be not accessible
and it’s safe to release memory.

I like to have this hack committed until the tdb_destroy() fixed.

> ok to commit this error cleanup?
> 
> bluhm
> 

Yes, I just pointed the fragile place. But since it exists for a long
time and still not triggered I have no objections to commit your diff.

ok mvs@

> Index: netinet/ip_ah.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
> retrieving revision 1.157
> diff -u -p -r1.157 ip_ah.c
> --- netinet/ip_ah.c   21 Oct 2021 22:59:07 -0000      1.157
> +++ netinet/ip_ah.c   22 Oct 2021 14:41:53 -0000
> @@ -1164,6 +1164,7 @@ ah_output_cb(struct tdb *tdb, struct tdb
> {
>       int skip = tc->tc_skip;
>       caddr_t ptr = (caddr_t) (tc + 1);
> +     int error;
> 
>       /*
>        * Copy original headers (with the new protocol number) back
> @@ -1175,10 +1176,8 @@ ah_output_cb(struct tdb *tdb, struct tdb
>       free(tc, M_XDATA, 0);
> 
>       /* Call the IPsec input callback. */
> -     if (ipsp_process_done(m, tdb)) {
> +     error = ipsp_process_done(m, tdb);
> +     if (error)
>               ahstat_inc(ahs_outfail);
> -             return -1;
> -     }
> -
> -     return 0;
> +     return error;
> }
> Index: netinet/ip_esp.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v
> retrieving revision 1.176
> diff -u -p -r1.176 ip_esp.c
> --- netinet/ip_esp.c  21 Oct 2021 22:59:07 -0000      1.176
> +++ netinet/ip_esp.c  22 Oct 2021 14:42:27 -0000
> @@ -1024,16 +1024,16 @@ int
> esp_output_cb(struct tdb *tdb, struct tdb_crypto *tc, struct mbuf *m, int 
> ilen,
>     int olen)
> {
> +     int error;
> +
>       /* Release crypto descriptors. */
>       free(tc, M_XDATA, 0);
> 
>       /* Call the IPsec input callback. */
> -     if (ipsp_process_done(m, tdb)) {
> +     error = ipsp_process_done(m, tdb);
> +     if (error)
>               espstat_inc(esps_outfail);
> -             return -1;
> -     }
> -
> -     return 0;
> +     return error;
> }
> 
> #define SEEN_SIZE     howmany(TDB_REPLAYMAX, 32)
> Index: netinet/ip_ipcomp.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipcomp.c,v
> retrieving revision 1.78
> diff -u -p -r1.78 ip_ipcomp.c
> --- netinet/ip_ipcomp.c       22 Oct 2021 12:30:53 -0000      1.78
> +++ netinet/ip_ipcomp.c       22 Oct 2021 14:42:41 -0000
> @@ -505,6 +505,7 @@ ipcomp_output_cb(struct tdb *tdb, struct
> #ifdef ENCDEBUG
>       char buf[INET6_ADDRSTRLEN];
> #endif
> +     int error;
> 
>       skip = tc->tc_skip;
>       rlen = ilen - skip;
> @@ -523,7 +524,8 @@ ipcomp_output_cb(struct tdb *tdb, struct
>                   ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
>                   ntohl(tdb->tdb_spi));
>               ipcompstat_inc(ipcomps_wrap);
> -             goto baddone;
> +             error = ENOBUFS;
> +             goto drop;
>       }
> 
>       /* Initialize the IPCOMP header */
> @@ -552,21 +554,21 @@ ipcomp_output_cb(struct tdb *tdb, struct
>                   ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
>                   ntohl(tdb->tdb_spi));
>               ipcompstat_inc(ipcomps_nopf);
> -             goto baddone;
> +             error = EPFNOSUPPORT;
> +             goto drop;
>       }
> 
>  skiphdr:
>       /* Release the crypto descriptor. */
>       free(tc, M_XDATA, 0);
> 
> -     if (ipsp_process_done(m, tdb)) {
> +     error = ipsp_process_done(m, tdb);
> +     if (error)
>               ipcompstat_inc(ipcomps_outfail);
> -             return -1;
> -     }
> -     return 0;
> +     return error;
> 
> - baddone:
> + drop:
>       m_freem(m);
>       free(tc, M_XDATA, 0);
> -     return -1;
> +     return error;
> }
> Index: netinet/ip_ipip.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipip.c,v
> retrieving revision 1.95
> diff -u -p -r1.95 ip_ipip.c
> --- netinet/ip_ipip.c 13 Oct 2021 14:36:31 -0000      1.95
> +++ netinet/ip_ipip.c 22 Oct 2021 14:45:33 -0000
> @@ -524,7 +524,7 @@ ipip_output(struct mbuf **mp, struct tdb
>               DPRINTF("unsupported protocol family %d",
>                   tdb->tdb_dst.sa.sa_family);
>               ipipstat_inc(ipips_family);
> -             error = EAFNOSUPPORT;
> +             error = EPFNOSUPPORT;
>               goto drop;
>       }
> 
> Index: netinet/ipsec_input.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_input.c,v
> retrieving revision 1.184
> diff -u -p -r1.184 ipsec_input.c
> --- netinet/ipsec_input.c     13 Oct 2021 22:49:11 -0000      1.184
> +++ netinet/ipsec_input.c     22 Oct 2021 14:58:54 -0000
> @@ -359,10 +359,10 @@ ipsec_common_input(struct mbuf *m, int s
>       return error;
> 
>  drop:
> +     m_freem(m);
>       ipsecstat_inc(ipsec_idrops);
>       if (tdbp != NULL)
>               tdbp->tdb_idrops++;
> -     m_freem(m);
>       return error;
> }
> 
> @@ -423,7 +423,6 @@ ipsec_input_cb(struct cryptop *crp)
>               panic("%s: unknown/unsupported security protocol %d",
>                   __func__, tdb->tdb_sproto);
>       }
> -
>       if (error) {
>               ipsecstat_inc(ipsec_idrops);
>               tdb->tdb_idrops++;
> @@ -431,12 +430,12 @@ ipsec_input_cb(struct cryptop *crp)
>       return;
> 
>  drop:
> +     m_freem(m);
> +     free(tc, M_XDATA, 0);
> +     crypto_freereq(crp);
>       ipsecstat_inc(ipsec_idrops);
>       if (tdb != NULL)
>               tdb->tdb_idrops++;
> -     free(tc, M_XDATA, 0);
> -     m_freem(m);
> -     crypto_freereq(crp);
> }
> 
> /*
> @@ -448,19 +447,15 @@ ipsec_common_input_cb(struct mbuf *m, st
> {
>       int af, sproto;
>       u_int8_t prot;
> -
> #if NBPFILTER > 0
>       struct ifnet *encif;
> #endif
> -
>       struct ip *ip, ipn;
> -
> #ifdef INET6
>       struct ip6_hdr *ip6, ip6n;
> #endif /* INET6 */
>       struct m_tag *mtag;
>       struct tdb_ident *tdbi;
> -
> #ifdef ENCDEBUG
>       char buf[INET6_ADDRSTRLEN];
> #endif
> @@ -477,7 +472,7 @@ ipsec_common_input_cb(struct mbuf *m, st
>                           ipsp_address(&tdbp->tdb_dst, buf, sizeof(buf)),
>                           ntohl(tdbp->tdb_spi));
>                       IPSEC_ISTAT(esps_hdrops, ahs_hdrops, ipcomps_hdrops);
> -                     return -1;
> +                     goto baddone;
>               }
> 
>               ip = mtod(m, struct ip *);
> @@ -489,10 +484,9 @@ ipsec_common_input_cb(struct mbuf *m, st
>               /* IP-in-IP encapsulation */
>               if (prot == IPPROTO_IPIP) {
>                       if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
> -                             m_freem(m);
>                               IPSEC_ISTAT(esps_hdrops, ahs_hdrops,
>                                   ipcomps_hdrops);
> -                             return -1;
> +                             goto baddone;
>                       }
>                       /* ipn will now contain the inner IPv4 header */
>                       m_copydata(m, skip, sizeof(struct ip),
> @@ -503,10 +497,9 @@ ipsec_common_input_cb(struct mbuf *m, st
>               /* IPv6-in-IP encapsulation. */
>               if (prot == IPPROTO_IPV6) {
>                       if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
> -                             m_freem(m);
>                               IPSEC_ISTAT(esps_hdrops, ahs_hdrops,
>                                   ipcomps_hdrops);
> -                             return -1;
> +                             goto baddone;
>                       }
>                       /* ip6n will now contain the inner IPv6 header. */
>                       m_copydata(m, skip, sizeof(struct ip6_hdr),
> @@ -517,8 +510,7 @@ ipsec_common_input_cb(struct mbuf *m, st
> 
> #ifdef INET6
>       /* Fix IPv6 header */
> -     if (af == AF_INET6)
> -     {
> +     if (af == AF_INET6) {
>               if (m->m_len < sizeof(struct ip6_hdr) &&
>                   (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
> 
> @@ -526,7 +518,7 @@ ipsec_common_input_cb(struct mbuf *m, st
>                           ipsp_address(&tdbp->tdb_dst, buf, sizeof(buf)),
>                           ntohl(tdbp->tdb_spi));
>                       IPSEC_ISTAT(esps_hdrops, ahs_hdrops, ipcomps_hdrops);
> -                     return -1;
> +                     goto baddone;
>               }
> 
>               ip6 = mtod(m, struct ip6_hdr *);
> @@ -538,10 +530,9 @@ ipsec_common_input_cb(struct mbuf *m, st
>               /* IP-in-IP encapsulation */
>               if (prot == IPPROTO_IPIP) {
>                       if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
> -                             m_freem(m);
>                               IPSEC_ISTAT(esps_hdrops, ahs_hdrops,
>                                   ipcomps_hdrops);
> -                             return -1;
> +                             goto baddone;
>                       }
>                       /* ipn will now contain the inner IPv4 header */
>                       m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn);
> @@ -550,10 +541,9 @@ ipsec_common_input_cb(struct mbuf *m, st
>               /* IPv6-in-IP encapsulation */
>               if (prot == IPPROTO_IPV6) {
>                       if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
> -                             m_freem(m);
>                               IPSEC_ISTAT(esps_hdrops, ahs_hdrops,
>                                   ipcomps_hdrops);
> -                             return -1;
> +                             goto baddone;
>                       }
>                       /* ip6n will now contain the inner IPv6 header. */
>                       m_copydata(m, skip, sizeof(struct ip6_hdr),
> @@ -574,10 +564,9 @@ ipsec_common_input_cb(struct mbuf *m, st
>               switch (prot) {
>               case IPPROTO_UDP:
>                       if (m->m_pkthdr.len < skip + sizeof(struct udphdr)) {
> -                             m_freem(m);
>                               IPSEC_ISTAT(esps_hdrops, ahs_hdrops,
>                                   ipcomps_hdrops);
> -                             return -1;
> +                             goto baddone;
>                       }
>                       cksum = 0;
>                       m_copyback(m, skip + offsetof(struct udphdr, uh_sum),
> @@ -593,10 +582,9 @@ ipsec_common_input_cb(struct mbuf *m, st
>                       break;
>               case IPPROTO_TCP:
>                       if (m->m_pkthdr.len < skip + sizeof(struct tcphdr)) {
> -                             m_freem(m);
>                               IPSEC_ISTAT(esps_hdrops, ahs_hdrops,
>                                   ipcomps_hdrops);
> -                             return -1;
> +                             goto baddone;
>                       }
>                       cksum = 0;
>                       m_copyback(m, skip + offsetof(struct tcphdr, th_sum),
> @@ -623,10 +611,9 @@ ipsec_common_input_cb(struct mbuf *m, st
>               mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
>                   sizeof(struct tdb_ident), M_NOWAIT);
>               if (mtag == NULL) {
> -                     m_freem(m);
>                       DPRINTF("failed to get tag");
>                       IPSEC_ISTAT(esps_hdrops, ahs_hdrops, ipcomps_hdrops);
> -                     return -1;
> +                     goto baddone;
>               }
> 
>               tdbi = (struct tdb_ident *)(mtag + 1);
> @@ -703,22 +690,24 @@ ipsec_common_input_cb(struct mbuf *m, st
> 
>               /* This is the enc0 interface unless for ipcomp. */
>               if ((ifp = if_get(m->m_pkthdr.ph_ifidx)) == NULL) {
> -                     m_freem(m);
> -                     return -1;
> +                     goto baddone;
>               }
>               if (pf_test(af, PF_IN, ifp, &m) != PF_PASS) {
>                       if_put(ifp);
> -                     m_freem(m);
> -                     return -1;
> +                     goto baddone;
>               }
>               if_put(ifp);
>               if (m == NULL)
> -                     return -1;
> +                     return 0;
>       }
> #endif
>       /* Call the appropriate IPsec transform callback. */
>       ip_deliver(&m, &skip, prot, af);
>       return 0;
> +
> + baddone:
> +     m_freem(m);
> +     return -1;
> #undef IPSEC_ISTAT
> }
> 
> Index: netinet/ipsec_output.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_output.c,v
> retrieving revision 1.89
> diff -u -p -r1.89 ipsec_output.c
> --- netinet/ipsec_output.c    13 Oct 2021 22:43:44 -0000      1.89
> +++ netinet/ipsec_output.c    22 Oct 2021 15:02:38 -0000
> @@ -130,7 +130,7 @@ ipsp_process_packet(struct mbuf *m, stru
>                   ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
>                   ntohl(tdb->tdb_spi), tdb->tdb_sproto,
>                   tdb->tdb_dst.sa.sa_family);
> -             error = ENXIO;
> +             error = EPFNOSUPPORT;
>               goto drop;
>       }
> 
> @@ -348,7 +348,7 @@ ipsp_process_packet(struct mbuf *m, stru
>               break;
> #endif /* INET6 */
>       default:
> -             error = EINVAL;
> +             error = EPFNOSUPPORT;
>               goto drop;
>       }
> 
> @@ -434,10 +434,9 @@ ipsec_output_cb(struct cryptop *crp)
>               error = ipcomp_output_cb(tdb, tc, m, ilen, olen);
>               break;
>       default:
> -             panic("%s: unknown/unsupported security protocol %d",
> +             panic("%s: unhandled security protocol %d",
>                   __func__, tdb->tdb_sproto);
>       }
> -
>       if (error) {
>               ipsecstat_inc(ipsec_odrops);
>               tdb->tdb_odrops++;
> @@ -445,12 +444,12 @@ ipsec_output_cb(struct cryptop *crp)
>       return;
> 
>  drop:
> -     if (tdb != NULL)
> -             tdb->tdb_odrops++;
>       m_freem(m);
>       free(tc, M_XDATA, 0);
>       crypto_freereq(crp);
>       ipsecstat_inc(ipsec_odrops);
> +     if (tdb != NULL)
> +             tdb->tdb_odrops++;
> }
> 
> /*
> @@ -494,7 +493,7 @@ ipsp_process_done(struct mbuf *m, struct
>               default:
>                       DPRINTF("unknown protocol family (%d)",
>                           tdb->tdb_dst.sa.sa_family);
> -                     error = ENXIO;
> +                     error = EPFNOSUPPORT;
>                       goto drop;
>               }
> 
> @@ -548,7 +547,7 @@ ipsp_process_done(struct mbuf *m, struct
>       default:
>               DPRINTF("unknown protocol family (%d)",
>                   tdb->tdb_dst.sa.sa_family);
> -             error = ENXIO;
> +             error = EPFNOSUPPORT;
>               goto drop;
>       }
> 
> @@ -596,18 +595,22 @@ ipsp_process_done(struct mbuf *m, struct
>        */
>       switch (tdb->tdb_dst.sa.sa_family) {
>       case AF_INET:
> -             return (ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL, 0));
> -
> +             error = ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL, 0);
> +             break;
> #ifdef INET6
>       case AF_INET6:
>               /*
>                * We don't need massage, IPv6 header fields are always in
>                * net endian.
>                */
> -             return (ip6_output(m, NULL, NULL, 0, NULL, NULL));
> +             error = ip6_output(m, NULL, NULL, 0, NULL, NULL);
> +             break;
> #endif /* INET6 */
> +     default:
> +             error = EPFNOSUPPORT;
> +             break;
>       }
> -     error = EINVAL; /* Not reached. */
> +     return error;
> 
>  drop:
>       m_freem(m);

Reply via email to