]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 30 Jan 2021 14:57:00 +0000 (15:57 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 30 Jan 2021 14:57:00 +0000 (15:57 +0100)
added patches:
icmpv6-add-icmpv6-parameter-problem-code-3-definition.patch
ipv6-reply-icmp-error-if-the-first-fragment-don-t-include-all-headers.patch
nbd-freeze-the-queue-while-we-re-adding-connections.patch

queue-5.4/icmpv6-add-icmpv6-parameter-problem-code-3-definition.patch [new file with mode: 0644]
queue-5.4/ipv6-reply-icmp-error-if-the-first-fragment-don-t-include-all-headers.patch [new file with mode: 0644]
queue-5.4/nbd-freeze-the-queue-while-we-re-adding-connections.patch [new file with mode: 0644]

diff --git a/queue-5.4/icmpv6-add-icmpv6-parameter-problem-code-3-definition.patch b/queue-5.4/icmpv6-add-icmpv6-parameter-problem-code-3-definition.patch
new file mode 100644 (file)
index 0000000..3a8f28e
--- /dev/null
@@ -0,0 +1,37 @@
+From b59e286be280fa3c2e94a0716ddcee6ba02bc8ba Mon Sep 17 00:00:00 2001
+From: Hangbin Liu <liuhangbin@gmail.com>
+Date: Tue, 27 Oct 2020 20:33:12 +0800
+Subject: ICMPv6: Add ICMPv6 Parameter Problem, code 3 definition
+
+From: Hangbin Liu <liuhangbin@gmail.com>
+
+commit b59e286be280fa3c2e94a0716ddcee6ba02bc8ba upstream.
+
+Based on RFC7112, Section 6:
+
+   IANA has added the following "Type 4 - Parameter Problem" message to
+   the "Internet Control Message Protocol version 6 (ICMPv6) Parameters"
+   registry:
+
+      CODE     NAME/DESCRIPTION
+       3       IPv6 First Fragment has incomplete IPv6 Header Chain
+
+Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Aviraj CJ <acj@cisco.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/uapi/linux/icmpv6.h |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/uapi/linux/icmpv6.h
++++ b/include/uapi/linux/icmpv6.h
+@@ -137,6 +137,7 @@ struct icmp6hdr {
+ #define ICMPV6_HDR_FIELD              0
+ #define ICMPV6_UNK_NEXTHDR            1
+ #define ICMPV6_UNK_OPTION             2
++#define ICMPV6_HDR_INCOMP             3
+ /*
+  *    constants for (set|get)sockopt
diff --git a/queue-5.4/ipv6-reply-icmp-error-if-the-first-fragment-don-t-include-all-headers.patch b/queue-5.4/ipv6-reply-icmp-error-if-the-first-fragment-don-t-include-all-headers.patch
new file mode 100644 (file)
index 0000000..cb45038
--- /dev/null
@@ -0,0 +1,111 @@
+From 2efdaaaf883a143061296467913c01aa1ff4b3ce Mon Sep 17 00:00:00 2001
+From: Hangbin Liu <liuhangbin@gmail.com>
+Date: Tue, 27 Oct 2020 20:33:13 +0800
+Subject: IPv6: reply ICMP error if the first fragment don't include all headers
+
+From: Hangbin Liu <liuhangbin@gmail.com>
+
+commit 2efdaaaf883a143061296467913c01aa1ff4b3ce upstream.
+
+Based on RFC 8200, Section 4.5 Fragment Header:
+
+  -  If the first fragment does not include all headers through an
+     Upper-Layer header, then that fragment should be discarded and
+     an ICMP Parameter Problem, Code 3, message should be sent to
+     the source of the fragment, with the Pointer field set to zero.
+
+Checking each packet header in IPv6 fast path will have performance impact,
+so I put the checking in ipv6_frag_rcv().
+
+As the packet may be any kind of L4 protocol, I only checked some common
+protocols' header length and handle others by (offset + 1) > skb->len.
+Also use !(frag_off & htons(IP6_OFFSET)) to catch atomic fragments
+(fragmented packet with only one fragment).
+
+When send ICMP error message, if the 1st truncated fragment is ICMP message,
+icmp6_send() will break as is_ineligible() return true. So I added a check
+in is_ineligible() to let fragment packet with nexthdr ICMP but no ICMP header
+return false.
+
+Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Aviraj CJ <acj@cisco.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv6/icmp.c       |    8 +++++++-
+ net/ipv6/reassembly.c |   33 ++++++++++++++++++++++++++++++++-
+ 2 files changed, 39 insertions(+), 2 deletions(-)
+
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -158,7 +158,13 @@ static bool is_ineligible(const struct s
+               tp = skb_header_pointer(skb,
+                       ptr+offsetof(struct icmp6hdr, icmp6_type),
+                       sizeof(_type), &_type);
+-              if (!tp || !(*tp & ICMPV6_INFOMSG_MASK))
++
++              /* Based on RFC 8200, Section 4.5 Fragment Header, return
++               * false if this is a fragment packet with no icmp header info.
++               */
++              if (!tp && frag_off != 0)
++                      return false;
++              else if (!tp || !(*tp & ICMPV6_INFOMSG_MASK))
+                       return true;
+       }
+       return false;
+--- a/net/ipv6/reassembly.c
++++ b/net/ipv6/reassembly.c
+@@ -42,6 +42,8 @@
+ #include <linux/skbuff.h>
+ #include <linux/slab.h>
+ #include <linux/export.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
+ #include <net/sock.h>
+ #include <net/snmp.h>
+@@ -322,7 +324,9 @@ static int ipv6_frag_rcv(struct sk_buff
+       struct frag_queue *fq;
+       const struct ipv6hdr *hdr = ipv6_hdr(skb);
+       struct net *net = dev_net(skb_dst(skb)->dev);
+-      int iif;
++      __be16 frag_off;
++      int iif, offset;
++      u8 nexthdr;
+       if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED)
+               goto fail_hdr;
+@@ -351,6 +355,33 @@ static int ipv6_frag_rcv(struct sk_buff
+               return 1;
+       }
++      /* RFC 8200, Section 4.5 Fragment Header:
++       * If the first fragment does not include all headers through an
++       * Upper-Layer header, then that fragment should be discarded and
++       * an ICMP Parameter Problem, Code 3, message should be sent to
++       * the source of the fragment, with the Pointer field set to zero.
++       */
++      nexthdr = hdr->nexthdr;
++      offset = ipv6_skip_exthdr(skb, skb_transport_offset(skb), &nexthdr, &frag_off);
++      if (offset >= 0) {
++              /* Check some common protocols' header */
++              if (nexthdr == IPPROTO_TCP)
++                      offset += sizeof(struct tcphdr);
++              else if (nexthdr == IPPROTO_UDP)
++                      offset += sizeof(struct udphdr);
++              else if (nexthdr == IPPROTO_ICMPV6)
++                      offset += sizeof(struct icmp6hdr);
++              else
++                      offset += 1;
++
++              if (!(frag_off & htons(IP6_OFFSET)) && offset > skb->len) {
++                      __IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
++                                      IPSTATS_MIB_INHDRERRORS);
++                      icmpv6_param_prob(skb, ICMPV6_HDR_INCOMP, 0);
++                      return -1;
++              }
++      }
++
+       iif = skb->dev ? skb->dev->ifindex : 0;
+       fq = fq_find(net, fhdr->identification, hdr, iif);
+       if (fq) {
diff --git a/queue-5.4/nbd-freeze-the-queue-while-we-re-adding-connections.patch b/queue-5.4/nbd-freeze-the-queue-while-we-re-adding-connections.patch
new file mode 100644 (file)
index 0000000..a2867ce
--- /dev/null
@@ -0,0 +1,60 @@
+From b98e762e3d71e893b221f871825dc64694cfb258 Mon Sep 17 00:00:00 2001
+From: Josef Bacik <josef@toxicpanda.com>
+Date: Mon, 25 Jan 2021 12:21:02 -0500
+Subject: nbd: freeze the queue while we're adding connections
+
+From: Josef Bacik <josef@toxicpanda.com>
+
+commit b98e762e3d71e893b221f871825dc64694cfb258 upstream.
+
+When setting up a device, we can krealloc the config->socks array to add
+new sockets to the configuration.  However if we happen to get a IO
+request in at this point even though we aren't setup we could hit a UAF,
+as we deref config->socks without any locking, assuming that the
+configuration was setup already and that ->socks is safe to access it as
+we have a reference on the configuration.
+
+But there's nothing really preventing IO from occurring at this point of
+the device setup, we don't want to incur the overhead of a lock to
+access ->socks when it will never change while the device is running.
+To fix this UAF scenario simply freeze the queue if we are adding
+sockets.  This will protect us from this particular case without adding
+any additional overhead for the normal running case.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/nbd.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/block/nbd.c
++++ b/drivers/block/nbd.c
+@@ -1014,6 +1014,12 @@ static int nbd_add_socket(struct nbd_dev
+       if (!sock)
+               return err;
++      /*
++       * We need to make sure we don't get any errant requests while we're
++       * reallocating the ->socks array.
++       */
++      blk_mq_freeze_queue(nbd->disk->queue);
++
+       if (!netlink && !nbd->task_setup &&
+           !test_bit(NBD_RT_BOUND, &config->runtime_flags))
+               nbd->task_setup = current;
+@@ -1052,10 +1058,12 @@ static int nbd_add_socket(struct nbd_dev
+       nsock->cookie = 0;
+       socks[config->num_connections++] = nsock;
+       atomic_inc(&config->live_connections);
++      blk_mq_unfreeze_queue(nbd->disk->queue);
+       return 0;
+ put_socket:
++      blk_mq_unfreeze_queue(nbd->disk->queue);
+       sockfd_put(sock);
+       return err;
+ }