From e91bb401f88e42037a04111227a024efe8ad3c3f Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Mon, 7 Mar 2022 13:11:39 +0100 Subject: [PATCH 1/5] esp: Fix possible buffer overflow in ESP transformation Signed-off-by: wufan ----------------------------------------------- mainline inclusion from mainline-v5.17-rc8 commit ebe48d368e97d007bfeb76fcb065d6cfc4c96645 category: bugfix issue: #I4YLYC CVE: CVE-2022-0886 Signed-off-by: Yu Changchun --------------------------------------- The maximum message size that can be send is bigger than the maximum site that skb_page_frag_refill can allocate. So it is possible to write beyond the allocated buffer. Fix this by doing a fallback to COW in that case. v2: Avoid get get_order() costs as suggested by Linus Torvalds. Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible") Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible") Reported-by: valis Signed-off-by: Steffen Klassert Signed-off-by: Xu Jia Reviewed-by: Wei Yongjun Reviewed-by: Xiu Jianfeng Signed-off-by: Zheng Zengkai Signed-off-by: Yu Changchun --- include/net/esp.h | 2 ++ net/ipv4/esp4.c | 5 +++++ net/ipv6/esp6.c | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/include/net/esp.h b/include/net/esp.h index 117652eb6ea3..465e38890ee9 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -4,6 +4,8 @@ #include +#define ESP_SKB_FRAG_MAXSIZE (PAGE_SIZE << SKB_FRAG_PAGE_ORDER) + struct ip_esp_hdr; static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb) diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 114f9def1ec5..cde9a5fd4149 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -276,6 +276,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; + unsigned int allocsz; /* this is non-NULL only with UDP Encapsulation */ if (x->encap) { @@ -285,6 +286,10 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * return err; } + allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); + if (allocsz > ESP_SKB_FRAG_MAXSIZE) + goto cow; + if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { nfrags = 1; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index a7d996148eed..53987b1c227c 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -242,6 +242,11 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; + unsigned int allocsz; + + allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); + if (allocsz > ESP_SKB_FRAG_MAXSIZE) + goto cow; if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { -- Gitee From 81da9382e75420d0062a0f8d35d52820613d4b1c Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Thu, 26 Aug 2021 10:49:47 +0800 Subject: [PATCH 2/5] sock: remove one redundant SKB_FRAG_PAGE_ORDER macro Signed-off-by: wufan ----------------------------------------------- mainline inclusion from mainline-v5.15-rc1 commit 723783d077e39c256a1fafebbd97cbb14207c28f category: bugfix issue: #I4YLYC CVE: CVE-2022-0886 Signed-off-by: Yu Changchun --------------------------------------- Both SKB_FRAG_PAGE_ORDER are defined to the same value in net/core/sock.c and drivers/vhost/net.c. Move the SKB_FRAG_PAGE_ORDER definition to net/core/sock.h, as both net/core/sock.c and drivers/vhost/net.c include it, and it seems a reasonable file to put the macro. Signed-off-by: Yunsheng Lin Acked-by: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Xu Jia Reviewed-by: Wei Yongjun Reviewed-by: Xiu Jianfeng Signed-off-by: Zheng Zengkai Signed-off-by: Yu Changchun --- include/net/sock.h | 3 +++ net/core/sock.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index bc752237dff3..d280da601c25 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2512,6 +2512,9 @@ extern int sysctl_optmem_max; extern __u32 sysctl_wmem_default; extern __u32 sysctl_rmem_default; +#define SKB_FRAG_PAGE_ORDER get_order(32768) +DECLARE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key); + static inline int sk_get_wmem0(const struct sock *sk, const struct proto *proto) { /* Does this proto have per netns sysctl_wmem ? */ diff --git a/net/core/sock.c b/net/core/sock.c index d243a6f41267..b9cfe5589d38 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2189,8 +2189,7 @@ static void sk_leave_memory_pressure(struct sock *sk) } } -/* On 32bit arches, an skb frag is limited to 2^15 */ -#define SKB_FRAG_PAGE_ORDER get_order(32768) +DEFINE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key); /** * skb_page_frag_refill - check that a page_frag contains enough room -- Gitee From a49d8775750fa6cd3de006d569d32366fbc605a4 Mon Sep 17 00:00:00 2001 From: Haimin Zhang Date: Wed, 16 Feb 2022 16:40:38 +0800 Subject: [PATCH 3/5] block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kern Signed-off-by: wufan ----------------------------------------------- stable inclusion from stable-5.17-rc5 commit cc8f7fe1f5eab010191aa4570f27641876fa1267 category: bugfix issue: I51A19 CVE: CVE-2022-0494 Signed-off-by: gaochao --------------------------------------- block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kern Add __GFP_ZERO flag for alloc_page in function bio_copy_kern to initialize the buffer of a bio. Signed-off-by: Haimin Zhang Reviewed-by: Chaitanya Kulkarni Reviewed-by: Christoph Hellwig Link: https://lore.kernel.org/r/20220216084038.15635-1-tcs.kernel@gmail.com Signed-off-by: Jens Axboe --- block/bio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/bio.c b/block/bio.c index 3d757055305f..2b4a505d2ee4 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1528,7 +1528,7 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, if (bytes > len) bytes = len; - page = alloc_page(q->bounce_gfp | gfp_mask); + page = alloc_page(q->bounce_gfp | __GFP_ZERO | gfp_mask); if (!page) goto cleanup; -- Gitee From 01d5a1f8e0cd3323d86fe2bed3fffd9317158bda Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 13 Apr 2022 11:09:57 +0800 Subject: [PATCH 4/5] Reinstate some of "swiotlb: rework "fix info leak with DMA_FROM_DEVICE"" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wufan ----------------------------------------------- Signed-off-by: Kong Zhiquan ------------------------------ mainline inclusion from mainline-v5.18-rc1 commit 901c7280ca0d5e2b4a8929fbe0bfb007ac2a6544 category: bugfix bugzilla: 186478, https://gitee.com/src-openeuler/kernel/issues/I503W4 CVE: CVE-2022-0854 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=901c7280ca0d5e2b4a8929fbe0bfb007ac2a6544 -------------------------------- Halil Pasic points out [1] that the full revert of that commit (revert in bddac7c1e02b), and that a partial revert that only reverts the problematic case, but still keeps some of the cleanups is probably better.  And that partial revert [2] had already been verified by Oleksandr Natalenko to also fix the issue, I had just missed that in the long discussion. So let's reinstate the cleanups from commit aa6f8dcbab47 ("swiotlb: rework "fix info leak with DMA_FROM_DEVICE""), and effectively only revert the part that caused problems. Link: https://lore.kernel.org/all/20220328013731.017ae3e3.pasic@linux.ibm.com/ [1] Link: https://lore.kernel.org/all/20220324055732.GB12078@lst.de/ [2] Link: https://lore.kernel.org/all/4386660.LvFx2qVVIh@natalenko.name/ [3] Suggested-by: Halil Pasic Tested-by: Oleksandr Natalenko Cc: Christoph Hellwig" Signed-off-by: Linus Torvalds Conflicts: kernel/dma/swiotlb.c Signed-off-by: Liu Shixin Signed-off-by: Zheng Zengkai Reviewed-by: Kefeng Wang Reviewed-by: Weilong Chen --- kernel/dma/swiotlb.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 2a8c41f12d45..543597e33cff 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -583,10 +583,15 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, */ for (i = 0; i < nslots; i++) io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT); - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && - (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) - swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE); + /* + * When dir == DMA_FROM_DEVICE we could omit the copy from the orig + * to the tlb buffer, if we knew for sure the device will + * overwirte the entire current content. But we don't. Thus + * unconditional bounce may prevent leaking swiotlb content (i.e. + * kernel memory) to user-space. + */ + swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE); return tlb_addr; } -- Gitee From 4ce48c36502dd45375cb67547bd134009d22f6da Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 3 Apr 2022 15:58:11 -0400 Subject: [PATCH 5/5] SUNRPC: Ensure we flush any closed sockets before xs_xprt_free() Signed-off-by: wufan ----------------------------------------------- stable inclusion from stable-v5.18-rc2 commit f00432063db1a0db484e85193eccc6845435b80e category: bugfix issue: #I51A19 CVE: CVE-2022-28893 Signed-off-by: gaochao ------------------------------------------- SUNRPC: Ensure we flush any closed sockets before xs_xprt_free() We must ensure that all sockets are closed before we call xprt_free() and release the reference to the net namespace. The problem is that calling fput() will defer closing the socket until delayed_fput() gets called. Let's fix the situation by allowing rpciod and the transport teardown code (which runs on the system wq) to call __fput_sync(), and directly close the socket. Reported-by: Felix Fu Acked-by: Al Viro Fixes: a73881c96d73 ("SUNRPC: Fix an Oops in udp_poll()") Cc: stable@vger.kernel.org # 5.1.x: 3be232f11a3c: SUNRPC: Prevent immediate close+reconnect Cc: stable@vger.kernel.org # 5.1.x: 89f42494f92f: SUNRPC: Don't call connect() more than once on a TCP socket Cc: stable@vger.kernel.org # 5.1.x Signed-off-by: Trond Myklebust --- fs/file_table.c | 1 + net/sunrpc/xprt.c | 5 +---- net/sunrpc/xprtsock.c | 12 +++++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/fs/file_table.c b/fs/file_table.c index e49af4caf15d..ba4418325c26 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -365,6 +365,7 @@ void __fput_sync(struct file *file) } EXPORT_SYMBOL(fput); +EXPORT_SYMBOL(__fput_sync); void __init files_init(void) { diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 5e7c13aa66d0..7ca4bb09c48a 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -768,10 +768,7 @@ void xprt_connect(struct rpc_task *task) if (!xprt_lock_write(xprt, task)) return; - if (test_and_clear_bit(XPRT_CLOSE_WAIT, &xprt->state)) - xprt->ops->close(xprt); - - if (!xprt_connected(xprt)) { + if (!xprt_connected(xprt) && !test_bit(XPRT_CLOSE_WAIT, &xprt->state)) { task->tk_rqstp->rq_bytes_sent = 0; task->tk_timeout = task->tk_rqstp->rq_timeout; task->tk_rqstp->rq_connect_cookie = xprt->connect_cookie; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 9dc059dea689..917724875a64 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -557,7 +557,7 @@ static int xs_local_send_request(struct rpc_task *task) -status); /* fall through */ case -EPIPE: - xs_close(xprt); + xprt_force_disconnect(xprt); status = -ENOTCONN; } @@ -845,6 +845,16 @@ static void xs_reset_transport(struct sock_xprt *transport) if (sk == NULL) return; + /* + * Make sure we're calling this in a context from which it is safe + * to call __fput_sync(). In practice that means rpciod and the + * system workqueue. + */ + if (!(current->flags & PF_WQ_WORKER)) { + WARN_ON_ONCE(1); + set_bit(XPRT_CLOSE_WAIT, &xprt->state); + return; + } if (atomic_read(&transport->xprt.swapper)) sk_clear_memalloc(sk); -- Gitee