Skip to content

Commit 2e67122

Browse files
lxingregkh
authored andcommitted
sctp: set frag_point in sctp_setsockopt_maxseg correctly
commit ecca8f8 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. Suggested-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Reported-by: Hangbin Liu <liuhangbin@gmail.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 8555288 commit 2e67122

File tree

2 files changed

+21
-11
lines changed

2 files changed

+21
-11
lines changed

include/net/sctp/sctp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,8 @@ static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu)
433433
if (asoc->user_frag)
434434
frag = min_t(int, frag, asoc->user_frag);
435435

436-
frag = SCTP_TRUNC4(min_t(int, frag, SCTP_MAX_CHUNK_LEN));
436+
frag = SCTP_TRUNC4(min_t(int, frag, SCTP_MAX_CHUNK_LEN -
437+
sizeof(struct sctp_data_chunk)));
437438

438439
return frag;
439440
}

net/sctp/socket.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3125,9 +3125,9 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign
31253125
*/
31263126
static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
31273127
{
3128+
struct sctp_sock *sp = sctp_sk(sk);
31283129
struct sctp_assoc_value params;
31293130
struct sctp_association *asoc;
3130-
struct sctp_sock *sp = sctp_sk(sk);
31313131
int val;
31323132

31333133
if (optlen == sizeof(int)) {
@@ -3143,26 +3143,35 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
31433143
if (copy_from_user(&params, optval, optlen))
31443144
return -EFAULT;
31453145
val = params.assoc_value;
3146-
} else
3146+
} else {
31473147
return -EINVAL;
3148+
}
31483149

3149-
if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)))
3150-
return -EINVAL;
3150+
if (val) {
3151+
int min_len, max_len;
31513152

3152-
asoc = sctp_id2assoc(sk, params.assoc_id);
3153-
if (!asoc && params.assoc_id && sctp_style(sk, UDP))
3154-
return -EINVAL;
3153+
min_len = SCTP_DEFAULT_MINSEGMENT - sp->pf->af->net_header_len;
3154+
min_len -= sizeof(struct sctphdr) +
3155+
sizeof(struct sctp_data_chunk);
3156+
3157+
max_len = SCTP_MAX_CHUNK_LEN - sizeof(struct sctp_data_chunk);
31553158

3159+
if (val < min_len || val > max_len)
3160+
return -EINVAL;
3161+
}
3162+
3163+
asoc = sctp_id2assoc(sk, params.assoc_id);
31563164
if (asoc) {
31573165
if (val == 0) {
3158-
val = asoc->pathmtu;
3159-
val -= sp->pf->af->net_header_len;
3166+
val = asoc->pathmtu - sp->pf->af->net_header_len;
31603167
val -= sizeof(struct sctphdr) +
3161-
sizeof(struct sctp_data_chunk);
3168+
sizeof(struct sctp_data_chunk);
31623169
}
31633170
asoc->user_frag = val;
31643171
asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
31653172
} else {
3173+
if (params.assoc_id && sctp_style(sk, UDP))
3174+
return -EINVAL;
31663175
sp->user_frag = val;
31673176
}
31683177

0 commit comments

Comments
 (0)