Re: ipsec crypto kernel lock

2021-06-17 Thread Vitaliy Makkoveev
On Thu, Jun 17, 2021 at 03:19:11PM +0200, Alexander Bluhm wrote:
> On Thu, Jun 17, 2021 at 10:09:47AM +0200, Martin Pieuchot wrote:
> > It's not clear to me which field is the KERNEL_LOCK() protecting.  Is it
> > the access to `swcr_sessions'?  Is it a reference?  If so grabbing/releasing
> > the lock might not be enough to fix the use-after-free.
> 
> I am running the fix for nearly a day now.  Seems to be stable.  I
> guess the crash is a regression from unlocking the pfkey socket.
> Rekeying had the kernel lock before, now it does not.  Calling
> crypto operations without kernel lock looks wrong.  There is no
> other locking in crypto.
> 
> > Could you annotate which field is being protected by the KERNEL_LOCK()? 
> 
> No.  I do not want to invest into fine grained crypto locking.  I
> need a stable test machine.  If you think my aporoach of throwing
> the kernel lock between the boundary of network stack, pfkey and
> crypto is too naive, I would suggest that we backoout the pfkey
> unlocking.
> 
> But my aproach is stable and has less locks than before.  I think
> it is an improvement.

We perform crypto(9) access from net stack without kernel lock held, so
pfkey unlocking backout could not be enough and 'tdbp->tdb_xform->xf_*'
routines should be also wrapped by kernel lock. So this diff is welcomed
anyway.

> 
> bluhm
> 
> > > Index: netinet/ip_ah.c
> > > ===
> > > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
> > > retrieving revision 1.146
> > > diff -u -p -r1.146 ip_ah.c
> > > --- netinet/ip_ah.c   25 Feb 2021 02:48:21 -  1.146
> > > +++ netinet/ip_ah.c   16 Jun 2021 17:29:37 -
> > > @@ -98,6 +98,7 @@ ah_init(struct tdb *tdbp, struct xformsw
> > >  {
> > >   struct auth_hash *thash = NULL;
> > >   struct cryptoini cria, crin;
> > > + int error;
> > >  
> > >   /* Authentication operation. */
> > >   switch (ii->ii_authalg) {
> > > @@ -162,7 +163,10 @@ ah_init(struct tdb *tdbp, struct xformsw
> > >   cria.cri_next = 
> > >   }
> > >  
> > > - return crypto_newsession(>tdb_cryptoid, , 0);
> > > + KERNEL_LOCK();
> > > + error = crypto_newsession(>tdb_cryptoid, , 0);
> > > + KERNEL_UNLOCK();
> > > + return error;
> > >  }
> > >  
> > >  /*
> > > @@ -171,7 +175,7 @@ ah_init(struct tdb *tdbp, struct xformsw
> > >  int
> > >  ah_zeroize(struct tdb *tdbp)
> > >  {
> > > - int err;
> > > + int error;
> > >  
> > >   if (tdbp->tdb_amxkey) {
> > >   explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
> > > @@ -179,9 +183,11 @@ ah_zeroize(struct tdb *tdbp)
> > >   tdbp->tdb_amxkey = NULL;
> > >   }
> > >  
> > > - err = crypto_freesession(tdbp->tdb_cryptoid);
> > > + KERNEL_LOCK();
> > > + error = crypto_freesession(tdbp->tdb_cryptoid);
> > > + KERNEL_UNLOCK();
> > >   tdbp->tdb_cryptoid = 0;
> > > - return err;
> > > + return error;
> > >  }
> > >  
> > >  /*
> > > @@ -626,7 +632,9 @@ ah_input(struct mbuf *m, struct tdb *tdb
> > >   }
> > >  
> > >   /* Get crypto descriptors. */
> > > + KERNEL_LOCK();
> > >   crp = crypto_getreq(1);
> > > + KERNEL_UNLOCK();
> > >   if (crp == NULL) {
> > >   DPRINTF(("%s: failed to acquire crypto descriptors\n",
> > >   __func__));
> > > @@ -696,11 +704,16 @@ ah_input(struct mbuf *m, struct tdb *tdb
> > >   tc->tc_rdomain = tdb->tdb_rdomain;
> > >   memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
> > >  
> > > - return crypto_dispatch(crp);
> > > + KERNEL_LOCK();
> > > + error = crypto_dispatch(crp);
> > > + KERNEL_UNLOCK();
> > > + return error;
> > >  
> > >   drop:
> > >   m_freem(m);
> > > + KERNEL_LOCK();
> > >   crypto_freereq(crp);
> > > + KERNEL_UNLOCK();
> > >   free(tc, M_XDATA, 0);
> > >   return error;
> > >  }
> > > @@ -1047,7 +1060,9 @@ ah_output(struct mbuf *m, struct tdb *td
> > >  #endif
> > >  
> > >   /* Get crypto descriptors. */
> > > + KERNEL_LOCK();
> > >   crp = crypto_getreq(1);
> > > + KERNEL_UNLOCK();
> > >   if (crp == NULL) {
> > >   DPRINTF(("%s: failed to acquire crypto descriptors\n",
> > >   __func__));
> > > @@ -1144,11 +1159,16 @@ ah_output(struct mbuf *m, struct tdb *td
> > >   tc->tc_rdomain = tdb->tdb_rdomain;
> > >   memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
> > >  
> > > - return crypto_dispatch(crp);
> > > + KERNEL_LOCK();
> > > + error = crypto_dispatch(crp);
> > > + KERNEL_UNLOCK();
> > > + return error;
> > >  
> > >   drop:
> > >   m_freem(m);
> > > + KERNEL_LOCK();
> > >   crypto_freereq(crp);
> > > + KERNEL_UNLOCK();
> > >   free(tc, M_XDATA, 0);
> > >   return error;
> > >  }
> > > Index: netinet/ip_esp.c
> > > ===
> > > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v
> > > retrieving revision 1.162
> > > diff -u -p -r1.162 ip_esp.c
> > > --- netinet/ip_esp.c  25 Feb 2021 02:48:21 -  1.162
> > > +++ netinet/ip_esp.c  16 Jun 2021 17:29:55 -
> > 

Re: ipsec crypto kernel lock

2021-06-17 Thread Alexander Bluhm
On Thu, Jun 17, 2021 at 10:09:47AM +0200, Martin Pieuchot wrote:
> It's not clear to me which field is the KERNEL_LOCK() protecting.  Is it
> the access to `swcr_sessions'?  Is it a reference?  If so grabbing/releasing
> the lock might not be enough to fix the use-after-free.

