Patch "sctp: set frag_point in sctp_setsockopt_maxseg correctly" has been added to the 4.14-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
sctp: set frag_point in sctp_setsockopt_maxseg correctly
to the 4.14-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
sctp-set-frag_point-in-sctp_setsockopt_maxseg-correctly.patch
and it can be found in the queue-4.14 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
ecca8f88da5c4260cc2bccfefd2a24976704c366Mon Sep 17 00:00:00 2001
From: Xin Long <[email protected]>
Date: Fri, 17 Nov 2017 14:11:11 +0800
Subject: sctp: set frag_point in sctp_setsockopt_maxseg correctly
From: Xin Long <[email protected]>
commit ecca8f88da5c4260cc2bccfefd2a24976704c366 upstream.
Now in sctp_setsockopt_maxseg user_frag or frag_point can be set with val >= 8 and val <= SCTP_MAX_CHUNK_LEN. But both checks are incorrect.
val >= 8 means frag_point can even be less than SCTP_DEFAULT_MINSEGMENT. Then in sctp_datamsg_from_user(), when it's value is greater than cookie echo len and trying to bundle with cookie echo chunk, the first_len will overflow.
The worse case is when it's value is equal as cookie echo len, first_len becomes 0, it will go into a dead loop for fragment later on. In Hangbin syzkaller testing env, oom was even triggered due to consecutive memory allocation in that loop.
Besides, SCTP_MAX_CHUNK_LEN is the max size of the whole chunk, it should deduct the data header for frag_point or user_frag check.
This patch does a proper check with SCTP_DEFAULT_MINSEGMENT subtracting the sctphdr and datahdr, SCTP_MAX_CHUNK_LEN subtracting datahdr when setting frag_point via sockopt. It also improves sctp_setsockopt_maxseg codes.
--- include/net/sctp/sctp.h | 3 ++- net/sctp/socket.c | 29 +++++++++++++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-)
include/net/sctp/sctp.h +2 -1
@@ -444,7 +444,8 @@ static inline int sctp_frag_point(constif (asoc->user_frag) frag =min_t (int, frag, asoc->user_frag); - frag =SCTP_TRUNC4 (min_t (int, frag,SCTP_MAX_CHUNK_LEN )); + frag =SCTP_TRUNC4 (min_t (int, frag,SCTP_MAX_CHUNK_LEN - +sizeof (struct sctp_data_chunk )));return frag; }
net/sctp/socket.c +19 -10
@@ -3136,9 +3136,9 @@ static int sctp_setsockopt_mappedv4(stru*/ static int sctp_setsockopt_maxseg (struct sock *sk,char __user *optval,unsigned int optlen) { +struct sctp_sock *sp =sctp_sk (sk);struct sctp_assoc_value params;struct sctp_association *asoc; -struct sctp_sock *sp =sctp_sk (sk);int val;if (optlen ==sizeof (int )) {
@@ -3154,26 +3154,35 @@ static int sctp_setsockopt_maxseg(structif (copy_from_user (¶ms, optval, optlen))return -EFAULT ; val = params.assoc_value; - }else + }else {return -EINVAL ; + } -if ((val !=0 ) && ((val <8 ) || (val >SCTP_MAX_CHUNK_LEN ))) -return -EINVAL ; +if (val) { +int min_len, max_len; - asoc =sctp_id2assoc (sk, params.assoc_id); -if (!asoc && params.assoc_id &&sctp_style (sk,UDP )) -return -EINVAL ; + min_len =SCTP_DEFAULT_MINSEGMENT - sp->pf->af->net_header_len; + min_len -=sizeof (struct sctphdr ) + +sizeof (struct sctp_data_chunk ); + + max_len =SCTP_MAX_CHUNK_LEN -sizeof (struct sctp_data_chunk ); +if (val < min_len || val > max_len) +return -EINVAL ; + } + + asoc =sctp_id2assoc (sk, params.assoc_id);if (asoc) {if (val ==0 ) { - val = asoc->pathmtu; - val -= sp->pf->af->net_header_len; + val = asoc->pathmtu - sp->pf->af->net_header_len; val -=sizeof (struct sctphdr ) + -sizeof (struct sctp_data_chunk ); +sizeof (struct sctp_data_chunk ); } asoc->user_frag = val; asoc->frag_point =sctp_frag_point (asoc, asoc->pathmtu); }else { +if (params.assoc_id &&sctp_style (sk,UDP )) +return -EINVAL ; sp->user_frag = val; }
Patches currently in stable-queue which might be from [email protected] are
queue-4.14/sctp-set-frag_point-in-sctp_setsockopt_maxseg-correctly.patch