Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932840AbcJUMjx (ORCPT ); Fri, 21 Oct 2016 08:39:53 -0400 Received: from charlotte.tuxdriver.com ([70.61.120.58]:52528 "EHLO smtp.tuxdriver.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753916AbcJUMju (ORCPT ); Fri, 21 Oct 2016 08:39:50 -0400 Date: Fri, 21 Oct 2016 08:39:27 -0400 From: Neil Horman To: Jiri Slaby Cc: Vlad Yasevich , linux-kernel@vger.kernel.org, "David S. Miller" , linux-sctp@vger.kernel.org, netdev@vger.kernel.org Subject: Re: [PATCH] net: sctp, forbid negative length Message-ID: <20161021123927.GA25597@hmsreliant.think-freely.org> References: <20161021121324.13942-1-jslaby@suse.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20161021121324.13942-1-jslaby@suse.cz> User-Agent: Mutt/1.7.0 (2016-08-17) X-Spam-Score: -2.9 (--) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2900 Lines: 74 On Fri, Oct 21, 2016 at 02:13:24PM +0200, Jiri Slaby wrote: > Most of getsockopt handlers in net/sctp/socket.c check len against > sizeof some structure like: > if (len < sizeof(int)) > return -EINVAL; > > On the first look, the check seems to be correct. But since len is int > and sizeof returns size_t, int gets promoted to unsigned size_t too. So > the test returns false for negative lengths. Yes, (-1 < sizeof(long)) is > false. > > Fix this in sctp by explicitly checking len < 0 before any getsockopt > handler is called. > > Note that sctp_getsockopt_events already handled the negative case. > Since we added the < 0 check elsewhere, this one can be removed. > > If not checked, this is the result: > UBSAN: Undefined behaviour in ../mm/page_alloc.c:2722:19 > shift exponent 52 is too large for 32-bit type 'int' > CPU: 1 PID: 24535 Comm: syz-executor Not tainted 4.8.1-0-syzkaller #1 > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.9.1-0-gb3ef39f-prebuilt.qemu-project.org 04/01/2014 > 0000000000000000 ffff88006d99f2a8 ffffffffb2f7bdea 0000000041b58ab3 > ffffffffb4363c14 ffffffffb2f7bcde ffff88006d99f2d0 ffff88006d99f270 > 0000000000000000 0000000000000000 0000000000000034 ffffffffb5096422 > Call Trace: > [] ? __ubsan_handle_shift_out_of_bounds+0x29c/0x300 > ... > [] ? kmalloc_order+0x24/0x90 > [] ? kmalloc_order_trace+0x24/0x220 > [] ? __kmalloc+0x330/0x540 > [] ? sctp_getsockopt_local_addrs+0x174/0xca0 [sctp] > [] ? sctp_getsockopt+0x10d/0x1b0 [sctp] > [] ? sock_common_getsockopt+0xb9/0x150 > [] ? SyS_getsockopt+0x1a5/0x270 > > Signed-off-by: Jiri Slaby > Cc: Vlad Yasevich > Cc: Neil Horman > Cc: "David S. Miller" > Cc: linux-sctp@vger.kernel.org > Cc: netdev@vger.kernel.org > --- > net/sctp/socket.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/net/sctp/socket.c b/net/sctp/socket.c > index fb02c7033307..9fbb6feb8c27 100644 > --- a/net/sctp/socket.c > +++ b/net/sctp/socket.c > @@ -4687,7 +4687,7 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, > static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, > int __user *optlen) > { > - if (len <= 0) > + if (len == 0) > return -EINVAL; > if (len > sizeof(struct sctp_event_subscribe)) > len = sizeof(struct sctp_event_subscribe); > @@ -6430,6 +6430,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, > if (get_user(len, optlen)) > return -EFAULT; > > + if (len < 0) > + return -EINVAL; > + > lock_sock(sk); > > switch (optname) { > -- > 2.10.1 > > Acked-by: Neil Horman