Abort an association when receiving illegal packet
When receiving a packet with a DATA chunk followed by an unknown
chunk with a too small length, abort the association.
Thanks for Felix Weinrank for making me aware of the problem.
#ifdef __FreeBSD__
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 324615 2017-10-14 10:02:59Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 324729 2017-10-18 20:17:44Z tuexen $");
#endif
#include <netinet/sctp_os.h>
@@ -2685,7 +2685,8 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
#endif
/* get pointer to the first chunk header */
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
- sizeof(struct sctp_chunkhdr), (uint8_t *) & chunk_buf);
+ sizeof(struct sctp_chunkhdr),
+ (uint8_t *)&chunk_buf);
if (ch == NULL) {
return (1);
}
@@ -2742,7 +2743,8 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
struct mbuf *op_err;
char msg[SCTP_DIAG_INFO_LEN];
- snprintf(msg, sizeof(msg), "DATA chunk of length %d",
+ snprintf(msg, sizeof(msg), "%s chunk of length %d",
+ ch->chunk_type == SCTP_DATA ? "DATA" : "I-DATA",
chk_length);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20;
@@ -2817,7 +2819,25 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
return (2);
}
default:
- /* unknown chunk type, use bit rules */
+ /*
+ * Unknown chunk type: use bit rules after
+ * checking length
+ */
+ if (chk_length < sizeof(struct sctp_chunkhdr)) {
+ /*
+ * Need to send an abort since we had a
+ * invalid chunk.
+ */
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
+ snprintf(msg, sizeof(msg), "Chunk of length %d",
+ chk_length);
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20;
+ sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return (2);
+ }
if (ch->chunk_type & 0x40) {
/* Add a error report to the queue */
struct mbuf *op_err;
@@ -2853,7 +2873,8 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
continue;
}
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
- sizeof(struct sctp_chunkhdr), (uint8_t *) & chunk_buf);
+ sizeof(struct sctp_chunkhdr),
+ (uint8_t *)&chunk_buf);
if (ch == NULL) {
*offset = length;
stop_proc = 1;
