From e873d657b954b45ef19ba0c0538be1a071bf83fd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 26 Jan 2024 16:57:05 -0800 Subject: [PATCH] 5.10-stable patches added patches: kvm-use-__vcalloc-for-very-large-allocations.patch mm-vmalloc-introduce-array-allocation-functions.patch smb3-replace-smb2pdu-1-element-arrays-with-flex-arrays.patch stddef-introduce-declare_flex_array-helper.patch --- ...__vcalloc-for-very-large-allocations.patch | 81 ++++ ...ve-highatomic-page-blocks-before-oom.patch | 104 ----- ...introduce-array-allocation-functions.patch | 96 +++++ queue-5.10/series | 5 +- ...du-1-element-arrays-with-flex-arrays.patch | 369 ++++++++++++++++++ ...-introduce-declare_flex_array-helper.patch | 152 ++++++++ 6 files changed, 702 insertions(+), 105 deletions(-) create mode 100644 queue-5.10/kvm-use-__vcalloc-for-very-large-allocations.patch delete mode 100644 queue-5.10/mm-page_alloc-unreserve-highatomic-page-blocks-before-oom.patch create mode 100644 queue-5.10/mm-vmalloc-introduce-array-allocation-functions.patch create mode 100644 queue-5.10/smb3-replace-smb2pdu-1-element-arrays-with-flex-arrays.patch create mode 100644 queue-5.10/stddef-introduce-declare_flex_array-helper.patch diff --git a/queue-5.10/kvm-use-__vcalloc-for-very-large-allocations.patch b/queue-5.10/kvm-use-__vcalloc-for-very-large-allocations.patch new file mode 100644 index 00000000000..6152a965383 --- /dev/null +++ b/queue-5.10/kvm-use-__vcalloc-for-very-large-allocations.patch @@ -0,0 +1,81 @@ +From 37b2a6510a48ca361ced679f92682b7b7d7d0330 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Tue, 8 Mar 2022 04:49:37 -0500 +Subject: KVM: use __vcalloc for very large allocations + +From: Paolo Bonzini + +commit 37b2a6510a48ca361ced679f92682b7b7d7d0330 upstream. + +Allocations whose size is related to the memslot size can be arbitrarily +large. Do not use kvzalloc/kvcalloc, as those are limited to "not crazy" +sizes that fit in 32 bits. + +Cc: stable@vger.kernel.org +Fixes: 7661809d493b ("mm: don't allow oversized kvmalloc() calls") +Reviewed-by: David Hildenbrand +Signed-off-by: Paolo Bonzini +Signed-off-by: Alexander Ofitserov +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/kvm/book3s_hv_uvmem.c | 2 +- + arch/x86/kvm/mmu/page_track.c | 2 +- + arch/x86/kvm/x86.c | 4 ++-- + virt/kvm/kvm_main.c | 4 ++-- + 4 files changed, 6 insertions(+), 6 deletions(-) + +--- a/arch/powerpc/kvm/book3s_hv_uvmem.c ++++ b/arch/powerpc/kvm/book3s_hv_uvmem.c +@@ -250,7 +250,7 @@ int kvmppc_uvmem_slot_init(struct kvm *k + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; +- p->pfns = vzalloc(array_size(slot->npages, sizeof(*p->pfns))); ++ p->pfns = vcalloc(slot->npages, sizeof(*p->pfns)); + if (!p->pfns) { + kfree(p); + return -ENOMEM; +--- a/arch/x86/kvm/mmu/page_track.c ++++ b/arch/x86/kvm/mmu/page_track.c +@@ -35,7 +35,7 @@ int kvm_page_track_create_memslot(struct + + for (i = 0; i < KVM_PAGE_TRACK_MAX; i++) { + slot->arch.gfn_track[i] = +- kvcalloc(npages, sizeof(*slot->arch.gfn_track[i]), ++ __vcalloc(npages, sizeof(*slot->arch.gfn_track[i]), + GFP_KERNEL_ACCOUNT); + if (!slot->arch.gfn_track[i]) + goto track_free; +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -10826,14 +10826,14 @@ static int kvm_alloc_memslot_metadata(st + slot->base_gfn, level) + 1; + + slot->arch.rmap[i] = +- kvcalloc(lpages, sizeof(*slot->arch.rmap[i]), ++ __vcalloc(lpages, sizeof(*slot->arch.rmap[i]), + GFP_KERNEL_ACCOUNT); + if (!slot->arch.rmap[i]) + goto out_free; + if (i == 0) + continue; + +- linfo = kvcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT); ++ linfo = __vcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT); + if (!linfo) + goto out_free; + +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -1008,9 +1008,9 @@ static int kvm_vm_release(struct inode * + */ + static int kvm_alloc_dirty_bitmap(struct kvm_memory_slot *memslot) + { +- unsigned long dirty_bytes = 2 * kvm_dirty_bitmap_bytes(memslot); ++ unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(memslot); + +- memslot->dirty_bitmap = kvzalloc(dirty_bytes, GFP_KERNEL_ACCOUNT); ++ memslot->dirty_bitmap = __vcalloc(2, dirty_bytes, GFP_KERNEL_ACCOUNT); + if (!memslot->dirty_bitmap) + return -ENOMEM; + diff --git a/queue-5.10/mm-page_alloc-unreserve-highatomic-page-blocks-before-oom.patch b/queue-5.10/mm-page_alloc-unreserve-highatomic-page-blocks-before-oom.patch deleted file mode 100644 index e209541e89c..00000000000 --- a/queue-5.10/mm-page_alloc-unreserve-highatomic-page-blocks-before-oom.patch +++ /dev/null @@ -1,104 +0,0 @@ -From ac3f3b0a55518056bc80ed32a41931c99e1f7d81 Mon Sep 17 00:00:00 2001 -From: Charan Teja Kalla -Date: Fri, 24 Nov 2023 16:27:25 +0530 -Subject: mm: page_alloc: unreserve highatomic page blocks before oom - -From: Charan Teja Kalla - -commit ac3f3b0a55518056bc80ed32a41931c99e1f7d81 upstream. - -__alloc_pages_direct_reclaim() is called from slowpath allocation where -high atomic reserves can be unreserved after there is a progress in -reclaim and yet no suitable page is found. Later should_reclaim_retry() -gets called from slow path allocation to decide if the reclaim needs to be -retried before OOM kill path is taken. - -should_reclaim_retry() checks the available(reclaimable + free pages) -memory against the min wmark levels of a zone and returns: - -a) true, if it is above the min wmark so that slow path allocation will - do the reclaim retries. - -b) false, thus slowpath allocation takes oom kill path. - -should_reclaim_retry() can also unreserves the high atomic reserves **but -only after all the reclaim retries are exhausted.** - -In a case where there are almost none reclaimable memory and free pages -contains mostly the high atomic reserves but allocation context can't use -these high atomic reserves, makes the available memory below min wmark -levels hence false is returned from should_reclaim_retry() leading the -allocation request to take OOM kill path. This can turn into a early oom -kill if high atomic reserves are holding lot of free memory and -unreserving of them is not attempted. - -(early)OOM is encountered on a VM with the below state: -[ 295.998653] Normal free:7728kB boost:0kB min:804kB low:1004kB -high:1204kB reserved_highatomic:8192KB active_anon:4kB inactive_anon:0kB -active_file:24kB inactive_file:24kB unevictable:1220kB writepending:0kB -present:70732kB managed:49224kB mlocked:0kB bounce:0kB free_pcp:688kB -local_pcp:492kB free_cma:0kB -[ 295.998656] lowmem_reserve[]: 0 32 -[ 295.998659] Normal: 508*4kB (UMEH) 241*8kB (UMEH) 143*16kB (UMEH) -33*32kB (UH) 7*64kB (UH) 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB -0*4096kB = 7752kB - -Per above log, the free memory of ~7MB exist in the high atomic reserves -is not freed up before falling back to oom kill path. - -Fix it by trying to unreserve the high atomic reserves in -should_reclaim_retry() before __alloc_pages_direct_reclaim() can fallback -to oom kill path. - -Link: https://lkml.kernel.org/r/1700823445-27531-1-git-send-email-quic_charante@quicinc.com -Fixes: 0aaa29a56e4f ("mm, page_alloc: reserve pageblocks for high-order atomic allocations on demand") -Signed-off-by: Charan Teja Kalla -Reported-by: Chris Goldsworthy -Suggested-by: Michal Hocko -Acked-by: Michal Hocko -Acked-by: David Rientjes -Cc: Chris Goldsworthy -Cc: David Hildenbrand -Cc: Johannes Weiner -Cc: Mel Gorman -Cc: Pavankumar Kondeti -Cc: Vlastimil Babka -Cc: Joakim Tjernlund -Signed-off-by: Andrew Morton -Signed-off-by: Greg Kroah-Hartman ---- - mm/page_alloc.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -4534,14 +4534,9 @@ should_reclaim_retry(gfp_t gfp_mask, uns - else - (*no_progress_loops)++; - -- /* -- * Make sure we converge to OOM if we cannot make any progress -- * several times in the row. -- */ -- if (*no_progress_loops > MAX_RECLAIM_RETRIES) { -- /* Before OOM, exhaust highatomic_reserve */ -- return unreserve_highatomic_pageblock(ac, true); -- } -+ if (*no_progress_loops > MAX_RECLAIM_RETRIES) -+ goto out; -+ - - /* - * Keep reclaiming pages while there is a chance this will lead -@@ -4603,6 +4598,11 @@ out: - schedule_timeout_uninterruptible(1); - else - cond_resched(); -+out: -+ /* Before OOM, exhaust highatomic_reserve */ -+ if (!ret) -+ return unreserve_highatomic_pageblock(ac, true); -+ - return ret; - } - diff --git a/queue-5.10/mm-vmalloc-introduce-array-allocation-functions.patch b/queue-5.10/mm-vmalloc-introduce-array-allocation-functions.patch new file mode 100644 index 00000000000..76efe5c586f --- /dev/null +++ b/queue-5.10/mm-vmalloc-introduce-array-allocation-functions.patch @@ -0,0 +1,96 @@ +From a8749a35c39903120ec421ef2525acc8e0daa55c Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Tue, 8 Mar 2022 04:47:22 -0500 +Subject: mm: vmalloc: introduce array allocation functions + +From: Paolo Bonzini + +commit a8749a35c39903120ec421ef2525acc8e0daa55c upstream. + +Linux has dozens of occurrences of vmalloc(array_size()) and +vzalloc(array_size()). Allow to simplify the code by providing +vmalloc_array and vcalloc, as well as the underscored variants that let +the caller specify the GFP flags. + +Acked-by: Michal Hocko +Signed-off-by: Paolo Bonzini +Signed-off-by: Alexander Ofitserov +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/vmalloc.h | 5 ++++ + mm/util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 55 insertions(+) + +--- a/include/linux/vmalloc.h ++++ b/include/linux/vmalloc.h +@@ -112,6 +112,11 @@ extern void *__vmalloc_node_range(unsign + void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask, + int node, const void *caller); + ++extern void *__vmalloc_array(size_t n, size_t size, gfp_t flags) __alloc_size(1, 2); ++extern void *vmalloc_array(size_t n, size_t size) __alloc_size(1, 2); ++extern void *__vcalloc(size_t n, size_t size, gfp_t flags) __alloc_size(1, 2); ++extern void *vcalloc(size_t n, size_t size) __alloc_size(1, 2); ++ + extern void vfree(const void *addr); + extern void vfree_atomic(const void *addr); + +--- a/mm/util.c ++++ b/mm/util.c +@@ -686,6 +686,56 @@ static inline void *__page_rmapping(stru + return (void *)mapping; + } + ++/** ++ * __vmalloc_array - allocate memory for a virtually contiguous array. ++ * @n: number of elements. ++ * @size: element size. ++ * @flags: the type of memory to allocate (see kmalloc). ++ */ ++void *__vmalloc_array(size_t n, size_t size, gfp_t flags) ++{ ++ size_t bytes; ++ ++ if (unlikely(check_mul_overflow(n, size, &bytes))) ++ return NULL; ++ return __vmalloc(bytes, flags); ++} ++EXPORT_SYMBOL(__vmalloc_array); ++ ++/** ++ * vmalloc_array - allocate memory for a virtually contiguous array. ++ * @n: number of elements. ++ * @size: element size. ++ */ ++void *vmalloc_array(size_t n, size_t size) ++{ ++ return __vmalloc_array(n, size, GFP_KERNEL); ++} ++EXPORT_SYMBOL(vmalloc_array); ++ ++/** ++ * __vcalloc - allocate and zero memory for a virtually contiguous array. ++ * @n: number of elements. ++ * @size: element size. ++ * @flags: the type of memory to allocate (see kmalloc). ++ */ ++void *__vcalloc(size_t n, size_t size, gfp_t flags) ++{ ++ return __vmalloc_array(n, size, flags | __GFP_ZERO); ++} ++EXPORT_SYMBOL(__vcalloc); ++ ++/** ++ * vcalloc - allocate and zero memory for a virtually contiguous array. ++ * @n: number of elements. ++ * @size: element size. ++ */ ++void *vcalloc(size_t n, size_t size) ++{ ++ return __vmalloc_array(n, size, GFP_KERNEL | __GFP_ZERO); ++} ++EXPORT_SYMBOL(vcalloc); ++ + /* Neutral page->mapping pointer to address_space or anon_vma or other */ + void *page_rmapping(struct page *page) + { diff --git a/queue-5.10/series b/queue-5.10/series index 6ae4450a06d..74ce7fa91f9 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -36,4 +36,7 @@ nouveau-vmm-don-t-set-addr-on-the-fail-path-to-avoid-warning.patch ubifs-ubifs_symlink-fix-memleak-of-inode-i_link-in-error-path.patch rename-fix-the-locking-of-subdirectories.patch block-remove-special-casing-of-compound-pages.patch -mm-page_alloc-unreserve-highatomic-page-blocks-before-oom.patch +stddef-introduce-declare_flex_array-helper.patch +smb3-replace-smb2pdu-1-element-arrays-with-flex-arrays.patch +mm-vmalloc-introduce-array-allocation-functions.patch +kvm-use-__vcalloc-for-very-large-allocations.patch diff --git a/queue-5.10/smb3-replace-smb2pdu-1-element-arrays-with-flex-arrays.patch b/queue-5.10/smb3-replace-smb2pdu-1-element-arrays-with-flex-arrays.patch new file mode 100644 index 00000000000..b8610ffd2a6 --- /dev/null +++ b/queue-5.10/smb3-replace-smb2pdu-1-element-arrays-with-flex-arrays.patch @@ -0,0 +1,369 @@ +From stable+bounces-15922-greg=kroah.com@vger.kernel.org Fri Jan 26 11:33:27 2024 +From: kovalev@altlinux.org +Date: Fri, 26 Jan 2024 22:31:43 +0300 +Subject: smb3: Replace smb2pdu 1-element arrays with flex-arrays +To: stable@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-cifs@vger.kernel.org, samba-technical@lists.samba.org +Cc: keescook@chromium.org, sfrench@samba.org, corbet@lwn.net, natechancellor@gmail.com, ndesaulniers@google.com, kovalev@altlinux.org, Paulo Alcantara , Ronnie Sahlberg , Shyam Prasad N , Tom Talpey , Namjae Jeon , Sergey Senozhatsky , Steve French +Message-ID: <20240126193143.245122-3-kovalev@altlinux.org> + +From: Kees Cook + +commit eb3e28c1e89b4984308777231887e41aa8a0151f upstream. + +The kernel is globally removing the ambiguous 0-length and 1-element +arrays in favor of flexible arrays, so that we can gain both compile-time +and run-time array bounds checking[1]. + +Replace the trailing 1-element array with a flexible array in the +following structures: + + struct smb2_err_rsp + struct smb2_tree_connect_req + struct smb2_negotiate_rsp + struct smb2_sess_setup_req + struct smb2_sess_setup_rsp + struct smb2_read_req + struct smb2_read_rsp + struct smb2_write_req + struct smb2_write_rsp + struct smb2_query_directory_req + struct smb2_query_directory_rsp + struct smb2_set_info_req + struct smb2_change_notify_rsp + struct smb2_create_rsp + struct smb2_query_info_req + struct smb2_query_info_rsp + +Replace the trailing 1-element array with a flexible array, but leave +the existing structure padding: + + struct smb2_file_all_info + struct smb2_lock_req + +Adjust all related size calculations to match the changes to sizeof(). + +No machine code output or .data section differences are produced after +these changes. + +[1] For lots of details, see both: + https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays + https://people.kernel.org/kees/bounded-flexible-arrays-in-c + +Cc: Steve French +Cc: Paulo Alcantara +Cc: Ronnie Sahlberg +Cc: Shyam Prasad N +Cc: Tom Talpey +Cc: Namjae Jeon +Cc: Sergey Senozhatsky +Cc: linux-cifs@vger.kernel.org +Cc: samba-technical@lists.samba.org +Reviewed-by: Namjae Jeon +Signed-off-by: Kees Cook +Signed-off-by: Steve French +Signed-off-by: Vasiliy Kovalev +Signed-off-by: Greg Kroah-Hartman +--- + fs/cifs/smb2misc.c | 2 +- + fs/cifs/smb2ops.c | 14 +++++++------- + fs/cifs/smb2pdu.c | 13 ++++++------- + fs/cifs/smb2pdu.h | 42 ++++++++++++++++++++++++------------------ + 4 files changed, 38 insertions(+), 33 deletions(-) + +--- a/fs/cifs/smb2misc.c ++++ b/fs/cifs/smb2misc.c +@@ -117,7 +117,7 @@ static __u32 get_neg_ctxt_len(struct smb + } else if (nc_offset + 1 == non_ctxlen) { + cifs_dbg(FYI, "no SPNEGO security blob in negprot rsp\n"); + size_of_pad_before_neg_ctxts = 0; +- } else if (non_ctxlen == SMB311_NEGPROT_BASE_SIZE) ++ } else if (non_ctxlen == SMB311_NEGPROT_BASE_SIZE + 1) + /* has padding, but no SPNEGO blob */ + size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen + 1; + else +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -5561,7 +5561,7 @@ struct smb_version_values smb20_values = + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, + .max_header_size = MAX_SMB2_HDR_SIZE, +- .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, ++ .read_rsp_size = sizeof(struct smb2_read_rsp), + .lock_cmd = SMB2_LOCK, + .cap_unix = 0, + .cap_nt_find = SMB2_NT_FIND, +@@ -5583,7 +5583,7 @@ struct smb_version_values smb21_values = + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, + .max_header_size = MAX_SMB2_HDR_SIZE, +- .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, ++ .read_rsp_size = sizeof(struct smb2_read_rsp), + .lock_cmd = SMB2_LOCK, + .cap_unix = 0, + .cap_nt_find = SMB2_NT_FIND, +@@ -5604,7 +5604,7 @@ struct smb_version_values smb3any_values + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, + .max_header_size = MAX_SMB2_HDR_SIZE, +- .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, ++ .read_rsp_size = sizeof(struct smb2_read_rsp), + .lock_cmd = SMB2_LOCK, + .cap_unix = 0, + .cap_nt_find = SMB2_NT_FIND, +@@ -5625,7 +5625,7 @@ struct smb_version_values smbdefault_val + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, + .max_header_size = MAX_SMB2_HDR_SIZE, +- .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, ++ .read_rsp_size = sizeof(struct smb2_read_rsp), + .lock_cmd = SMB2_LOCK, + .cap_unix = 0, + .cap_nt_find = SMB2_NT_FIND, +@@ -5646,7 +5646,7 @@ struct smb_version_values smb30_values = + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, + .max_header_size = MAX_SMB2_HDR_SIZE, +- .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, ++ .read_rsp_size = sizeof(struct smb2_read_rsp), + .lock_cmd = SMB2_LOCK, + .cap_unix = 0, + .cap_nt_find = SMB2_NT_FIND, +@@ -5667,7 +5667,7 @@ struct smb_version_values smb302_values + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, + .max_header_size = MAX_SMB2_HDR_SIZE, +- .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, ++ .read_rsp_size = sizeof(struct smb2_read_rsp), + .lock_cmd = SMB2_LOCK, + .cap_unix = 0, + .cap_nt_find = SMB2_NT_FIND, +@@ -5688,7 +5688,7 @@ struct smb_version_values smb311_values + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, + .max_header_size = MAX_SMB2_HDR_SIZE, +- .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, ++ .read_rsp_size = sizeof(struct smb2_read_rsp), + .lock_cmd = SMB2_LOCK, + .cap_unix = 0, + .cap_nt_find = SMB2_NT_FIND, +--- a/fs/cifs/smb2pdu.c ++++ b/fs/cifs/smb2pdu.c +@@ -1261,7 +1261,7 @@ SMB2_sess_sendreceive(struct SMB2_sess_d + + /* Testing shows that buffer offset must be at location of Buffer[0] */ + req->SecurityBufferOffset = +- cpu_to_le16(sizeof(struct smb2_sess_setup_req) - 1 /* pad */); ++ cpu_to_le16(sizeof(struct smb2_sess_setup_req)); + req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len); + + memset(&rqst, 0, sizeof(struct smb_rqst)); +@@ -1760,8 +1760,7 @@ SMB2_tcon(const unsigned int xid, struct + iov[0].iov_len = total_len - 1; + + /* Testing shows that buffer offset must be at location of Buffer[0] */ +- req->PathOffset = cpu_to_le16(sizeof(struct smb2_tree_connect_req) +- - 1 /* pad */); ++ req->PathOffset = cpu_to_le16(sizeof(struct smb2_tree_connect_req)); + req->PathLength = cpu_to_le16(unc_path_len - 2); + iov[1].iov_base = unc_path; + iov[1].iov_len = unc_path_len; +@@ -4676,7 +4675,7 @@ int SMB2_query_directory_init(const unsi + memcpy(bufptr, &asteriks, len); + + req->FileNameOffset = +- cpu_to_le16(sizeof(struct smb2_query_directory_req) - 1); ++ cpu_to_le16(sizeof(struct smb2_query_directory_req)); + req->FileNameLength = cpu_to_le16(len); + /* + * BB could be 30 bytes or so longer if we used SMB2 specific +@@ -4873,7 +4872,7 @@ SMB2_set_info_init(struct cifs_tcon *tco + req->AdditionalInformation = cpu_to_le32(additional_info); + + req->BufferOffset = +- cpu_to_le16(sizeof(struct smb2_set_info_req) - 1); ++ cpu_to_le16(sizeof(struct smb2_set_info_req)); + req->BufferLength = cpu_to_le32(*size); + + memcpy(req->Buffer, *data, *size); +@@ -5105,9 +5104,9 @@ build_qfs_info_req(struct kvec *iov, str + req->VolatileFileId = volatile_fid; + /* 1 for pad */ + req->InputBufferOffset = +- cpu_to_le16(sizeof(struct smb2_query_info_req) - 1); ++ cpu_to_le16(sizeof(struct smb2_query_info_req)); + req->OutputBufferLength = cpu_to_le32( +- outbuf_len + sizeof(struct smb2_query_info_rsp) - 1); ++ outbuf_len + sizeof(struct smb2_query_info_rsp)); + + iov->iov_base = (char *)req; + iov->iov_len = total_len; +--- a/fs/cifs/smb2pdu.h ++++ b/fs/cifs/smb2pdu.h +@@ -220,7 +220,7 @@ struct smb2_err_rsp { + __le16 StructureSize; + __le16 Reserved; /* MBZ */ + __le32 ByteCount; /* even if zero, at least one byte follows */ +- __u8 ErrorData[1]; /* variable length */ ++ __u8 ErrorData[]; /* variable length */ + } __packed; + + #define SYMLINK_ERROR_TAG 0x4c4d5953 +@@ -464,7 +464,7 @@ struct smb2_negotiate_rsp { + __le16 SecurityBufferOffset; + __le16 SecurityBufferLength; + __le32 NegotiateContextOffset; /* Pre:SMB3.1.1 was reserved/ignored */ +- __u8 Buffer[1]; /* variable length GSS security buffer */ ++ __u8 Buffer[]; /* variable length GSS security buffer */ + } __packed; + + /* Flags */ +@@ -481,7 +481,7 @@ struct smb2_sess_setup_req { + __le16 SecurityBufferOffset; + __le16 SecurityBufferLength; + __u64 PreviousSessionId; +- __u8 Buffer[1]; /* variable length GSS security buffer */ ++ __u8 Buffer[]; /* variable length GSS security buffer */ + } __packed; + + /* Currently defined SessionFlags */ +@@ -494,7 +494,7 @@ struct smb2_sess_setup_rsp { + __le16 SessionFlags; + __le16 SecurityBufferOffset; + __le16 SecurityBufferLength; +- __u8 Buffer[1]; /* variable length GSS security buffer */ ++ __u8 Buffer[]; /* variable length GSS security buffer */ + } __packed; + + struct smb2_logoff_req { +@@ -520,7 +520,7 @@ struct smb2_tree_connect_req { + __le16 Flags; /* Reserved MBZ for dialects prior to SMB3.1.1 */ + __le16 PathOffset; + __le16 PathLength; +- __u8 Buffer[1]; /* variable length */ ++ __u8 Buffer[]; /* variable length */ + } __packed; + + /* See MS-SMB2 section 2.2.9.2 */ +@@ -828,7 +828,7 @@ struct smb2_create_rsp { + __u64 VolatileFileId; /* opaque endianness */ + __le32 CreateContextsOffset; + __le32 CreateContextsLength; +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + struct create_context { +@@ -1289,7 +1289,7 @@ struct smb2_read_plain_req { + __le32 RemainingBytes; + __le16 ReadChannelInfoOffset; + __le16 ReadChannelInfoLength; +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + /* Read flags */ +@@ -1304,7 +1304,7 @@ struct smb2_read_rsp { + __le32 DataLength; + __le32 DataRemaining; + __u32 Flags; +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + /* For write request Flags field below the following flags are defined: */ +@@ -1324,7 +1324,7 @@ struct smb2_write_req { + __le16 WriteChannelInfoOffset; + __le16 WriteChannelInfoLength; + __le32 Flags; +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + struct smb2_write_rsp { +@@ -1335,7 +1335,7 @@ struct smb2_write_rsp { + __le32 DataLength; + __le32 DataRemaining; + __u32 Reserved2; +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + /* notify flags */ +@@ -1371,7 +1371,7 @@ struct smb2_change_notify_rsp { + __le16 StructureSize; /* Must be 9 */ + __le16 OutputBufferOffset; + __le32 OutputBufferLength; +- __u8 Buffer[1]; /* array of file notify structs */ ++ __u8 Buffer[]; /* array of file notify structs */ + } __packed; + + #define SMB2_LOCKFLAG_SHARED_LOCK 0x0001 +@@ -1394,7 +1394,10 @@ struct smb2_lock_req { + __u64 PersistentFileId; /* opaque endianness */ + __u64 VolatileFileId; /* opaque endianness */ + /* Followed by at least one */ +- struct smb2_lock_element locks[1]; ++ union { ++ struct smb2_lock_element lock; ++ DECLARE_FLEX_ARRAY(struct smb2_lock_element, locks); ++ }; + } __packed; + + struct smb2_lock_rsp { +@@ -1434,7 +1437,7 @@ struct smb2_query_directory_req { + __le16 FileNameOffset; + __le16 FileNameLength; + __le32 OutputBufferLength; +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + struct smb2_query_directory_rsp { +@@ -1442,7 +1445,7 @@ struct smb2_query_directory_rsp { + __le16 StructureSize; /* Must be 9 */ + __le16 OutputBufferOffset; + __le32 OutputBufferLength; +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + /* Possible InfoType values */ +@@ -1483,7 +1486,7 @@ struct smb2_query_info_req { + __le32 Flags; + __u64 PersistentFileId; /* opaque endianness */ + __u64 VolatileFileId; /* opaque endianness */ +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + struct smb2_query_info_rsp { +@@ -1491,7 +1494,7 @@ struct smb2_query_info_rsp { + __le16 StructureSize; /* Must be 9 */ + __le16 OutputBufferOffset; + __le32 OutputBufferLength; +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + /* +@@ -1514,7 +1517,7 @@ struct smb2_set_info_req { + __le32 AdditionalInformation; + __u64 PersistentFileId; /* opaque endianness */ + __u64 VolatileFileId; /* opaque endianness */ +- __u8 Buffer[1]; ++ __u8 Buffer[]; + } __packed; + + struct smb2_set_info_rsp { +@@ -1716,7 +1719,10 @@ struct smb2_file_all_info { /* data bloc + __le32 Mode; + __le32 AlignmentRequirement; + __le32 FileNameLength; +- char FileName[1]; ++ union { ++ char __pad; /* Legacy structure padding */ ++ DECLARE_FLEX_ARRAY(char, FileName); ++ }; + } __packed; /* level 18 Query */ + + struct smb2_file_eof_info { /* encoding of request for level 10 */ diff --git a/queue-5.10/stddef-introduce-declare_flex_array-helper.patch b/queue-5.10/stddef-introduce-declare_flex_array-helper.patch new file mode 100644 index 00000000000..492e0af469b --- /dev/null +++ b/queue-5.10/stddef-introduce-declare_flex_array-helper.patch @@ -0,0 +1,152 @@ +From stable+bounces-15920-greg=kroah.com@vger.kernel.org Fri Jan 26 11:32:58 2024 +From: kovalev@altlinux.org +Date: Fri, 26 Jan 2024 22:31:42 +0300 +Subject: stddef: Introduce DECLARE_FLEX_ARRAY() helper +To: stable@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-cifs@vger.kernel.org, samba-technical@lists.samba.org +Cc: keescook@chromium.org, sfrench@samba.org, corbet@lwn.net, natechancellor@gmail.com, ndesaulniers@google.com, kovalev@altlinux.org, Arnd Bergmann , "Gustavo A. R. Silva" +Message-ID: <20240126193143.245122-2-kovalev@altlinux.org> + +From: Kees Cook + +commit 3080ea5553cc909b000d1f1d964a9041962f2c5b upstream. + +There are many places where kernel code wants to have several different +typed trailing flexible arrays. This would normally be done with multiple +flexible arrays in a union, but since GCC and Clang don't (on the surface) +allow this, there have been many open-coded workarounds, usually involving +neighboring 0-element arrays at the end of a structure. For example, +instead of something like this: + +struct thing { + ... + union { + struct type1 foo[]; + struct type2 bar[]; + }; +}; + +code works around the compiler with: + +struct thing { + ... + struct type1 foo[0]; + struct type2 bar[]; +}; + +Another case is when a flexible array is wanted as the single member +within a struct (which itself is usually in a union). For example, this +would be worked around as: + +union many { + ... + struct { + struct type3 baz[0]; + }; +}; + +These kinds of work-arounds cause problems with size checks against such +zero-element arrays (for example when building with -Warray-bounds and +-Wzero-length-bounds, and with the coming FORTIFY_SOURCE improvements), +so they must all be converted to "real" flexible arrays, avoiding warnings +like this: + +fs/hpfs/anode.c: In function 'hpfs_add_sector_to_btree': +fs/hpfs/anode.c:209:27: warning: array subscript 0 is outside the bounds of an interior zero-length array 'struct bplus_internal_node[0]' [-Wzero-length-bounds] + 209 | anode->btree.u.internal[0].down = cpu_to_le32(a); + | ~~~~~~~~~~~~~~~~~~~~~~~^~~ +In file included from fs/hpfs/hpfs_fn.h:26, + from fs/hpfs/anode.c:10: +fs/hpfs/hpfs.h:412:32: note: while referencing 'internal' + 412 | struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving + | ^~~~~~~~ + +drivers/net/can/usb/etas_es58x/es58x_fd.c: In function 'es58x_fd_tx_can_msg': +drivers/net/can/usb/etas_es58x/es58x_fd.c:360:35: warning: array subscript 65535 is outside the bounds of an interior zero-length array 'u8[0]' {aka 'unsigned char[]'} [-Wzero-length-bounds] + 360 | tx_can_msg = (typeof(tx_can_msg))&es58x_fd_urb_cmd->raw_msg[msg_len]; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In file included from drivers/net/can/usb/etas_es58x/es58x_core.h:22, + from drivers/net/can/usb/etas_es58x/es58x_fd.c:17: +drivers/net/can/usb/etas_es58x/es58x_fd.h:231:6: note: while referencing 'raw_msg' + 231 | u8 raw_msg[0]; + | ^~~~~~~ + +However, it _is_ entirely possible to have one or more flexible arrays +in a struct or union: it just has to be in another struct. And since it +cannot be alone in a struct, such a struct must have at least 1 other +named member -- but that member can be zero sized. Wrap all this nonsense +into the new DECLARE_FLEX_ARRAY() in support of having flexible arrays +in unions (or alone in a struct). + +As with struct_group(), since this is needed in UAPI headers as well, +implement the core there, with a non-UAPI wrapper. + +Additionally update kernel-doc to understand its existence. + +https://github.com/KSPP/linux/issues/137 + +Cc: Arnd Bergmann +Cc: "Gustavo A. R. Silva" +Signed-off-by: Kees Cook +Signed-off-by: Vasiliy Kovalev +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/stddef.h | 13 +++++++++++++ + include/uapi/linux/stddef.h | 16 ++++++++++++++++ + scripts/kernel-doc | 3 ++- + 3 files changed, 31 insertions(+), 1 deletion(-) + +--- a/include/linux/stddef.h ++++ b/include/linux/stddef.h +@@ -84,4 +84,17 @@ enum { + #define struct_group_tagged(TAG, NAME, MEMBERS...) \ + __struct_group(TAG, NAME, /* no attrs */, MEMBERS) + ++/** ++ * DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union ++ * ++ * @TYPE: The type of each flexible array element ++ * @NAME: The name of the flexible array member ++ * ++ * In order to have a flexible array member in a union or alone in a ++ * struct, it needs to be wrapped in an anonymous struct with at least 1 ++ * named member, but that member can be empty. ++ */ ++#define DECLARE_FLEX_ARRAY(TYPE, NAME) \ ++ __DECLARE_FLEX_ARRAY(TYPE, NAME) ++ + #endif +--- a/include/uapi/linux/stddef.h ++++ b/include/uapi/linux/stddef.h +@@ -28,4 +28,20 @@ + struct { MEMBERS } ATTRS; \ + struct TAG { MEMBERS } ATTRS NAME; \ + } ++ ++/** ++ * __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union ++ * ++ * @TYPE: The type of each flexible array element ++ * @NAME: The name of the flexible array member ++ * ++ * In order to have a flexible array member in a union or alone in a ++ * struct, it needs to be wrapped in an anonymous struct with at least 1 ++ * named member, but that member can be empty. ++ */ ++#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \ ++ struct { \ ++ struct { } __empty_ ## NAME; \ ++ TYPE NAME[]; \ ++ } + #endif +--- a/scripts/kernel-doc ++++ b/scripts/kernel-doc +@@ -1232,7 +1232,8 @@ sub dump_struct($$) { + $members =~ s/DECLARE_KFIFO\s*\(([^,)]+),\s*([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos; + # replace DECLARE_KFIFO_PTR + $members =~ s/DECLARE_KFIFO_PTR\s*\(([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos; +- ++ # replace DECLARE_FLEX_ARRAY ++ $members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos; + my $declaration = $members; + + # Split nested struct/union elements as newer ones -- 2.47.3