From 950ad38c29d2a829869a71de6c217eb369d3683e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 30 Jan 2021 15:57:00 +0100 Subject: [PATCH] 5.4-stable patches 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 --- ...-parameter-problem-code-3-definition.patch | 37 ++++++ ...t-fragment-don-t-include-all-headers.patch | 111 ++++++++++++++++++ ...queue-while-we-re-adding-connections.patch | 60 ++++++++++ 3 files changed, 208 insertions(+) create mode 100644 queue-5.4/icmpv6-add-icmpv6-parameter-problem-code-3-definition.patch create mode 100644 queue-5.4/ipv6-reply-icmp-error-if-the-first-fragment-don-t-include-all-headers.patch create mode 100644 queue-5.4/nbd-freeze-the-queue-while-we-re-adding-connections.patch 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 index 00000000000..3a8f28e4d52 --- /dev/null +++ b/queue-5.4/icmpv6-add-icmpv6-parameter-problem-code-3-definition.patch @@ -0,0 +1,37 @@ +From b59e286be280fa3c2e94a0716ddcee6ba02bc8ba Mon Sep 17 00:00:00 2001 +From: Hangbin Liu +Date: Tue, 27 Oct 2020 20:33:12 +0800 +Subject: ICMPv6: Add ICMPv6 Parameter Problem, code 3 definition + +From: Hangbin Liu + +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 +Signed-off-by: Jakub Kicinski +Signed-off-by: Aviraj CJ +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..cb45038e5b1 --- /dev/null +++ b/queue-5.4/ipv6-reply-icmp-error-if-the-first-fragment-don-t-include-all-headers.patch @@ -0,0 +1,111 @@ +From 2efdaaaf883a143061296467913c01aa1ff4b3ce Mon Sep 17 00:00:00 2001 +From: Hangbin Liu +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 + +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 +Signed-off-by: Jakub Kicinski +Signed-off-by: Aviraj CJ +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include ++#include + + #include + #include +@@ -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 index 00000000000..a2867ce72c2 --- /dev/null +++ b/queue-5.4/nbd-freeze-the-queue-while-we-re-adding-connections.patch @@ -0,0 +1,60 @@ +From b98e762e3d71e893b221f871825dc64694cfb258 Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Mon, 25 Jan 2021 12:21:02 -0500 +Subject: nbd: freeze the queue while we're adding connections + +From: Josef Bacik + +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 +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + } -- 2.47.3