From owner-svn-src-projects@freebsd.org Tue Nov 22 11:18:20 2016 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id ED4ADC4FFDA for ; Tue, 22 Nov 2016 11:18:20 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id C7C7010DC; Tue, 22 Nov 2016 11:18:20 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uAMBIJdt099981; Tue, 22 Nov 2016 11:18:19 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uAMBIJVn099980; Tue, 22 Nov 2016 11:18:19 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201611221118.uAMBIJVn099980@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Tue, 22 Nov 2016 11:18:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r308981 - projects/ipsec/sys/netipsec X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 22 Nov 2016 11:18:21 -0000 Author: ae Date: Tue Nov 22 11:18:19 2016 New Revision: 308981 URL: https://svnweb.freebsd.org/changeset/base/308981 Log: Modify key_spdadd() to do more accurate checks. Use SADB_CHECKHDR() and SADB_CHECKLEN() macros to check extension headers. Use key_checksockaddrs() to check sockaddr structures. Modified: projects/ipsec/sys/netipsec/key.c Modified: projects/ipsec/sys/netipsec/key.c ============================================================================== --- projects/ipsec/sys/netipsec/key.c Tue Nov 22 10:58:24 2016 (r308980) +++ projects/ipsec/sys/netipsec/key.c Tue Nov 22 11:18:19 2016 (r308981) @@ -1592,15 +1592,16 @@ fail: * SPDSETIDX like SPDADD without a part of policy requests. * SPDUPDATE replace a unique policy entry. * + * XXXAE: serialize this in PF_KEY to avoid races. * m will always be freed. */ static int key_spdadd(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) { + struct secpolicyindex spidx; struct sadb_address *src0, *dst0; struct sadb_x_policy *xpl0, *xpl; struct sadb_lifetime *lft = NULL; - struct secpolicyindex spidx; struct secpolicy *newsp; int error; @@ -1609,24 +1610,26 @@ key_spdadd(struct socket *so, struct mbu IPSEC_ASSERT(mhp != NULL, ("null msghdr")); IPSEC_ASSERT(mhp->msg != NULL, ("null msg")); - if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || - mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || - mhp->ext[SADB_X_EXT_POLICY] == NULL) { - ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || - mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) || - mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { - ipseclog((LOG_DEBUG, "%s: invalid message is passed.\n", - __func__)); - return key_senderror(so, m, EINVAL); - } - if (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL) { - if (mhp->extlen[SADB_EXT_LIFETIME_HARD] - < sizeof(struct sadb_lifetime)) { - ipseclog((LOG_DEBUG, "%s: invalid message is passed.\n", - __func__)); + if (SADB_CHECKHDR(mhp, SADB_EXT_ADDRESS_SRC) || + SADB_CHECKHDR(mhp, SADB_EXT_ADDRESS_DST) || + SADB_CHECKHDR(mhp, SADB_X_EXT_POLICY)) { + ipseclog((LOG_DEBUG, + "%s: invalid message: missing required header.\n", + __func__)); + return key_senderror(so, m, EINVAL); + } + if (SADB_CHECKLEN(mhp, SADB_EXT_ADDRESS_SRC) || + SADB_CHECKLEN(mhp, SADB_EXT_ADDRESS_DST) || + SADB_CHECKLEN(mhp, SADB_X_EXT_POLICY)) { + ipseclog((LOG_DEBUG, + "%s: invalid message: wrong header size.\n", __func__)); + return key_senderror(so, m, EINVAL); + } + if (!SADB_CHECKHDR(mhp, SADB_EXT_LIFETIME_HARD)) { + if (SADB_CHECKLEN(mhp, SADB_EXT_LIFETIME_HARD)) { + ipseclog((LOG_DEBUG, + "%s: invalid message: wrong header size.\n", + __func__)); return key_senderror(so, m, EINVAL); } lft = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD]; @@ -1636,130 +1639,92 @@ key_spdadd(struct socket *so, struct mbu dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY]; - /* + /* * Note: do not parse SADB_X_EXT_NAT_T_* here: * we are processing traffic endpoints. */ - /* make secindex */ - /* XXX boundary check against sa_len */ - KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, - src0 + 1, - dst0 + 1, - src0->sadb_address_prefixlen, - dst0->sadb_address_prefixlen, - src0->sadb_address_proto, - &spidx); - - /* checking the direciton. */ + /* check the direciton */ switch (xpl0->sadb_x_policy_dir) { case IPSEC_DIR_INBOUND: case IPSEC_DIR_OUTBOUND: break; default: - ipseclog((LOG_DEBUG, "%s: Invalid SP direction.\n", __func__)); - mhp->msg->sadb_msg_errno = EINVAL; - return 0; + ipseclog((LOG_DEBUG, "%s: invalid SP direction.\n", __func__)); + return key_senderror(so, m, EINVAL); } - - /* check policy */ /* key_spdadd() accepts DISCARD, NONE and IPSEC. */ - if (xpl0->sadb_x_policy_type == IPSEC_POLICY_ENTRUST - || xpl0->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { - ipseclog((LOG_DEBUG, "%s: Invalid policy type.\n", __func__)); + if (xpl0->sadb_x_policy_type != IPSEC_POLICY_DISCARD && + xpl0->sadb_x_policy_type != IPSEC_POLICY_NONE && + xpl0->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { + ipseclog((LOG_DEBUG, "%s: invalid policy type.\n", __func__)); return key_senderror(so, m, EINVAL); } /* policy requests are mandatory when action is ipsec. */ - if (mhp->msg->sadb_msg_type != SADB_X_SPDSETIDX - && xpl0->sadb_x_policy_type == IPSEC_POLICY_IPSEC - && mhp->extlen[SADB_X_EXT_POLICY] <= sizeof(*xpl0)) { - ipseclog((LOG_DEBUG, "%s: some policy requests part required\n", - __func__)); + if (xpl0->sadb_x_policy_type == IPSEC_POLICY_IPSEC && + mhp->extlen[SADB_X_EXT_POLICY] <= sizeof(*xpl0)) { + ipseclog((LOG_DEBUG, + "%s: policy requests required.\n", __func__)); return key_senderror(so, m, EINVAL); } - /* - * checking there is SP already or not. - * SPDUPDATE doesn't depend on whether there is a SP or not. - * If the type is either SPDADD or SPDSETIDX AND a SP is found, - * then error. - */ - newsp = key_getsp(&spidx); - if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { - if (newsp) { - key_unlink(newsp); - KEY_FREESP(&newsp); - } - } else { - if (newsp != NULL) { - KEY_FREESP(&newsp); - ipseclog((LOG_DEBUG, "%s: a SP entry exists already.\n", - __func__)); - return key_senderror(so, m, EEXIST); - } - } - - /* XXX: there is race between key_getsp and key_msg2sp. */ - - /* allocation new SP entry */ - if ((newsp = key_msg2sp(xpl0, PFKEY_EXTLEN(xpl0), &error)) == NULL) { + error = key_checksockaddrs((struct sockaddr *)(src0 + 1), + (struct sockaddr *)(dst0 + 1)); + if (error != 0 || + src0->sadb_address_proto != dst0->sadb_address_proto) { + ipseclog((LOG_DEBUG, "%s: invalid sockaddr.\n", __func__)); return key_senderror(so, m, error); } - - if ((newsp->id = key_getnewspid()) == 0) { - KEY_FREESP(&newsp); - return key_senderror(so, m, ENOBUFS); - } - - /* XXX boundary check against sa_len */ + /* make secindex */ KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, src0 + 1, dst0 + 1, src0->sadb_address_prefixlen, dst0->sadb_address_prefixlen, src0->sadb_address_proto, - &newsp->spidx); - - /* sanity check on addr pair */ - if (((struct sockaddr *)(src0 + 1))->sa_family != - ((struct sockaddr *)(dst0+ 1))->sa_family) { - KEY_FREESP(&newsp); - return key_senderror(so, m, EINVAL); - } - if (((struct sockaddr *)(src0 + 1))->sa_len != - ((struct sockaddr *)(dst0+ 1))->sa_len) { - KEY_FREESP(&newsp); - return key_senderror(so, m, EINVAL); - } -#if 1 - if (newsp->req && newsp->req->saidx.src.sa.sa_family && - newsp->req->saidx.dst.sa.sa_family) { - if (newsp->req->saidx.src.sa.sa_family != - newsp->req->saidx.dst.sa.sa_family) { - KEY_FREESP(&newsp); - return key_senderror(so, m, EINVAL); + &spidx); + /* Checking there is SP already or not. */ + newsp = key_getsp(&spidx); + if (newsp != NULL) { + if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { + KEYDBG(KEY_STAMP, + printf("%s: unlink SP(%p) for SPDUPDATE\n", + __func__, newsp)); + KEYDBG(KEY_DATA, kdebug_secpolicy(newsp)); + key_unlink(newsp); + key_freesp(&newsp); + } else { + key_freesp(&newsp); + ipseclog((LOG_DEBUG, "%s: a SP entry exists already.", + __func__)); + return (key_senderror(so, m, EEXIST)); } } -#endif - newsp->created = time_second; - newsp->lastused = newsp->created; + /* allocate new SP entry */ + if ((newsp = key_msg2sp(xpl0, PFKEY_EXTLEN(xpl0), &error)) == NULL) { + return key_senderror(so, m, error); + } + + newsp->lastused = newsp->created = time_second; newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0; newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0; + bcopy(&spidx, &newsp->spidx, sizeof(spidx)); + /* XXXAE: there is race between key_getsp() and key_insertsp() */ + SPTREE_WLOCK(); + if ((newsp->id = key_getnewspid()) == 0) { + SPTREE_WUNLOCK(); + key_freesp(&newsp); + return key_senderror(so, m, ENOBUFS); + } key_insertsp(newsp); + SPTREE_WUNLOCK(); - /* delete the entry in spacqtree */ - if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { - struct secspacq *spacq = key_getspacq(&spidx); - if (spacq != NULL) { - /* reset counter in order to deletion by timehandler. */ - spacq->created = time_second; - spacq->count = 0; - SPACQ_UNLOCK(); - } - } + KEYDBG(KEY_STAMP, + printf("%s: SP(%p)\n", __func__, newsp)); + KEYDBG(KEY_DATA, kdebug_secpolicy(newsp)); { struct mbuf *n, *mpolicy;