From cf4476eb39575e2ad601e85a5fe6796fd188ee6d Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Tue, 12 Apr 2016 11:48:54 +0000 Subject: [PATCH] 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 --- sys/netinet/sctp_usrreq.c | 56 ++++++++++++++++++++++----------------- sys/netinet/sctp_var.h | 4 --- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 64d3a262943..4024d1d29a1 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -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)) { diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h index 009ffdb4078..77e5da2edf0 100644 --- a/sys/netinet/sctp_var.h +++ b/sys/netinet/sctp_var.h @@ -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 *);