Received: by 10.223.185.116 with SMTP id b49csp6398807wrg; Wed, 28 Feb 2018 08:46:05 -0800 (PST) X-Google-Smtp-Source: AG47ELumcThNkZSgjB0Am7cbu3H7+dx9zBroV/OF7+vEPBeajMAQvdbDGPiIbxc/AsT52SGp5WgE X-Received: by 2002:a17:902:768b:: with SMTP id m11-v6mr14924130pll.185.1519836365144; Wed, 28 Feb 2018 08:46:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519836365; cv=none; d=google.com; s=arc-20160816; b=0zUBUtkJ9bJ+5DXBzoIFj8SkJ6CbbKh3SYA5A9WQPHUkrNQmflCX1ULbrzUFgiBNJA J8dEeK+cB2dlYptpqRgMivDjwI35sFnf6H7fwK/lNif8RGQjojiUPhCP73rpBCV7TrsJ cEjUF0wiIx/pzqqR+WZTwdbHvADTw1ChXCKNRVm9UCUoIivem1gn5sCuHb4VHlfyunZ4 Uy8KONAvfi4O/A0XMHHN6/JvuWEroAGimixyTBNYnHOBf7aL+/MfaBaZvvNOc8LKMDr7 3X00Yg3ubGPeA376fg4mMuln9RvK7p2owVE3l8LoZ4KRZODWAanAJLXF6+819mSQTaid 0FaQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:in-reply-to:subject:message-id:date:cc:to :from:mime-version:content-transfer-encoding:content-disposition :arc-authentication-results; bh=PCAOGmIfDmvzjx/6VmJqaQ8w7VwKMTLmGEbH7lrckqM=; b=yCTM0u/Oexj/hwQDZWjZdIzVUb3haE1dLCDUxnonlMNjT8HHvgKkoHC7Gw6lez58op CZZdSi/M9AKge9JlXLJpYHadcysNhRrT+0OL+s/mZ098LXyHBs4V1MmWvJVcIoeuqp6I h3K/dj6CKn8FqqcgmrEtGzH6ZASzHn5ia5PxkqR9G34aQiLXvHcFE2zh7jjHJkK9fq7n ykilYYln1bsfZGRPV1rKaSGMgEC/5ySl4PCAGQnA7QBXOWyd63iCm5OBWxFVtV4n0cMw bxrawBbXbiWJAwCtd8MF+DV4dtvP8+sgwdngYtpbP5NyR2R7oKSLjYjyekhRDyoawlNt yFQw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id h16-v6si1525153pli.832.2018.02.28.08.45.49; Wed, 28 Feb 2018 08:46:05 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932761AbeB1QAb (ORCPT + 99 others); Wed, 28 Feb 2018 11:00:31 -0500 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:34657 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932236AbeB1QA1 (ORCPT ); Wed, 28 Feb 2018 11:00:27 -0500 Received: from [2a02:8011:400e:2:6f00:88c8:c921:d332] (helo=deadeye) by shadbolt.decadent.org.uk with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1er3Yt-0006Xd-GW; Wed, 28 Feb 2018 15:22:31 +0000 Received: from ben by deadeye with local (Exim 4.90_1) (envelope-from ) id 1er3Yf-0008VQ-NS; Wed, 28 Feb 2018 15:22:17 +0000 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 From: Ben Hutchings To: linux-kernel@vger.kernel.org, stable@vger.kernel.org CC: akpm@linux-foundation.org, "Herbert Xu" , "David S. Miller" Date: Wed, 28 Feb 2018 15:20:18 +0000 Message-ID: X-Mailer: LinuxStableQueue (scripts by bwh) Subject: [PATCH 3.16 087/254] ipv4: Avoid reading user iov twice after raw_probe_proto_opt In-Reply-To: X-SA-Exim-Connect-IP: 2a02:8011:400e:2:6f00:88c8:c921:d332 X-SA-Exim-Mail-From: ben@decadent.org.uk X-SA-Exim-Scanned: No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.16.55-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: Herbert Xu commit c008ba5bdc9fa830e1a349b20b0be5a137bdef7a upstream. Ever since raw_probe_proto_opt was added it had the problem of causing the user iov to be read twice, once during the probe for the protocol header and once again in ip_append_data. This is a potential security problem since it means that whatever we're probing may be invalid. This patch plugs the hole by firstly advancing the iov so we don't read the same spot again, and secondly saving what we read the first time around for use by ip_append_data. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Ben Hutchings --- net/ipv4/raw.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 8 deletions(-) --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -78,6 +78,16 @@ #include #include #include +#include + +struct raw_frag_vec { + struct iovec *iov; + union { + struct icmphdr icmph; + char c[1]; + } hdr; + int hlen; +}; static struct raw_hashinfo raw_v4_hashinfo = { .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock), @@ -415,25 +425,57 @@ error: return err; } -static int raw_probe_proto_opt(struct flowi4 *fl4, struct msghdr *msg) +static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4) { - struct icmphdr icmph; int err; if (fl4->flowi4_proto != IPPROTO_ICMP) return 0; /* We only need the first two bytes. */ - err = memcpy_fromiovecend((void *)&icmph, msg->msg_iov, 0, 2); + rfv->hlen = 2; + + err = memcpy_fromiovec(rfv->hdr.c, rfv->iov, rfv->hlen); if (err) return err; - fl4->fl4_icmp_type = icmph.type; - fl4->fl4_icmp_code = icmph.code; + fl4->fl4_icmp_type = rfv->hdr.icmph.type; + fl4->fl4_icmp_code = rfv->hdr.icmph.code; return 0; } +static int raw_getfrag(void *from, char *to, int offset, int len, int odd, + struct sk_buff *skb) +{ + struct raw_frag_vec *rfv = from; + + if (offset < rfv->hlen) { + int copy = min(rfv->hlen - offset, len); + + if (skb->ip_summed == CHECKSUM_PARTIAL) + memcpy(to, rfv->hdr.c + offset, copy); + else + skb->csum = csum_block_add( + skb->csum, + csum_partial_copy_nocheck(rfv->hdr.c + offset, + to, copy, 0), + odd); + + odd = 0; + offset += copy; + to += copy; + len -= copy; + + if (!len) + return 0; + } + + offset -= rfv->hlen; + + return ip_generic_getfrag(rfv->iov, to, offset, len, odd, skb); +} + static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { @@ -447,6 +489,7 @@ static int raw_sendmsg(struct kiocb *ioc u8 tos; int err; struct ip_options_data opt_copy; + struct raw_frag_vec rfv; err = -EMSGSIZE; if (len > 0xFFFF) @@ -554,7 +597,10 @@ static int raw_sendmsg(struct kiocb *ioc daddr, saddr, 0, 0); if (!inet->hdrincl) { - err = raw_probe_proto_opt(&fl4, msg); + rfv.iov = msg->msg_iov; + rfv.hlen = 0; + + err = raw_probe_proto_opt(&rfv, &fl4); if (err) goto done; } @@ -583,8 +629,8 @@ back_from_confirm: if (!ipc.addr) ipc.addr = fl4.daddr; lock_sock(sk); - err = ip_append_data(sk, &fl4, ip_generic_getfrag, - msg->msg_iov, len, 0, + err = ip_append_data(sk, &fl4, raw_getfrag, + &rfv, len, 0, &ipc, &rt, msg->msg_flags); if (err) ip_flush_pending_frames(sk);