From patchwork Tue Aug 1 21:10:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 129509 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9f41:0:b0:3e4:2afc:c1 with SMTP id v1csp50610vqx; Tue, 1 Aug 2023 15:25:46 -0700 (PDT) X-Google-Smtp-Source: APBJJlF5aOulttAHdX6dPw4uBJGf2fCzRDcikbarxX3HAoB58RXHRLSmr54T1qvimKjykpxbHw5n X-Received: by 2002:a05:6512:3c9d:b0:4fd:d016:c2e8 with SMTP id h29-20020a0565123c9d00b004fdd016c2e8mr4124657lfv.43.1690928746359; Tue, 01 Aug 2023 15:25:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690928746; cv=none; d=google.com; s=arc-20160816; b=Yg6OzlaDTetwM2zk1CrYKgx+kJDcJXcRc5tZqqlyg78ByUbLB1bgpbIQ8WQN2fuUKy 3evxYerMRr6lfJ+A0tUPtioetMTtm47yhrexHAWtKELRy/YKTe4yBJdks6rmbE0D+kWz g8+f4EmUuk2ZhZvfUPY0JcKN9zwhk2Tb8fyRBJZDRn+Kj+6EojFcMYq3OOqEO+yIlgSI 0tq7v218r31sruck+OHByCvrVNyQogcp2y3R5uPHg/3Wo5Q9ba/kAn3KZUMOJUo930eu O5CkcNGhx6AueBipHYhifnDwOm5q89Pc5Tys38wzNHkpzHd8KntFKv2rms1uIr9f0AdZ cFbA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:message-id:date:content-transfer-encoding :content-id:mime-version:subject:cc:to:from:organization :dkim-signature; bh=DI/Y27iYKk+GE2VbFkdqv51tvM927ZHMATm+vJN1hrs=; fh=sNMMWQTQQL4jS23WvYxwAJ6nk8/wHFpQy0iwPKo/4jY=; b=SwNZ4u5OM/jc6ZmKl0vV/SQIbA96XY2Dwv5u84PBuU68kfAtLo0touJaqs8hMEEAHW f7kOwZEIq1R/bRklbDZdCIdqYnpakJSV6uRr1HDXb+ILUw0/fUAOqU8sLhG2yEH5zoSP EpTearJCYXfhtGv13TrtQ6nJoIA1Ht69liroFBn6Ed9f+4PfYPFOiR7w5s3TccRCM9Hs /4XIc5L69lWHhc19HbnC0yWvPbsFHdZ+0+XqOlKXXWIgc0I4YsFX6W9k6FYXp0bjYuzl BzWcDK4ky8+i2EThWrh7K/c/TMBS9Zp//gH47uCsYXblTnBQA0KhgxBv9jG3uEoZckFa flNQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=e0JDJwbv; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id l16-20020aa7d950000000b00522270c5923si8753077eds.528.2023.08.01.15.25.21; Tue, 01 Aug 2023 15:25:46 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=e0JDJwbv; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231867AbjHAVLI (ORCPT + 99 others); Tue, 1 Aug 2023 17:11:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37994 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229898AbjHAVLF (ORCPT ); Tue, 1 Aug 2023 17:11:05 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D8040E6D for ; Tue, 1 Aug 2023 14:10:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1690924216; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=DI/Y27iYKk+GE2VbFkdqv51tvM927ZHMATm+vJN1hrs=; b=e0JDJwbvfoESn9+plrQPt2RroSxZ4ydPvjN7b7vjFgzWHI8aExiLDQ7tEll7ZIjaqYWR+n jN2xJRynxdkD64IX907PukxftWDDgo4k6tit5C0GCIX72AFdC1N8SgquFHLRH9LBElly+Q zOn2TXGq864BssY+5L9QDpIUgmH2RZ0= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-90-rpc81ftLN8q6r6O45lqd1A-1; Tue, 01 Aug 2023 17:10:13 -0400 X-MC-Unique: rpc81ftLN8q6r6O45lqd1A-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id DC98A856F66; Tue, 1 Aug 2023 21:10:09 +0000 (UTC) Received: from warthog.procyon.org.uk (unknown [10.42.28.131]) by smtp.corp.redhat.com (Postfix) with ESMTP id 03F2240C6CCC; Tue, 1 Aug 2023 21:10:07 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 From: David Howells To: netdev@vger.kernel.org, Willem de Bruijn cc: dhowells@redhat.com, syzbot+f527b971b4bdc8e79f9e@syzkaller.appspotmail.com, bpf@vger.kernel.org, brauner@kernel.org, davem@davemloft.net, dsahern@kernel.org, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, axboe@kernel.dk, viro@zeniv.linux.org.uk, linux-fsdevel@vger.kernel.org, syzkaller-bugs@googlegroups.com, linux-kernel@vger.kernel.org Subject: [PATCH net v2] udp: Fix __ip{,6}_append_data()'s handling of MSG_SPLICE_PAGES MIME-Version: 1.0 Content-ID: <1569148.1690924207.1@warthog.procyon.org.uk> Date: Tue, 01 Aug 2023 22:10:07 +0100 Message-ID: <1569149.1690924207@warthog.procyon.org.uk> X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1773065320750475937 X-GMAIL-MSGID: 1773067300861149173 __ip_append_data() can get into an infinite loop when asked to splice into a partially-built UDP message that has more than the frag-limit data and up to the MTU limit. Something like: pipe(pfd); sfd = socket(AF_INET, SOCK_DGRAM, 0); connect(sfd, ...); send(sfd, buffer, 8161, MSG_CONFIRM|MSG_MORE); write(pfd[1], buffer, 8); splice(pfd[0], 0, sfd, 0, 0x4ffe0ul, 0); where the amount of data given to send() is dependent on the MTU size (in this instance an interface with an MTU of 8192). The problem is that the calculation of the amount to copy in __ip_append_data() goes negative in two places, and, in the second place, this gets subtracted from the length remaining, thereby increasing it. This happens when pagedlen > 0 (which happens for MSG_ZEROCOPY and MSG_SPLICE_PAGES), the terms in: copy = datalen - transhdrlen - fraggap - pagedlen; then mostly cancel when pagedlen is substituted for, leaving just -fraggap. This causes: length -= copy + transhdrlen; to increase the length to more than the amount of data in msg->msg_iter, which causes skb_splice_from_iter() to be unable to fill the request and it returns less than 'copied' - which means that length never gets to 0 and we never exit the loop. Fix this by: (1) Insert a note about the dodgy calculation of 'copy'. (2) If MSG_SPLICE_PAGES, clear copy if it is negative from the above equation, so that 'offset' isn't regressed and 'length' isn't increased, which will mean that length and thus copy should match the amount left in the iterator. (3) When handling MSG_SPLICE_PAGES, give a warning and return -EIO if we're asked to splice more than is in the iterator. It might be better to not give the warning or even just give a 'short' write. The same problem occurs in __ip6_append_data(), except that there's a check in there that errors out with EINVAL if copy < 0. Fix this function in much the same way as the ipv4 variant but also skip the erroring out if copy < 0. [!] Note that this ought to also affect MSG_ZEROCOPY, but MSG_ZEROCOPY avoids the problem by simply assuming that everything asked for got copied, not just the amount that was in the iterator. This is a potential bug for the future. Fixes: 7ac7c987850c ("udp: Convert udp_sendpage() to use MSG_SPLICE_PAGES") Fixes: 6d8192bd69bb ("ip6, udp6: Support MSG_SPLICE_PAGES") Reported-by: syzbot+f527b971b4bdc8e79f9e@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000881d0606004541d1@google.com/ Signed-off-by: David Howells cc: Willem de Bruijn cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox cc: netdev@vger.kernel.org --- ver #2) - Fix __ip6_append_data() also. net/ipv4/ip_output.c | 9 +++++++++ net/ipv6/ip6_output.c | 11 ++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 6e70839257f7..91715603cf6e 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1158,10 +1158,15 @@ static int __ip_append_data(struct sock *sk, } copy = datalen - transhdrlen - fraggap - pagedlen; + /* [!] NOTE: copy will be negative if pagedlen>0 + * because then the equation reduces to -fraggap. + */ if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { err = -EFAULT; kfree_skb(skb); goto error; + } else if (flags & MSG_SPLICE_PAGES) { + copy = 0; } offset += copy; @@ -1209,6 +1214,10 @@ static int __ip_append_data(struct sock *sk, } else if (flags & MSG_SPLICE_PAGES) { struct msghdr *msg = from; + err = -EIO; + if (WARN_ON_ONCE(copy > msg->msg_iter.count)) + goto error; + err = skb_splice_from_iter(skb, &msg->msg_iter, copy, sk->sk_allocation); if (err < 0) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 1e8c90e97608..bc96559bbf0f 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1693,7 +1693,10 @@ static int __ip6_append_data(struct sock *sk, fraglen = datalen + fragheaderlen; copy = datalen - transhdrlen - fraggap - pagedlen; - if (copy < 0) { + /* [!] NOTE: copy may be negative if pagedlen>0 + * because then the equation may reduces to -fraggap. + */ + if (copy < 0 && !(flags & MSG_SPLICE_PAGES)) { err = -EINVAL; goto error; } @@ -1744,6 +1747,8 @@ static int __ip6_append_data(struct sock *sk, err = -EFAULT; kfree_skb(skb); goto error; + } else if (flags & MSG_SPLICE_PAGES) { + copy = 0; } offset += copy; @@ -1791,6 +1796,10 @@ static int __ip6_append_data(struct sock *sk, } else if (flags & MSG_SPLICE_PAGES) { struct msghdr *msg = from; + err = -EIO; + if (WARN_ON_ONCE(copy > msg->msg_iter.count)) + goto error; + err = skb_splice_from_iter(skb, &msg->msg_iter, copy, sk->sk_allocation); if (err < 0)