Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Apr 2016 11:48:54 +0000 (UTC)
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r297855 - head/sys/netinet
Message-ID:  <201604121148.u3CBmsA9068084@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tuexen
Date: Tue Apr 12 11:48:54 2016
New Revision: 297855
URL: https://svnweb.freebsd.org/changeset/base/297855

Log:
  When processing an ICMP packet containing an SCTP packet, it
  is required to check the verification tag. However, this
  requires the verification tag to be not 0. Enforce this.
  For packets with a verification tag of 0, we need to
  check it it contains an INIT chunk and use the initiate
  tag for the validation. This will be a separate commit,
  since it touches also other code.
  
  MFC after: 1 week

Modified:
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctp_var.h

Modified: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c	Tue Apr 12 11:48:50 2016	(r297854)
+++ head/sys/netinet/sctp_usrreq.c	Tue Apr 12 11:48:54 2016	(r297855)
@@ -147,26 +147,19 @@ static void
 sctp_notify_mbuf(struct sctp_inpcb *inp,
     struct sctp_tcb *stcb,
     struct sctp_nets *net,
-    struct ip *ip,
-    struct sctphdr *sh)
+    struct ip *ip)
 {
 	struct icmp *icmph;
 	int totsz, tmr_stopped = 0;
 	uint16_t nxtsz;
 
 	/* protection */
-	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
-	    (ip == NULL) || (sh == NULL)) {
+	if ((inp == NULL) || (stcb == NULL) || (net == NULL) || (ip == NULL)) {
 		if (stcb != NULL) {
 			SCTP_TCB_UNLOCK(stcb);
 		}
 		return;
 	}
-	/* First job is to verify the vtag matches what I would send */
-	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
-		SCTP_TCB_UNLOCK(stcb);
-		return;
-	}
 	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
 	    sizeof(struct ip)));
 	if (icmph->icmp_type != ICMP_UNREACH) {
@@ -213,10 +206,9 @@ sctp_notify_mbuf(struct sctp_inpcb *inp,
 	SCTP_TCB_UNLOCK(stcb);
 }
 
-void
+static void
 sctp_notify(struct sctp_inpcb *inp,
     struct ip *ip,
-    struct sctphdr *sh,
     struct sockaddr *to,
     struct sctp_tcb *stcb,
     struct sctp_nets *net)
@@ -228,17 +220,11 @@ sctp_notify(struct sctp_inpcb *inp,
 	struct icmp *icmph;
 
 	/* protection */
-	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
-	    (sh == NULL) || (to == NULL)) {
+	if ((inp == NULL) || (stcb == NULL) || (net == NULL) || (to == NULL)) {
 		if (stcb)
 			SCTP_TCB_UNLOCK(stcb);
 		return;
 	}
-	/* First job is to verify the vtag matches what I would send */
-	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
-		SCTP_TCB_UNLOCK(stcb);
-		return;
-	}
 	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
 	    sizeof(struct ip)));
 	if (icmph->icmp_type != ICMP_UNREACH) {
@@ -304,10 +290,7 @@ sctp_notify(struct sctp_inpcb *inp,
 
 #ifdef INET
 void
-sctp_ctlinput(cmd, sa, vip)
-	int cmd;
-	struct sockaddr *sa;
-	void *vip;
+sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
 {
 	struct ip *ip = vip;
 	struct sctphdr *sh;
@@ -348,14 +331,37 @@ sctp_ctlinput(cmd, sa, vip)
 		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to,
 		    (struct sockaddr *)&from,
 		    &inp, &net, 1, vrf_id);
-		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
+		if ((stcb != NULL) &&
+		    (inp != NULL) &&
+		    (inp->sctp_socket != NULL)) {
+			/* Check the verification tag */
+			if (ntohl(sh->v_tag) != 0) {
+				/*
+				 * This must be the verification tag used
+				 * for sending out packets. We don't
+				 * consider packets reflecting the
+				 * verification tag.
+				 */
+				if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
+					SCTP_TCB_UNLOCK(stcb);
+					return;
+				}
+			} else {
+				/*
+				 * In this case we could check if we got an
+				 * INIT chunk and if the initiate tag
+				 * matches. But this is not there yet...
+				 */
+				SCTP_TCB_UNLOCK(stcb);
+				return;
+			}
 			if (cmd != PRC_MSGSIZE) {
-				sctp_notify(inp, ip, sh,
+				sctp_notify(inp, ip,
 				    (struct sockaddr *)&to, stcb,
 				    net);
 			} else {
 				/* handle possible ICMP size messages */
-				sctp_notify_mbuf(inp, stcb, net, ip, sh);
+				sctp_notify_mbuf(inp, stcb, net, ip);
 			}
 		} else {
 			if ((stcb == NULL) && (inp != NULL)) {

Modified: head/sys/netinet/sctp_var.h
==============================================================================
--- head/sys/netinet/sctp_var.h	Tue Apr 12 11:48:50 2016	(r297854)
+++ head/sys/netinet/sctp_var.h	Tue Apr 12 11:48:54 2016	(r297855)
@@ -344,10 +344,6 @@ void sctp_init(void);
 void sctp_finish(void);
 int sctp_flush(struct socket *, int);
 int sctp_shutdown(struct socket *);
-void 
-sctp_notify(struct sctp_inpcb *, struct ip *ip, struct sctphdr *,
-    struct sockaddr *, struct sctp_tcb *,
-    struct sctp_nets *);
 int 
 sctp_bindx(struct socket *, int, struct sockaddr_storage *,
     int, int, struct proc *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201604121148.u3CBmsA9068084>