Re: [PATCH 4.4 31/36] sctp: verify size of a new chunk in _sctp_make_chunk()

Greg Kroah-Hartman
2018-03-13T09:56:00Z

On Tue, Mar 13, 2018 at 12:46:58AM +0000, Ben Hutchings wrote:
> On Fri, 2018-03-09 at 16:18 -0800, Greg Kroah-Hartman wrote:
> > 4.4-stable review patch.ï¿½ï¿½If anyone has any objections, please let me know.
> >
> > ------------------
> >
> > From: Alexey Kodanev <alexey.kodanev@oracle.com>
> >
> >
> > [ Upstream commit 07f2c7ab6f8d0a7e7c5764c4e6cc9c52951b9d9c ]
> >
> > When SCTP makes INIT or INIT_ACK packet the total chunk length
> > can exceed SCTP_MAX_CHUNK_LEN which leads to kernel panic when
> > transmitting these packets, e.g. the crash on sending INIT_ACK:
> >
> > [ï¿½ï¿½597.804948] skbuff: skb_over_panic: text:00000000ffae06e4 len:120168
> > ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½put:120156 head:000000007aa47635 data:00000000d991c2de
> > ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½tail:0x1d640 end:0xfec0 dev:<NULL>
> > ...
> > [ï¿½ï¿½597.976970] ------------[ cut here ]------------
> > [ï¿½ï¿½598.033408] kernel BUG at net/core/skbuff.c:104!
> > [ï¿½ï¿½600.314841] Call Trace:
> > [ï¿½ï¿½600.345829]ï¿½ï¿½<IRQ>
> > [ï¿½ï¿½600.371639]ï¿½ï¿½? sctp_packet_transmit+0x2095/0x26d0 [sctp]
> > [ï¿½ï¿½600.436934]ï¿½ï¿½skb_put+0x16c/0x200
> > [ï¿½ï¿½600.477295]ï¿½ï¿½sctp_packet_transmit+0x2095/0x26d0 [sctp]
> > [ï¿½ï¿½600.540630]ï¿½ï¿½? sctp_packet_config+0x890/0x890 [sctp]
> > [ï¿½ï¿½600.601781]ï¿½ï¿½? __sctp_packet_append_chunk+0x3b4/0xd00 [sctp]
> > [ï¿½ï¿½600.671356]ï¿½ï¿½? sctp_cmp_addr_exact+0x3f/0x90 [sctp]
> > [ï¿½ï¿½600.731482]ï¿½ï¿½sctp_outq_flush+0x663/0x30d0 [sctp]
> > [ï¿½ï¿½600.788565]ï¿½ï¿½? sctp_make_init+0xbf0/0xbf0 [sctp]
> > [ï¿½ï¿½600.845555]ï¿½ï¿½? sctp_check_transmitted+0x18f0/0x18f0 [sctp]
> > [ï¿½ï¿½600.912945]ï¿½ï¿½? sctp_outq_tail+0x631/0x9d0 [sctp]
> > [ï¿½ï¿½600.969936]ï¿½ï¿½sctp_cmd_interpreter.isra.22+0x3be1/0x5cb0 [sctp]
> > [ï¿½ï¿½601.041593]ï¿½ï¿½? sctp_sf_do_5_1B_init+0x85f/0xc30 [sctp]
> > [ï¿½ï¿½601.104837]ï¿½ï¿½? sctp_generate_t1_cookie_event+0x20/0x20 [sctp]
> > [ï¿½ï¿½601.175436]ï¿½ï¿½? sctp_eat_data+0x1710/0x1710 [sctp]
> > [ï¿½ï¿½601.233575]ï¿½ï¿½sctp_do_sm+0x182/0x560 [sctp]
> > [ï¿½ï¿½601.284328]ï¿½ï¿½? sctp_has_association+0x70/0x70 [sctp]
> > [ï¿½ï¿½601.345586]ï¿½ï¿½? sctp_rcv+0xef4/0x32f0 [sctp]
> > [ï¿½ï¿½601.397478]ï¿½ï¿½? sctp6_rcv+0xa/0x20 [sctp]
> > ...
> >
> > Here the chunk size for INIT_ACK packet becomes too big, mostly
> > because of the state cookie (INIT packet has large size with
> > many address parameters), plus additional server parameters.
> >
> > Later this chunk causes the panic in skb_put_data():
> >
> > ï¿½ skb_packet_transmit()
> > ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½sctp_packet_pack()
> > ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½skb_put_data(nskb, chunk->skb->data, chunk->skb->len);
> >
> > 'nskb' (head skb) was previously allocated with packet->size
> > from u16 'chunk->chunk_hdr->length'.
> >
> > As suggested by Marcelo we should check the chunk's length in
> > _sctp_make_chunk() before trying to allocate skb for it and
> > discard a chunk if its size bigger than SCTP_MAX_CHUNK_LEN.
> >
> > > Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
> > > Acked-by: Marcelo Ricardo Leitner <marcelo.leinter@gmail.com>
> > > Acked-by: Neil Horman <nhorman@tuxdriver.com>
> > > Signed-off-by: David S. Miller <davem@davemloft.net>
> > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > ---
> > ï¿½net/sctp/sm_make_chunk.c |ï¿½ï¿½ï¿½ï¿½8 ++++++--
> > ï¿½1 file changed, 6 insertions(+), 2 deletions(-)
> >
> > --- a/net/sctp/sm_make_chunk.c
> > +++ b/net/sctp/sm_make_chunk.c
> > @@ -1367,10 +1367,14 @@ static struct sctp_chunk *_sctp_make_chu
> > ï¿½ sctp_chunkhdr_t *chunk_hdr;
> > ï¿½ struct sk_buff *skb;
> > ï¿½ struct sock *sk;
> > + int chunklen;
> > +
> > + chunklen = sizeof(*chunk_hdr) + paylen;
>
> I think this length still needs to be rounded up (with WORD_ROUND here,
> instead of SCTP_PAD4 upstream).

Ah, good point, how's this patch:

diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 4ca31e052dd8..509e9426a056 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1369,7 +1369,7 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
struct sock *sk;
int chunklen;

- chunklen = sizeof(*chunk_hdr) + paylen;
+ chunklen = WORD_ROUND(sizeof(*chunk_hdr) + paylen);
if (chunklen > SCTP_MAX_CHUNK_LEN)
goto nodata;