diff options
author | Xin Long <lucien.xin@gmail.com> | 2017-12-18 01:07:25 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-12-18 13:21:46 -0500 |
commit | 5c468674d17056148da06218d4da5d04baf22eac (patch) | |
tree | 65dc8499eee2f0c96094daa1493e9259a0f57a3e /net/sctp/ulpqueue.c | |
parent | ac3241d5c81bf6e85095481435f29a4627ff820e (diff) |
sctp: fix the issue that a __u16 variable may overflow in sctp_ulpq_renege
Now when reneging events in sctp_ulpq_renege(), the variable freed
could be increased by a __u16 value twice while freed is of __u16
type. It means freed may overflow at the second addition.
This patch is to fix it by using __u32 type for 'freed', while at
it, also to remove 'if (chunk)' check, as all renege commands are
generated in sctp_eat_data and it can't be NULL.
Reported-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/ulpqueue.c')
-rw-r--r-- | net/sctp/ulpqueue.c | 24 |
1 files changed, 8 insertions, 16 deletions
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index a71be33f3afe..e36ec5dd64c6 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c | |||
@@ -1084,29 +1084,21 @@ void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, | |||
1084 | void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, | 1084 | void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, |
1085 | gfp_t gfp) | 1085 | gfp_t gfp) |
1086 | { | 1086 | { |
1087 | struct sctp_association *asoc; | 1087 | struct sctp_association *asoc = ulpq->asoc; |
1088 | __u16 needed, freed; | 1088 | __u32 freed = 0; |
1089 | 1089 | __u16 needed; | |
1090 | asoc = ulpq->asoc; | ||
1091 | 1090 | ||
1092 | if (chunk) { | 1091 | needed = ntohs(chunk->chunk_hdr->length) - |
1093 | needed = ntohs(chunk->chunk_hdr->length); | 1092 | sizeof(struct sctp_data_chunk); |
1094 | needed -= sizeof(struct sctp_data_chunk); | ||
1095 | } else | ||
1096 | needed = SCTP_DEFAULT_MAXWINDOW; | ||
1097 | |||
1098 | freed = 0; | ||
1099 | 1093 | ||
1100 | if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { | 1094 | if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { |
1101 | freed = sctp_ulpq_renege_order(ulpq, needed); | 1095 | freed = sctp_ulpq_renege_order(ulpq, needed); |
1102 | if (freed < needed) { | 1096 | if (freed < needed) |
1103 | freed += sctp_ulpq_renege_frags(ulpq, needed - freed); | 1097 | freed += sctp_ulpq_renege_frags(ulpq, needed - freed); |
1104 | } | ||
1105 | } | 1098 | } |
1106 | /* If able to free enough room, accept this chunk. */ | 1099 | /* If able to free enough room, accept this chunk. */ |
1107 | if (chunk && (freed >= needed)) { | 1100 | if (freed >= needed) { |
1108 | int retval; | 1101 | int retval = sctp_ulpq_tail_data(ulpq, chunk, gfp); |
1109 | retval = sctp_ulpq_tail_data(ulpq, chunk, gfp); | ||
1110 | /* | 1102 | /* |
1111 | * Enter partial delivery if chunk has not been | 1103 | * Enter partial delivery if chunk has not been |
1112 | * delivered; otherwise, drain the reassembly queue. | 1104 | * delivered; otherwise, drain the reassembly queue. |