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
This commit is contained in:
Michael Tuexen 2016-04-12 11:48:54 +00:00
parent 003c82d713
commit cf4476eb39
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=297855
2 changed files with 31 additions and 29 deletions

View File

@ -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)) {

View File

@ -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 *);