Module Name:    src
Committed By:   ozaki-r
Date:           Thu Jul  6 09:48:42 UTC 2017

Modified Files:
        src/sys/netipsec: key.c

Log Message:
Avoid updating sav directly

On SADB_UPDATE a target sav was updated directly, which was unsafe.
Instead allocate another sav, copy variables of the old sav to
the new one and replace the old one with the new one.


To generate a diff of this commit:
cvs rdiff -u -r1.166 -r1.167 src/sys/netipsec/key.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netipsec/key.c
diff -u src/sys/netipsec/key.c:1.166 src/sys/netipsec/key.c:1.167
--- src/sys/netipsec/key.c:1.166	Thu Jul  6 09:04:26 2017
+++ src/sys/netipsec/key.c	Thu Jul  6 09:48:42 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: key.c,v 1.166 2017/07/06 09:04:26 ozaki-r Exp $	*/
+/*	$NetBSD: key.c,v 1.167 2017/07/06 09:48:42 ozaki-r Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/key.c,v 1.3.2.3 2004/02/14 22:23:23 bms Exp $	*/
 /*	$KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $	*/
 
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.166 2017/07/06 09:04:26 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.167 2017/07/06 09:48:42 ozaki-r Exp $");
 
 /*
  * This code is referd to RFC 2367
@@ -3150,6 +3150,9 @@ key_setsaval(struct secasvar *sav, struc
 	KASSERT(mhp != NULL);
 	KASSERT(mhp->msg != NULL);
 
+	/* We shouldn't initialize sav variables while someone uses it. */
+	KASSERT(sav->refcnt == 0);
+
 	/* initialization */
 	key_freesaval(sav);
 	sav->tdb_xform = NULL;		/* transform */
@@ -5176,7 +5179,7 @@ key_api_update(struct socket *so, struct
 	const struct sockaddr *src, *dst;
 	struct secasindex saidx;
 	struct secashead *sah;
-	struct secasvar *sav;
+	struct secasvar *sav, *newsav;
 	u_int16_t proto;
 	u_int8_t mode;
 	u_int16_t reqid;
@@ -5283,24 +5286,47 @@ key_api_update(struct socket *so, struct
 		return key_senderror(so, m, EINVAL);
 	}
 
+	/*
+	 * Allocate a new SA instead of modifying the existing SA directly
+	 * to avoid race conditions.
+	 */
+	newsav = kmem_zalloc(sizeof(struct secasvar), KM_SLEEP);
+
 	/* copy sav values */
-	error = key_setsaval(sav, m, mhp);
+	newsav->spi = sav->spi;
+	newsav->seq = sav->seq;
+	newsav->created = sav->created;
+	newsav->pid = sav->pid;
+
+	error = key_setsaval(newsav, m, mhp);
 	if (error) {
-		KEY_FREESAV(&sav);
+		KEY_FREESAV(&newsav);
 		return key_senderror(so, m, error);
 	}
 
-	error = key_handle_natt_info(sav,mhp);
-	if (error != 0)
-		return key_senderror(so, m, EINVAL);
+	error = key_handle_natt_info(newsav, mhp);
+	if (error != 0) {
+		KEY_FREESAV(&newsav);
+		return key_senderror(so, m, error);
+	}
+
+	/* add to satree */
+	newsav->sah = sah;
+	newsav->refcnt = 1;
+	newsav->state = sav->state;
+	/* We have to keep the order */
+	LIST_INSERT_AFTER(sav, newsav, chain);
 
 	/* check SA values to be mature. */
-	error = key_mature(sav);
+	error = key_mature(newsav);
 	if (error != 0) {
-		KEY_FREESAV(&sav);
+		KEY_FREESAV(&newsav);
 		return key_senderror(so, m, error);
 	}
 
+	key_sa_chgstate(sav, SADB_SASTATE_DEAD);
+	KEY_FREESAV(&sav);
+
     {
 	struct mbuf *n;
 

Reply via email to