I am running the fix for nearly a day now.  Seems to be stable.  I
guess the crash is a regression from unlocking the pfkey socket.
Rekeying had the kernel lock before, now it does not.  Calling
crypto operations without kernel lock looks wrong.  There is no
other locking in crypto.

> Could you annotate which field is being protected by the KERNEL_LOCK()? 

No.  I do not want to invest into fine grained crypto locking.  I
need a stable test machine.  If you think my aporoach of throwing
the kernel lock between the boundary of network stack, pfkey and
crypto is too naive, I would suggest that we backoout the pfkey
unlocking.

But my aproach is stable and has less locks than before.  I think
it is an improvement.

bluhm

> > Index: netinet/ip_ah.c
> > ===
> > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
> > retrieving revision 1.146
> > diff -u -p -r1.146 ip_ah.c
> > --- netinet/ip_ah.c 25 Feb 2021 02:48:21 -  1.146
> > +++ netinet/ip_ah.c 16 Jun 2021 17:29:37 -
> > @@ -98,6 +98,7 @@ ah_init(struct tdb *tdbp, struct xformsw
> >  {
> > struct auth_hash *thash = NULL;
> > struct cryptoini cria, crin;
> > +   int error;
> >  
> > /* Authentication operation. */
> > switch (ii->ii_authalg) {
> > @@ -162,7 +163,10 @@ ah_init(struct tdb *tdbp, struct xformsw
> > cria.cri_next = 
> > }
> >  
> > -   return crypto_newsession(>tdb_cryptoid, , 0);
> > +   KERNEL_LOCK();
> > +   error = crypto_newsession(>tdb_cryptoid, , 0);
> > +   KERNEL_UNLOCK();
> > +   return error;
> >  }
> >  
> >  /*
> > @@ -171,7 +175,7 @@ ah_init(struct tdb *tdbp, struct xformsw
> >  int
> >  ah_zeroize(struct tdb *tdbp)
> >  {
> > -   int err;
> > +   int error;
> >  
> > if (tdbp->tdb_amxkey) {
> > explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
> > @@ -179,9 +183,11 @@ ah_zeroize(struct tdb *tdbp)
> > tdbp->tdb_amxkey = NULL;
> > }
> >  
> > -   err = crypto_freesession(tdbp->tdb_cryptoid);
> > +   KERNEL_LOCK();
> > +   error = crypto_freesession(tdbp->tdb_cryptoid);
> > +   KERNEL_UNLOCK();
> > tdbp->tdb_cryptoid = 0;
> > -   return err;
> > +   return error;
> >  }
> >  
> >  /*
> > @@ -626,7 +632,9 @@ ah_input(struct mbuf *m, struct tdb *tdb
> > }
> >  
> > /* Get crypto descriptors. */
> > +   KERNEL_LOCK();
> > crp = crypto_getreq(1);
> > +   KERNEL_UNLOCK();
> > if (crp == NULL) {
> > DPRINTF(("%s: failed to acquire crypto descriptors\n",
> > __func__));
> > @@ -696,11 +704,16 @@ ah_input(struct mbuf *m, struct tdb *tdb
> > tc->tc_rdomain = tdb->tdb_rdomain;
> > memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
> >  
> > -   return crypto_dispatch(crp);
> > +   KERNEL_LOCK();
> > +   error = crypto_dispatch(crp);
> > +   KERNEL_UNLOCK();
> > +   return error;
> >  
> >   drop:
> > m_freem(m);
> > +   KERNEL_LOCK();
> > crypto_freereq(crp);
> > +   KERNEL_UNLOCK();
> > free(tc, M_XDATA, 0);
> > return error;
> >  }
> > @@ -1047,7 +1060,9 @@ ah_output(struct mbuf *m, struct tdb *td
> >  #endif
> >  
> > /* Get crypto descriptors. */
> > +   KERNEL_LOCK();
> > crp = crypto_getreq(1);
> > +   KERNEL_UNLOCK();
> > if (crp == NULL) {
> > DPRINTF(("%s: failed to acquire crypto descriptors\n",
> > __func__));
> > @@ -1144,11 +1159,16 @@ ah_output(struct mbuf *m, struct tdb *td
> > tc->tc_rdomain = tdb->tdb_rdomain;
> > memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
> >  
> > -   return crypto_dispatch(crp);
> > +   KERNEL_LOCK();
> > +   error = crypto_dispatch(crp);
> > +   KERNEL_UNLOCK();
> > +   return error;
> >  
> >   drop:
> > m_freem(m);
> > +   KERNEL_LOCK();
> > crypto_freereq(crp);
> > +   KERNEL_UNLOCK();
> > free(tc, M_XDATA, 0);
> > return error;
> >  }
> > Index: netinet/ip_esp.c
> > ===
> > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v
> > retrieving revision 1.162
> > diff -u -p -r1.162 ip_esp.c
> > --- netinet/ip_esp.c25 Feb 2021 02:48:21 -  1.162
> > +++ netinet/ip_esp.c16 Jun 2021 17:29:55 -
> > @@ -93,6 +93,7 @@ esp_init(struct tdb *tdbp, struct xforms
> > struct enc_xform *txform = NULL;
> > struct auth_hash *thash = NULL;
> > struct cryptoini cria, crie, crin;
> > +   int error;
> >  
> > if (!ii->ii_encalg && !ii->ii_authalg) {
> > DPRINTF(("esp_init(): neither authentication nor encryption "
> > @@ -294,8 +295,11 @@ esp_init(struct tdb *tdbp, struct xforms
> > cria.cri_key = 

Re: ipsec crypto kernel lock

2021-06-17 Thread Martin Pieuchot
On 16/06/21(Wed) 22:05, Alexander Bluhm wrote:
> Hi,
> 
> I have seen a kernel crash with while forwarding and encrypting
> much traffic through OpenBSD IPsec gateways running iked.
> 
> kernel: protection fault trap, code=0
> Stopped at  aes_ctr_crypt+0x1e: addb$0x1,0x2e3(%rdi)
> 
> ddb{2}> trace
> aes_ctr_crypt(16367ed4be021a53,8000246e1db0) at aes_ctr_crypt+0x1e
> swcr_authenc(fd8132a21b08) at swcr_authenc+0x5c3
> swcr_process(fd8132a21b08) at swcr_process+0x1e8
> crypto_invoke(fd8132a21b08) at crypto_invoke+0xde
> taskq_thread(80200500) at taskq_thread+0x81
> end trace frame: 0x0, count: -5
> 
> *64926  109760  0  0  7 0x14200crypto
> 
> swcr_authenc() passes swe->sw_kschedule to aes_ctr_crypt(), swe has
> been freed and contains deaf006cdeaf4152, which looks like some
> sort of poison.  I suspect a use after free.
> 
> The swe value comes from the swcr_sessions global pointers.  Its
> content looks sane in ddb.  Noone touches it in swcr_authenc().  So
> I guess that an other CPU changes the global structures while
> swcr_authenc() is working with it.
> 
> The crypto thread is protected by kernel lock, both network stack
> and pfkey use net lock.  The kernel lock has been recently removed
> from pfkey.
> 
> I think the required lock for the crypto framework is the kernel
> lock.  If crypto_ functions are called, IPsec must grab the kernel
> lock.  pfkey accesses crypto only via tdb_ functions, so this diff
> also covers that case.

It's not clear to me which field is the KERNEL_LOCK() protecting.  Is it
the access to `swcr_sessions'?  Is it a reference?  If so grabbing/releasing
the lock might not be enough to fix the use-after-free.

Could you annotate which field is being protected by the KERNEL_LOCK()? 

> Index: netinet/ip_ah.c
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
> retrieving revision 1.146
> diff -u -p -r1.146 ip_ah.c
> --- netinet/ip_ah.c   25 Feb 2021 02:48:21 -  1.146
> +++ netinet/ip_ah.c   16 Jun 2021 17:29:37 -
> @@ -98,6 +98,7 @@ ah_init(struct tdb *tdbp, struct xformsw
>  {
>   struct auth_hash *thash = NULL;
>   struct cryptoini cria, crin;
> + int error;
>  
>   /* Authentication operation. */
>   switch (ii->ii_authalg) {
> @@ -162,7 +163,10 @@ ah_init(struct tdb *tdbp, struct xformsw
>   cria.cri_next = 
>   }
>  
> - return crypto_newsession(>tdb_cryptoid, , 0);
> + KERNEL_LOCK();
> + error = crypto_newsession(>tdb_cryptoid, , 0);
> + KERNEL_UNLOCK();
> + return error;
>  }
>  
>  /*
> @@ -171,7 +175,7 @@ ah_init(struct tdb *tdbp, struct xformsw
>  int
>  ah_zeroize(struct tdb *tdbp)
>  {
> - int err;
> + int error;
>  
>   if (tdbp->tdb_amxkey) {
>   explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
> @@ -179,9 +183,11 @@ ah_zeroize(struct tdb *tdbp)
>   tdbp->tdb_amxkey = NULL;
>   }
>  
> - err = crypto_freesession(tdbp->tdb_cryptoid);
> + KERNEL_LOCK();
> + error = crypto_freesession(tdbp->tdb_cryptoid);
> + KERNEL_UNLOCK();
>   tdbp->tdb_cryptoid = 0;
> - return err;
> + return error;
>  }
>  
>  /*
> @@ -626,7 +632,9 @@ ah_input(struct mbuf *m, struct tdb *tdb
>   }
>  
>   /* Get crypto descriptors. */
> + KERNEL_LOCK();
>   crp = crypto_getreq(1);
> + KERNEL_UNLOCK();
>   if (crp == NULL) {
>   DPRINTF(("%s: failed to acquire crypto descriptors\n",
>   __func__));
> @@ -696,11 +704,16 @@ ah_input(struct mbuf *m, struct tdb *tdb
>   tc->tc_rdomain = tdb->tdb_rdomain;
>   memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
>  
> - return crypto_dispatch(crp);
> + KERNEL_LOCK();
> + error = crypto_dispatch(crp);
> + KERNEL_UNLOCK();
> + return error;
>  
>   drop:
>   m_freem(m);
> + KERNEL_LOCK();
>   crypto_freereq(crp);
> + KERNEL_UNLOCK();
>   free(tc, M_XDATA, 0);
>   return error;
>  }
> @@ -1047,7 +1060,9 @@ ah_output(struct mbuf *m, struct tdb *td
>  #endif
>  
>   /* Get crypto descriptors. */
> + KERNEL_LOCK();
>   crp = crypto_getreq(1);
> + KERNEL_UNLOCK();
>   if (crp == NULL) {
>   DPRINTF(("%s: failed to acquire crypto descriptors\n",
>   __func__));
> @@ -1144,11 +1159,16 @@ ah_output(struct mbuf *m, struct tdb *td
>   tc->tc_rdomain = tdb->tdb_rdomain;
>   memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
>  
> - return crypto_dispatch(crp);
> + KERNEL_LOCK();
> + error = crypto_dispatch(crp);
> + KERNEL_UNLOCK();
> + return error;
>  
>   drop:
>   m_freem(m);
> + KERNEL_LOCK();
>   crypto_freereq(crp);
> + KERNEL_UNLOCK();
>   free(tc, M_XDATA, 0);
>   return error;
>  }
> Index: netinet/ip_esp.c
> 

Re: ipsec crypto kernel lock

2021-06-16 Thread Vitaliy Makkoveev
ok mvs@

> On 17 Jun 2021, at 01:06, Alexander Bluhm  wrote:
> 
> On Wed, Jun 16, 2021 at 11:58:48PM +0300, Vitaliy Makkoveev wrote:
>> crypto_getreq() and crypto_freereq() don???t require kernel lock.
> 
> Indeed, new diff.
> 
> ok?
> 
> bluhm
> 
> Index: netinet/ip_ah.c
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
> retrieving revision 1.146
> diff -u -p -r1.146 ip_ah.c
> --- netinet/ip_ah.c   25 Feb 2021 02:48:21 -  1.146
> +++ netinet/ip_ah.c   16 Jun 2021 21:59:38 -
> @@ -98,6 +98,7 @@ ah_init(struct tdb *tdbp, struct xformsw
> {
>   struct auth_hash *thash = NULL;
>   struct cryptoini cria, crin;
> + int error;
> 
>   /* Authentication operation. */
>   switch (ii->ii_authalg) {
> @@ -162,7 +163,10 @@ ah_init(struct tdb *tdbp, struct xformsw
>   cria.cri_next = 
>   }
> 
> - return crypto_newsession(>tdb_cryptoid, , 0);
> + KERNEL_LOCK();
> + error = crypto_newsession(>tdb_cryptoid, , 0);
> + KERNEL_UNLOCK();
> + return error;
> }
> 
> /*
> @@ -171,7 +175,7 @@ ah_init(struct tdb *tdbp, struct xformsw
> int
> ah_zeroize(struct tdb *tdbp)
> {
> - int err;
> + int error;
> 
>   if (tdbp->tdb_amxkey) {
>   explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
> @@ -179,9 +183,11 @@ ah_zeroize(struct tdb *tdbp)
>   tdbp->tdb_amxkey = NULL;
>   }
> 
> - err = crypto_freesession(tdbp->tdb_cryptoid);
> + KERNEL_LOCK();
> + error = crypto_freesession(tdbp->tdb_cryptoid);
> + KERNEL_UNLOCK();
>   tdbp->tdb_cryptoid = 0;
> - return err;
> + return error;
> }
> 
> /*
> @@ -696,7 +702,10 @@ ah_input(struct mbuf *m, struct tdb *tdb
>   tc->tc_rdomain = tdb->tdb_rdomain;
>   memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
> 
> - return crypto_dispatch(crp);
> + KERNEL_LOCK();
> + error = crypto_dispatch(crp);
> + KERNEL_UNLOCK();
> + return error;
> 
>  drop:
>   m_freem(m);
> @@ -1144,7 +1153,10 @@ ah_output(struct mbuf *m, struct tdb *td
>   tc->tc_rdomain = tdb->tdb_rdomain;
>   memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
> 
> - return crypto_dispatch(crp);
> + KERNEL_LOCK();
> + error = crypto_dispatch(crp);
> + KERNEL_UNLOCK();
> + return error;
> 
>  drop:
>   m_freem(m);
> Index: netinet/ip_esp.c
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v
> retrieving revision 1.162
> diff -u -p -r1.162 ip_esp.c
> --- netinet/ip_esp.c  25 Feb 2021 02:48:21 -  1.162
> +++ netinet/ip_esp.c  16 Jun 2021 22:00:08 -
> @@ -93,6 +93,7 @@ esp_init(struct tdb *tdbp, struct xforms
>   struct enc_xform *txform = NULL;
>   struct auth_hash *thash = NULL;
>   struct cryptoini cria, crie, crin;
> + int error;
> 
>   if (!ii->ii_encalg && !ii->ii_authalg) {
>   DPRINTF(("esp_init(): neither authentication nor encryption "
> @@ -294,8 +295,11 @@ esp_init(struct tdb *tdbp, struct xforms
>   cria.cri_key = ii->ii_authkey;
>   }
> 
> - return crypto_newsession(>tdb_cryptoid,
> + KERNEL_LOCK();
> + error = crypto_newsession(>tdb_cryptoid,
>   (tdbp->tdb_encalgxform ?  : ), 0);
> + KERNEL_UNLOCK();
> + return error;
> }
> 
> /*
> @@ -304,7 +308,7 @@ esp_init(struct tdb *tdbp, struct xforms
> int
> esp_zeroize(struct tdb *tdbp)
> {
> - int err;
> + int error;
> 
>   if (tdbp->tdb_amxkey) {
>   explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
> @@ -318,9 +322,11 @@ esp_zeroize(struct tdb *tdbp)
>   tdbp->tdb_emxkey = NULL;
>   }
> 
> - err = crypto_freesession(tdbp->tdb_cryptoid);
> + KERNEL_LOCK();
> + error = crypto_freesession(tdbp->tdb_cryptoid);
> + KERNEL_UNLOCK();
>   tdbp->tdb_cryptoid = 0;
> - return err;
> + return error;
> }
> 
> #define MAXBUFSIZ (AH_ALEN_MAX > ESP_MAX_IVS ? AH_ALEN_MAX : ESP_MAX_IVS)
> @@ -519,7 +525,10 @@ esp_input(struct mbuf *m, struct tdb *td
>   crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
>   }
> 
> - return crypto_dispatch(crp);
> + KERNEL_LOCK();
> + error = crypto_dispatch(crp);
> + KERNEL_UNLOCK();
> + return error;
> 
>  drop:
>   m_freem(m);
> @@ -1006,7 +1015,10 @@ esp_output(struct mbuf *m, struct tdb *t
>   crda->crd_len = m->m_pkthdr.len - (skip + alen);
>   }
> 
> - return crypto_dispatch(crp);
> + KERNEL_LOCK();
> + error = crypto_dispatch(crp);
> + KERNEL_UNLOCK();
> + return error;
> 
>  drop:
>   m_freem(m);
> Index: netinet/ip_ipcomp.c
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipcomp.c,v
> retrieving revision 1.67
> diff -u -p -r1.67 ip_ipcomp.c
> --- 

Re: ipsec crypto kernel lock

2021-06-16 Thread Alexander Bluhm
On Wed, Jun 16, 2021 at 11:58:48PM +0300, Vitaliy Makkoveev wrote:
> crypto_getreq() and crypto_freereq() don???t require kernel lock.

Indeed, new diff.

ok?

bluhm

Index: netinet/ip_ah.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
retrieving revision 1.146
diff -u -p -r1.146 ip_ah.c
--- netinet/ip_ah.c 25 Feb 2021 02:48:21 -  1.146
+++ netinet/ip_ah.c 16 Jun 2021 21:59:38 -
@@ -98,6 +98,7 @@ ah_init(struct tdb *tdbp, struct xformsw
 {
struct auth_hash *thash = NULL;
struct cryptoini cria, crin;
+   int error;
 
/* Authentication operation. */
switch (ii->ii_authalg) {
@@ -162,7 +163,10 @@ ah_init(struct tdb *tdbp, struct xformsw
cria.cri_next = 
}
 
-   return crypto_newsession(>tdb_cryptoid, , 0);
+   KERNEL_LOCK();
+   error = crypto_newsession(>tdb_cryptoid, , 0);
+   KERNEL_UNLOCK();
+   return error;
 }
 
 /*
@@ -171,7 +175,7 @@ ah_init(struct tdb *tdbp, struct xformsw
 int
 ah_zeroize(struct tdb *tdbp)
 {
-   int err;
+   int error;
 
if (tdbp->tdb_amxkey) {
explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
@@ -179,9 +183,11 @@ ah_zeroize(struct tdb *tdbp)
tdbp->tdb_amxkey = NULL;
}
 
-   err = crypto_freesession(tdbp->tdb_cryptoid);
+   KERNEL_LOCK();
+   error = crypto_freesession(tdbp->tdb_cryptoid);
+   KERNEL_UNLOCK();
tdbp->tdb_cryptoid = 0;
-   return err;
+   return error;
 }
 
 /*
@@ -696,7 +702,10 @@ ah_input(struct mbuf *m, struct tdb *tdb
tc->tc_rdomain = tdb->tdb_rdomain;
memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
 
-   return crypto_dispatch(crp);
+   KERNEL_LOCK();
+   error = crypto_dispatch(crp);
+   KERNEL_UNLOCK();
+   return error;
 
  drop:
m_freem(m);
@@ -1144,7 +1153,10 @@ ah_output(struct mbuf *m, struct tdb *td
tc->tc_rdomain = tdb->tdb_rdomain;
memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
 
-   return crypto_dispatch(crp);
+   KERNEL_LOCK();
+   error = crypto_dispatch(crp);
+   KERNEL_UNLOCK();
+   return error;
 
  drop:
m_freem(m);
Index: netinet/ip_esp.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v
retrieving revision 1.162
diff -u -p -r1.162 ip_esp.c
--- netinet/ip_esp.c25 Feb 2021 02:48:21 -  1.162
+++ netinet/ip_esp.c16 Jun 2021 22:00:08 -
@@ -93,6 +93,7 @@ esp_init(struct tdb *tdbp, struct xforms
struct enc_xform *txform = NULL;
struct auth_hash *thash = NULL;
struct cryptoini cria, crie, crin;
+   int error;
 
if (!ii->ii_encalg && !ii->ii_authalg) {
DPRINTF(("esp_init(): neither authentication nor encryption "
@@ -294,8 +295,11 @@ esp_init(struct tdb *tdbp, struct xforms
cria.cri_key = ii->ii_authkey;
}
 
-   return crypto_newsession(>tdb_cryptoid,
+   KERNEL_LOCK();
+   error = crypto_newsession(>tdb_cryptoid,
(tdbp->tdb_encalgxform ?  : ), 0);
+   KERNEL_UNLOCK();
+   return error;
 }
 
 /*
@@ -304,7 +308,7 @@ esp_init(struct tdb *tdbp, struct xforms
 int
 esp_zeroize(struct tdb *tdbp)
 {
-   int err;
+   int error;
 
if (tdbp->tdb_amxkey) {
explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
@@ -318,9 +322,11 @@ esp_zeroize(struct tdb *tdbp)
tdbp->tdb_emxkey = NULL;
}
 
-   err = crypto_freesession(tdbp->tdb_cryptoid);
+   KERNEL_LOCK();
+   error = crypto_freesession(tdbp->tdb_cryptoid);
+   KERNEL_UNLOCK();
tdbp->tdb_cryptoid = 0;
-   return err;
+   return error;
 }
 
 #define MAXBUFSIZ (AH_ALEN_MAX > ESP_MAX_IVS ? AH_ALEN_MAX : ESP_MAX_IVS)
@@ -519,7 +525,10 @@ esp_input(struct mbuf *m, struct tdb *td
crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
}
 
-   return crypto_dispatch(crp);
+   KERNEL_LOCK();
+   error = crypto_dispatch(crp);
+   KERNEL_UNLOCK();
+   return error;
 
  drop:
m_freem(m);
@@ -1006,7 +1015,10 @@ esp_output(struct mbuf *m, struct tdb *t
crda->crd_len = m->m_pkthdr.len - (skip + alen);
}
 
-   return crypto_dispatch(crp);
+   KERNEL_LOCK();
+   error = crypto_dispatch(crp);
+   KERNEL_UNLOCK();
+   return error;
 
  drop:
m_freem(m);
Index: netinet/ip_ipcomp.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipcomp.c,v
retrieving revision 1.67
diff -u -p -r1.67 ip_ipcomp.c
--- netinet/ip_ipcomp.c 30 Sep 2019 01:53:05 -  1.67
+++ netinet/ip_ipcomp.c 16 Jun 2021 22:00:45 -
@@ -79,6 +79,7 @@ ipcomp_init(struct tdb *tdbp, struct xfo
 {

Re: ipsec crypto kernel lock

2021-06-16 Thread Vitaliy Makkoveev
Hi,

crypto_getreq() and crypto_freereq() don’t require kernel lock.

> On 16 Jun 2021, at 23:05, Alexander Bluhm  wrote:
> 
> Hi,
> 
> I have seen a kernel crash with while forwarding and encrypting
> much traffic through OpenBSD IPsec gateways running iked.
> 
> kernel: protection fault trap, code=0
> Stopped at  aes_ctr_crypt+0x1e: addb$0x1,0x2e3(%rdi)
> 
> ddb{2}> trace
> aes_ctr_crypt(16367ed4be021a53,8000246e1db0) at aes_ctr_crypt+0x1e
> swcr_authenc(fd8132a21b08) at swcr_authenc+0x5c3
> swcr_process(fd8132a21b08) at swcr_process+0x1e8
> crypto_invoke(fd8132a21b08) at crypto_invoke+0xde
> taskq_thread(80200500) at taskq_thread+0x81
> end trace frame: 0x0, count: -5
> 
> *64926  109760  0  0  7 0x14200crypto
> 
> swcr_authenc() passes swe->sw_kschedule to aes_ctr_crypt(), swe has
> been freed and contains deaf006cdeaf4152, which looks like some
> sort of poison.  I suspect a use after free.
> 
> The swe value comes from the swcr_sessions global pointers.  Its
> content looks sane in ddb.  Noone touches it in swcr_authenc().  So
> I guess that an other CPU changes the global structures while
> swcr_authenc() is working with it.
> 
> The crypto thread is protected by kernel lock, both network stack
> and pfkey use net lock.  The kernel lock has been recently removed
> from pfkey.
> 
> I think the required lock for the crypto framework is the kernel
> lock.  If crypto_ functions are called, IPsec must grab the kernel
> lock.  pfkey accesses crypto only via tdb_ functions, so this diff
> also covers that case.
> 
> ok?
> 
> bluhm
> 
> Index: netinet/ip_ah.c
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
> retrieving revision 1.146
> diff -u -p -r1.146 ip_ah.c
> --- netinet/ip_ah.c   25 Feb 2021 02:48:21 -  1.146
> +++ netinet/ip_ah.c   16 Jun 2021 17:29:37 -
> @@ -98,6 +98,7 @@ ah_init(struct tdb *tdbp, struct xformsw
> {
>   struct auth_hash *thash = NULL;
>   struct cryptoini cria, crin;
> + int error;
> 
>   /* Authentication operation. */
>   switch (ii->ii_authalg) {
> @@ -162,7 +163,10 @@ ah_init(struct tdb *tdbp, struct xformsw
>   cria.cri_next = 
>   }
> 
> - return crypto_newsession(>tdb_cryptoid, , 0);
> + KERNEL_LOCK();
> + error = crypto_newsession(>tdb_cryptoid, , 0);
> + KERNEL_UNLOCK();
> + return error;
> }
> 
> /*
> @@ -171,7 +175,7 @@ ah_init(struct tdb *tdbp, struct xformsw
> int
> ah_zeroize(struct tdb *tdbp)
> {
> - int err;
> + int error;
> 
>   if (tdbp->tdb_amxkey) {
>   explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
> @@ -179,9 +183,11 @@ ah_zeroize(struct tdb *tdbp)
>   tdbp->tdb_amxkey = NULL;
>   }
> 
> - err = crypto_freesession(tdbp->tdb_cryptoid);
> + KERNEL_LOCK();
> + error = crypto_freesession(tdbp->tdb_cryptoid);
> + KERNEL_UNLOCK();
>   tdbp->tdb_cryptoid = 0;
> - return err;
> + return error;
> }
> 
> /*
> @@ -626,7 +632,9 @@ ah_input(struct mbuf *m, struct tdb *tdb
>   }
> 
>   /* Get crypto descriptors. */
> + KERNEL_LOCK();
>   crp = crypto_getreq(1);
> + KERNEL_UNLOCK();
>   if (crp == NULL) {
>   DPRINTF(("%s: failed to acquire crypto descriptors\n",
>   __func__));
> @@ -696,11 +704,16 @@ ah_input(struct mbuf *m, struct tdb *tdb
>   tc->tc_rdomain = tdb->tdb_rdomain;
>   memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
> 
> - return crypto_dispatch(crp);
> + KERNEL_LOCK();
> + error = crypto_dispatch(crp);
> + KERNEL_UNLOCK();
> + return error;
> 
>  drop:
>   m_freem(m);
> + KERNEL_LOCK();
>   crypto_freereq(crp);
> + KERNEL_UNLOCK();
>   free(tc, M_XDATA, 0);
>   return error;
> }
> @@ -1047,7 +1060,9 @@ ah_output(struct mbuf *m, struct tdb *td
> #endif
> 
>   /* Get crypto descriptors. */
> + KERNEL_LOCK();
>   crp = crypto_getreq(1);
> + KERNEL_UNLOCK();
>   if (crp == NULL) {
>   DPRINTF(("%s: failed to acquire crypto descriptors\n",
>   __func__));
> @@ -1144,11 +1159,16 @@ ah_output(struct mbuf *m, struct tdb *td
>   tc->tc_rdomain = tdb->tdb_rdomain;
>   memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
> 
> - return crypto_dispatch(crp);
> + KERNEL_LOCK();
> + error = crypto_dispatch(crp);
> + KERNEL_UNLOCK();
> + return error;
> 
>  drop:
>   m_freem(m);
> + KERNEL_LOCK();
>   crypto_freereq(crp);
> + KERNEL_UNLOCK();
>   free(tc, M_XDATA, 0);
>   return error;
> }
> Index: netinet/ip_esp.c
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v
> retrieving revision 1.162
> diff -u -p -r1.162 ip_esp.c
> --- netinet/ip_esp.c  25 Feb 2021 02:48:21 -  1.162
> +++ 

ipsec crypto kernel lock

2021-06-16 Thread Alexander Bluhm
Hi,

I have seen a kernel crash with while forwarding and encrypting
much traffic through OpenBSD IPsec gateways running iked.

kernel: protection fault trap, code=0
Stopped at  aes_ctr_crypt+0x1e: addb$0x1,0x2e3(%rdi)

ddb{2}> trace
aes_ctr_crypt(16367ed4be021a53,8000246e1db0) at aes_ctr_crypt+0x1e
swcr_authenc(fd8132a21b08) at swcr_authenc+0x5c3
swcr_process(fd8132a21b08) at swcr_process+0x1e8
crypto_invoke(fd8132a21b08) at crypto_invoke+0xde
taskq_thread(80200500) at taskq_thread+0x81
end trace frame: 0x0, count: -5

*64926  109760  0  0  7 0x14200crypto

swcr_authenc() passes swe->sw_kschedule to aes_ctr_crypt(), swe has
been freed and contains deaf006cdeaf4152, which looks like some
sort of poison.  I suspect a use after free.

The swe value comes from the swcr_sessions global pointers.  Its
content looks sane in ddb.  Noone touches it in swcr_authenc().  So
I guess that an other CPU changes the global structures while
swcr_authenc() is working with it.

The crypto thread is protected by kernel lock, both network stack
and pfkey use net lock.  The kernel lock has been recently removed
from pfkey.

I think the required lock for the crypto framework is the kernel
lock.  If crypto_ functions are called, IPsec must grab the kernel
lock.  pfkey accesses crypto only via tdb_ functions, so this diff
also covers that case.

ok?

bluhm

Index: netinet/ip_ah.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
retrieving revision 1.146
diff -u -p -r1.146 ip_ah.c
--- netinet/ip_ah.c 25 Feb 2021 02:48:21 -  1.146
+++ netinet/ip_ah.c 16 Jun 2021 17:29:37 -
@@ -98,6 +98,7 @@ ah_init(struct tdb *tdbp, struct xformsw
 {
struct auth_hash *thash = NULL;
struct cryptoini cria, crin;
+   int error;
 
/* Authentication operation. */
switch (ii->ii_authalg) {
@@ -162,7 +163,10 @@ ah_init(struct tdb *tdbp, struct xformsw
cria.cri_next = 
}
 
-   return crypto_newsession(>tdb_cryptoid, , 0);
+   KERNEL_LOCK();
+   error = crypto_newsession(>tdb_cryptoid, , 0);
+   KERNEL_UNLOCK();
+   return error;
 }
 
 /*
@@ -171,7 +175,7 @@ ah_init(struct tdb *tdbp, struct xformsw
 int
 ah_zeroize(struct tdb *tdbp)
 {
-   int err;
+   int error;
 
if (tdbp->tdb_amxkey) {
explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
@@ -179,9 +183,11 @@ ah_zeroize(struct tdb *tdbp)
tdbp->tdb_amxkey = NULL;
}
 
-   err = crypto_freesession(tdbp->tdb_cryptoid);
+   KERNEL_LOCK();
+   error = crypto_freesession(tdbp->tdb_cryptoid);
+   KERNEL_UNLOCK();
tdbp->tdb_cryptoid = 0;
-   return err;
+   return error;
 }
 
 /*
@@ -626,7 +632,9 @@ ah_input(struct mbuf *m, struct tdb *tdb
}
 
/* Get crypto descriptors. */
+   KERNEL_LOCK();
crp = crypto_getreq(1);
+   KERNEL_UNLOCK();
if (crp == NULL) {
DPRINTF(("%s: failed to acquire crypto descriptors\n",
__func__));
@@ -696,11 +704,16 @@ ah_input(struct mbuf *m, struct tdb *tdb
tc->tc_rdomain = tdb->tdb_rdomain;
memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
 
-   return crypto_dispatch(crp);
+   KERNEL_LOCK();
+   error = crypto_dispatch(crp);
+   KERNEL_UNLOCK();
+   return error;
 
  drop:
m_freem(m);
+   KERNEL_LOCK();
crypto_freereq(crp);
+   KERNEL_UNLOCK();
free(tc, M_XDATA, 0);
return error;
 }
@@ -1047,7 +1060,9 @@ ah_output(struct mbuf *m, struct tdb *td
 #endif
 
/* Get crypto descriptors. */
+   KERNEL_LOCK();
crp = crypto_getreq(1);
+   KERNEL_UNLOCK();
if (crp == NULL) {
DPRINTF(("%s: failed to acquire crypto descriptors\n",
__func__));
@@ -1144,11 +1159,16 @@ ah_output(struct mbuf *m, struct tdb *td
tc->tc_rdomain = tdb->tdb_rdomain;
memcpy(>tc_dst, >tdb_dst, sizeof(union sockaddr_union));
 
-   return crypto_dispatch(crp);
+   KERNEL_LOCK();
+   error = crypto_dispatch(crp);
+   KERNEL_UNLOCK();
+   return error;
 
  drop:
m_freem(m);
+   KERNEL_LOCK();
crypto_freereq(crp);
+   KERNEL_UNLOCK();
free(tc, M_XDATA, 0);
return error;
 }
Index: netinet/ip_esp.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v
retrieving revision 1.162
diff -u -p -r1.162 ip_esp.c
--- netinet/ip_esp.c25 Feb 2021 02:48:21 -  1.162
+++ netinet/ip_esp.c16 Jun 2021 17:29:55 -
@@ -93,6 +93,7 @@ esp_init(struct tdb *tdbp, struct xforms
struct enc_xform *txform = NULL;
struct auth_hash *thash = NULL;
struct cryptoini cria, crie, crin;
+   int error;
 
if