diff --git a/COPYING-5.14.0-687.10.1.el9_8 b/COPYING-5.14.0-687.12.1.el9_8 similarity index 100% rename from COPYING-5.14.0-687.10.1.el9_8 rename to COPYING-5.14.0-687.12.1.el9_8 diff --git a/Makefile.rhelver b/Makefile.rhelver index 592051d69d66e..bfb6e0d8e8a66 100644 --- a/Makefile.rhelver +++ b/Makefile.rhelver @@ -12,7 +12,7 @@ RHEL_MINOR = 8 # # Use this spot to avoid future merge conflicts. # Do not trim this comment. -RHEL_RELEASE = 687.10.1 +RHEL_RELEASE = 687.12.1 # # ZSTREAM diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index d930416d4c903..da0de34d2e5ca 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -187,7 +187,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) * is unbound or probed and that userspace can't access its * configuration space while we perform recovery. */ - pci_dev_lock(pdev); + device_lock(&pdev->dev); if (pdev->error_state == pci_channel_io_perm_failure) { ers_res = PCI_ERS_RESULT_DISCONNECT; goto out_unlock; @@ -254,7 +254,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) if (driver->err_handler->resume) driver->err_handler->resume(pdev); out_unlock: - pci_dev_unlock(pdev); + device_unlock(&pdev->dev); zpci_report_status(zdev, "recovery", status_str); return ers_res; diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index dc4fcf3d80913..f05d65446d320 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -1017,6 +1018,9 @@ static void __meminit free_pagetable(struct page *page, int order) unsigned long magic; unsigned int nr_pages = 1 << order; + /* Flush IOMMU paging structure caches before freeing PT page */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); + /* bootmem page has reserved flag */ if (PageReserved(page)) { __ClearPageReserved(page); diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 77dca29d82f61..63cafe9f76c34 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1204,6 +1205,8 @@ static bool try_to_free_pte_page(pte_t *pte) if (!pte_none(pte[i])) return false; + /* Flush IOMMU paging structure caches before freeing PT page */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); free_page((unsigned long)pte); return true; } @@ -1216,6 +1219,8 @@ static bool try_to_free_pmd_page(pmd_t *pmd) if (!pmd_none(pmd[i])) return false; + /* Flush IOMMU paging structure caches before freeing PT page */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); free_page((unsigned long)pmd); return true; } diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index d28d84f7d567d..e7ed6a69e76fd 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -832,6 +833,9 @@ int pud_free_pmd_page(pud_t *pud, unsigned long addr) /* INVLPG to clear all paging-structure caches */ flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1); + /* Flush IOMMU paging structure caches before freeing PT pages */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); + for (i = 0; i < PTRS_PER_PMD; i++) { if (!pmd_none(pmd_sv[i])) { pte = (pte_t *)pmd_page_vaddr(pmd_sv[i]); @@ -865,6 +869,8 @@ int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) /* INVLPG to clear all paging-structure caches */ flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1); + /* Flush IOMMU paging structure caches before freeing PT page */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); free_page((unsigned long)pte); return 1; diff --git a/ciq/ciq_backports/kernel-5.14.0-687.10.1.el9_8.0.1/rebuild.details.txt b/ciq/ciq_backports/kernel-5.14.0-687.10.1.el9_8.0.1/rebuild.details.txt new file mode 100644 index 0000000000000..5f96f7e2ab096 --- /dev/null +++ b/ciq/ciq_backports/kernel-5.14.0-687.10.1.el9_8.0.1/rebuild.details.txt @@ -0,0 +1,17 @@ +Rebuild_History BUILDABLE +Rebuilding Kernel from rpm changelog with Fuzz Limit: 87.50% +Number of commits in upstream range v5.14~1..kernel-mainline: 382157 +Number of commits in rpm: 1 +Number of commits matched with upstream: 0 (0.00%) +Number of commits in upstream but not in rpm: 382157 +Number of commits NOT found in upstream: 1 (100.00%) + +Rebuilding Kernel on Branch rocky9_8_rebuild_kernel-5.14.0-687.10.1.el9_8.0.1 for kernel-5.14.0-687.10.1.el9_8.0.1 +Clean Cherry Picks: 0 (0.00%) +Empty Cherry Picks: 0 (0.00%) +_______________________________ + +__EMPTY COMMITS__________________________ + +__CHANGES NOT IN UPSTREAM________________ +Bump release for rebuild with updated rocky-sb-certs' diff --git a/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/0a8cf165.failed b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/0a8cf165.failed new file mode 100644 index 0000000000000..e332d7f676f7a --- /dev/null +++ b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/0a8cf165.failed @@ -0,0 +1,65 @@ +smb: client: validate the whole DACL before rewriting it in cifsacl + +jira KERNEL-1100 +cve CVE-2026-31709 +Rebuild_History Non-Buildable kernel-5.14.0-687.12.1.el9_8 +commit-author Michael Bommarito +commit 0a8cf165566ba55a39fd0f4de172119dd646d39a +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/0a8cf165.failed + +build_sec_desc() and id_mode_to_cifs_acl() derive a DACL pointer from a +server-supplied dacloffset and then use the incoming ACL to rebuild the +chmod/chown security descriptor. + +The original fix only checked that the struct smb_acl header fits before +reading dacl_ptr->size or dacl_ptr->num_aces. That avoids the immediate +header-field OOB read, but the rewrite helpers still walk ACEs based on +pdacl->num_aces with no structural validation of the incoming DACL body. + +A malicious server can return a truncated DACL that still contains a +header, claims one or more ACEs, and then drive +replace_sids_and_copy_aces() or set_chmod_dacl() past the validated +extent while they compare or copy attacker-controlled ACEs. + +Factor the DACL structural checks into validate_dacl(), extend them to +validate each ACE against the DACL bounds, and use the shared validator +before the chmod/chown rebuild paths. parse_dacl() reuses the same +validator so the read-side parser and write-side rewrite paths agree on +what constitutes a well-formed incoming DACL. + +Fixes: bc3e9dd9d104 ("cifs: Change SIDs in ACEs while transferring file ownership.") + Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Assisted-by: Codex:gpt-5-4 + Signed-off-by: Michael Bommarito + Signed-off-by: Steve French +(cherry picked from commit 0a8cf165566ba55a39fd0f4de172119dd646d39a) + Signed-off-by: Jonathan Maple + +# Conflicts: +# fs/smb/client/cifsacl.c +diff --cc fs/smb/client/cifsacl.c +index 345d788b1cb2,cb4060ba5e31..000000000000 +--- a/fs/smb/client/cifsacl.c ++++ b/fs/smb/client/cifsacl.c +@@@ -799,13 -868,7 +867,17 @@@ static void parse_dacl(struct smb_acl * + if (num_aces > 0) { + umode_t denied_mode = 0; + +++<<<<<<< HEAD + + if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) / + + (offsetof(struct smb_ace, sid) + + + offsetof(struct smb_sid, sub_auth) + sizeof(__le16))) + + return; + + + + ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), + + GFP_KERNEL); +++======= ++ ppace = kmalloc_objs(struct smb_ace *, num_aces); +++>>>>>>> 0a8cf165566b (smb: client: validate the whole DACL before rewriting it in cifsacl) + if (!ppace) + return; + +* Unmerged path fs/smb/client/cifsacl.c diff --git a/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/31e62c2e.failed b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/31e62c2e.failed new file mode 100644 index 0000000000000..d369c8856338e --- /dev/null +++ b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/31e62c2e.failed @@ -0,0 +1,65 @@ +ptrace: slightly saner 'get_dumpable()' logic + +jira KERNEL-1100 +cve CVE-2026-46333 +Rebuild_History Non-Buildable kernel-5.14.0-687.12.1.el9_8 +commit-author Linus Torvalds +commit 31e62c2ebbfdc3fe3dbdf5e02c92a9dc67087a3a +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/31e62c2e.failed + +The 'dumpability' of a task is fundamentally about the memory image of +the task - the concept comes from whether it can core dump or not - and +makes no sense when you don't have an associated mm. + +And almost all users do in fact use it only for the case where the task +has a mm pointer. + +But we have one odd special case: ptrace_may_access() uses 'dumpable' to +check various other things entirely independently of the MM (typically +explicitly using flags like PTRACE_MODE_READ_FSCREDS). Including for +threads that no longer have a VM (and maybe never did, like most kernel +threads). + +It's not what this flag was designed for, but it is what it is. + +The ptrace code does check that the uid/gid matches, so you do have to +be uid-0 to see kernel thread details, but this means that the +traditional "drop capabilities" model doesn't make any difference for +this all. + +Make it all make a *bit* more sense by saying that if you don't have a +MM pointer, we'll use a cached "last dumpability" flag if the thread +ever had a MM (it will be zero for kernel threads since it is never +set), and require a proper CAP_SYS_PTRACE capability to override. + + Reported-by: Qualys Security Advisory + Cc: Oleg Nesterov + Cc: Kees Cook + Signed-off-by: Linus Torvalds +(cherry picked from commit 31e62c2ebbfdc3fe3dbdf5e02c92a9dc67087a3a) + Signed-off-by: Jonathan Maple + +# Conflicts: +# include/linux/sched.h +diff --cc include/linux/sched.h +index 0ecc26623bf8,ee06cba5c6f5..000000000000 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@@ -962,7 -1002,10 +962,14 @@@ struct task_struct + unsigned sched_rt_mutex:1; + #endif + +++<<<<<<< HEAD + + /* Bit to tell LSMs we're in execve(): */ +++======= ++ /* Save user-dumpable when mm goes away */ ++ unsigned user_dumpable:1; ++ ++ /* Bit to tell TOMOYO we're in execve(): */ +++>>>>>>> 31e62c2ebbfd (ptrace: slightly saner 'get_dumpable()' logic) + unsigned in_execve:1; + unsigned in_iowait:1; + #ifndef TIF_RESTORE_SIGMASK +* Unmerged path include/linux/sched.h diff --git a/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/48f6a535.failed b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/48f6a535.failed new file mode 100644 index 0000000000000..5f6c4a7dfeced --- /dev/null +++ b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/48f6a535.failed @@ -0,0 +1,183 @@ +net: skbuff: propagate shared-frag marker through frag-transfer helpers + +jira KERNEL-1100 +cve CVE-2026-46300 +Rebuild_History Non-Buildable kernel-5.14.0-687.12.1.el9_8 +commit-author Hyunwoo Kim +commit 48f6a5356a33dd78e7144ae1faef95ffc990aae0 +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/48f6a535.failed + +Two frag-transfer helpers (__pskb_copy_fclone() and skb_shift()) fail +to propagate the SKBFL_SHARED_FRAG bit in skb_shinfo()->flags when +moving frags from source to destination. __pskb_copy_fclone() defers +the rest of the shinfo metadata to skb_copy_header() after copying +frag descriptors, but that helper only carries over gso_{size,segs, +type} and never touches skb_shinfo()->flags; skb_shift() moves frag +descriptors directly and leaves flags untouched. As a result, the +destination skb keeps a reference to the same externally-owned or +page-cache-backed pages while reporting skb_has_shared_frag() as +false. + +The mismatch is harmful in any in-place writer that uses +skb_has_shared_frag() to decide whether shared pages must be detoured +through skb_cow_data(). ESP input is one such writer (esp4.c, +esp6.c), and a single nft 'dup to ' rule -- or any other +nf_dup_ipv4() / xt_TEE caller -- is enough to land a pskb_copy()'d +skb in esp_input() with the marker stripped, letting an unprivileged +user write into the page cache of a root-owned read-only file via +authencesn-ESN stray writes. + +Set SKBFL_SHARED_FRAG on the destination whenever frag descriptors +were actually moved from the source. skb_copy() and skb_copy_expand() +share skb_copy_header() too but linearize all paged data into freshly +allocated head storage and emerge with nr_frags == 0, so +skb_has_shared_frag() returns false on its own; they need no change. + +The same omission exists in skb_gro_receive() and skb_gro_receive_list(). +The former moves the incoming skb's frag descriptors into the +accumulator's last sub-skb via two paths (a direct frag-move loop and +the head_frag + memcpy path); the latter chains the incoming skb whole +onto p's frag_list. Downstream skb_segment() reads only +skb_shinfo(p)->flags, and skb_segment_list() reuses each sub-skb's +shinfo as the nskb -- both p and lp must carry the marker. + +The same omission also exists in tcp_clone_payload(), which builds an +MTU probe skb by moving frag descriptors from skbs on sk_write_queue +into a freshly allocated nskb. The helper falls into the same family +and warrants the same fix for consistency; no TCP TX-side in-place +writer is currently known to reach a user page through this gap, but +a future consumer depending on the marker would regress silently. + +The same omission exists in skb_segment(): the per-iteration flag +merge takes only head_skb's flag, and the inner switch that rebinds +frag_skb to list_skb on head_skb-frags exhaustion does not fold the +new frag_skb's flag into nskb. Fold frag_skb's flag at both sites +so segments drawing frags from frag_list members carry the marker. + +Fixes: cef401de7be8 ("net: fix possible wrong checksum generation") +Fixes: f4c50a4034e6 ("xfrm: esp: avoid in-place decrypt on shared skb frags") + Suggested-by: Sabrina Dubroca + Suggested-by: Sultan Alsawaf + Suggested-by: Ben Hutchings + Suggested-by: Lin Ma + Suggested-by: Jingguo Tan + Suggested-by: Aaron Esau + Cc: stable@vger.kernel.org + Signed-off-by: Hyunwoo Kim + Tested-by: Rajat Gupta +Link: https://patch.msgid.link/ageeJfJHwgzmKXbh@v4bel + Signed-off-by: Paolo Abeni +(cherry picked from commit 48f6a5356a33dd78e7144ae1faef95ffc990aae0) + Signed-off-by: Jonathan Maple + +# Conflicts: +# net/core/skbuff.c +# net/ipv4/tcp_output.c +diff --cc net/core/skbuff.c +index 799c2e8f770a,44ac121cfccb..000000000000 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@@ -4032,13 -4352,8 +4032,18 @@@ onlymerged + + skb_shinfo(tgt)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; + +++<<<<<<< HEAD + + /* Yak, is it really working this way? Some helper please? */ + + skb->len -= shiftlen; + + skb->data_len -= shiftlen; + + skb->truesize -= shiftlen; + + tgt->len += shiftlen; + + tgt->data_len += shiftlen; + + tgt->truesize += shiftlen; +++======= ++ skb_len_add(skb, -shiftlen); ++ skb_len_add(tgt, shiftlen); +++>>>>>>> 48f6a5356a33 (net: skbuff: propagate shared-frag marker through frag-transfer helpers) + + return shiftlen; + } +diff --cc net/ipv4/tcp_output.c +index 797645369a51,6e4bb411dc04..000000000000 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@@ -2321,6 -2604,73 +2321,76 @@@ static bool tcp_can_coalesce_send_queue + return true; + } + +++<<<<<<< HEAD +++======= ++ static int tcp_clone_payload(struct sock *sk, struct sk_buff *to, ++ int probe_size) ++ { ++ skb_frag_t *lastfrag = NULL, *fragto = skb_shinfo(to)->frags; ++ int i, todo, len = 0, nr_frags = 0; ++ const struct sk_buff *skb; ++ ++ if (!sk_wmem_schedule(sk, to->truesize + probe_size)) ++ return -ENOMEM; ++ ++ skb_queue_walk(&sk->sk_write_queue, skb) { ++ const skb_frag_t *fragfrom = skb_shinfo(skb)->frags; ++ ++ if (skb_headlen(skb)) ++ return -EINVAL; ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, fragfrom++) { ++ if (len >= probe_size) ++ goto commit; ++ todo = min_t(int, skb_frag_size(fragfrom), ++ probe_size - len); ++ len += todo; ++ skb_shinfo(to)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; ++ if (lastfrag && ++ skb_frag_page(fragfrom) == skb_frag_page(lastfrag) && ++ skb_frag_off(fragfrom) == skb_frag_off(lastfrag) + ++ skb_frag_size(lastfrag)) { ++ skb_frag_size_add(lastfrag, todo); ++ continue; ++ } ++ if (unlikely(nr_frags == MAX_SKB_FRAGS)) ++ return -E2BIG; ++ skb_frag_page_copy(fragto, fragfrom); ++ skb_frag_off_copy(fragto, fragfrom); ++ skb_frag_size_set(fragto, todo); ++ nr_frags++; ++ lastfrag = fragto++; ++ } ++ } ++ commit: ++ WARN_ON_ONCE(len != probe_size); ++ for (i = 0; i < nr_frags; i++) ++ skb_frag_ref(to, i); ++ ++ skb_shinfo(to)->nr_frags = nr_frags; ++ to->truesize += probe_size; ++ to->len += probe_size; ++ to->data_len += probe_size; ++ __skb_header_release(to); ++ return 0; ++ } ++ ++ /* tcp_mtu_probe() and tcp_grow_skb() can both eat an skb (src) if ++ * all its payload was moved to another one (dst). ++ * Make sure to transfer tcp_flags, eor, and tstamp. ++ */ ++ static void tcp_eat_one_skb(struct sock *sk, ++ struct sk_buff *dst, ++ struct sk_buff *src) ++ { ++ TCP_SKB_CB(dst)->tcp_flags |= TCP_SKB_CB(src)->tcp_flags; ++ TCP_SKB_CB(dst)->eor = TCP_SKB_CB(src)->eor; ++ tcp_skb_collapse_tstamp(dst, src); ++ tcp_unlink_write_queue(src, sk); ++ tcp_wmem_free_skb(sk, src); ++ } ++ +++>>>>>>> 48f6a5356a33 (net: skbuff: propagate shared-frag marker through frag-transfer helpers) + /* Create a new MTU probe if we are ready. + * MTU probe is regularly attempting to increase the path MTU by + * deliberately sending larger packets. This discovers routing +* Unmerged path net/core/skbuff.c +* Unmerged path net/ipv4/tcp_output.c diff --git a/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/a55a6088.failed b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/a55a6088.failed new file mode 100644 index 0000000000000..c27e30a6d7958 --- /dev/null +++ b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/a55a6088.failed @@ -0,0 +1,69 @@ +smb: client: scope end_of_dacl to CIFS_DEBUG2 use in parse_dacl + +jira KERNEL-1100 +Rebuild_History Non-Buildable kernel-5.14.0-687.12.1.el9_8 +commit-author Michael Bommarito +commit a55a60886e612bedb0e9a402ba0dca544c4c6a51 +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/a55a6088.failed + +After validate_dacl() was factored out in commit 149822e5541c, the +local end_of_dacl in parse_dacl() is only read by the dump_ace() +call under #ifdef CONFIG_CIFS_DEBUG2. With CIFS_DEBUG2 off the +variable is assigned but never used, which gcc -W=1 flags as +-Wunused-but-set-variable. + +Remove the local and compute the end-of-dacl pointer inline at the +single call site inside the existing CIFS_DEBUG2 guard. No +functional change: when CIFS_DEBUG2 is enabled the argument value +is identical to what the removed local carried; when CIFS_DEBUG2 +is disabled the code was already dead. + + Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604220046.tGkRxVtS-lkp@intel.com/ +Fixes: 149822e5541c ("smb: client: validate the whole DACL before rewriting it in cifsacl") + Signed-off-by: Michael Bommarito +Assisted-by: Claude:claude-opus-4-7 + Signed-off-by: Steve French +(cherry picked from commit a55a60886e612bedb0e9a402ba0dca544c4c6a51) + Signed-off-by: Jonathan Maple + +# Conflicts: +# fs/smb/client/cifsacl.c +diff --cc fs/smb/client/cifsacl.c +index 805034cad419,ec5d47779304..000000000000 +--- a/fs/smb/client/cifsacl.c ++++ b/fs/smb/client/cifsacl.c +@@@ -810,25 -872,11 +810,30 @@@ static void parse_dacl(struct smb_acl * + return; + + for (i = 0; i < num_aces; ++i) { + + if (end_of_acl - acl_base < acl_size) + + break; + + + ppace[i] = (struct smb_ace *) (acl_base + acl_size); + + acl_base = (char *)ppace[i]; + + acl_size = offsetof(struct smb_ace, sid) + + + offsetof(struct smb_sid, sub_auth); + + + + if (end_of_acl - acl_base < acl_size || + + ppace[i]->sid.num_subauth == 0 || + + ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || + + (end_of_acl - acl_base < + + acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || + + (le16_to_cpu(ppace[i]->size) < + + acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) + + break; + + #ifdef CONFIG_CIFS_DEBUG2 +++<<<<<<< HEAD + + dump_ace(ppace[i], end_of_acl); +++======= ++ dump_ace(ppace[i], ++ (char *)pdacl + le16_to_cpu(pdacl->size)); +++>>>>>>> a55a60886e61 (smb: client: scope end_of_dacl to CIFS_DEBUG2 use in parse_dacl) + #endif + if (mode_from_special_sid && + ppace[i]->sid.num_subauth >= 3 && +* Unmerged path fs/smb/client/cifsacl.c diff --git a/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/ac1ea219.failed b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/ac1ea219.failed new file mode 100644 index 0000000000000..7451479100f69 --- /dev/null +++ b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/ac1ea219.failed @@ -0,0 +1,73 @@ +mm/page_alloc: clear page->private in free_pages_prepare() + +jira KERNEL-1100 +cve CVE-2026-43303 +Rebuild_History Non-Buildable kernel-5.14.0-687.12.1.el9_8 +commit-author Mikhail Gavrilov +commit ac1ea219590c09572ed5992dc233bbf7bb70fef9 +Empty-Commit: Cherry-Pick Conflicts during history rebuild. +Will be included in final tarball splat. Ref for failed cherry-pick at: +ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/ac1ea219.failed + +Several subsystems (slub, shmem, ttm, etc.) use page->private but don't +clear it before freeing pages. When these pages are later allocated as +high-order pages and split via split_page(), tail pages retain stale +page->private values. + +This causes a use-after-free in the swap subsystem. The swap code uses +page->private to track swap count continuations, assuming freshly +allocated pages have page->private == 0. When stale values are present, +swap_count_continued() incorrectly assumes the continuation list is valid +and iterates over uninitialized page->lru containing LIST_POISON values, +causing a crash: + + KASAN: maybe wild-memory-access in range [0xdead000000000100-0xdead000000000107] + RIP: 0010:__do_sys_swapoff+0x1151/0x1860 + +Fix this by clearing page->private in free_pages_prepare(), ensuring all +freed pages have clean state regardless of previous use. + +Link: https://lkml.kernel.org/r/20260207173615.146159-1-mikhail.v.gavrilov@gmail.com +Fixes: 3b8000ae185c ("mm/vmalloc: huge vmalloc backing pages should be split rather than compound") + Signed-off-by: Mikhail Gavrilov + Suggested-by: Zi Yan + Acked-by: Zi Yan + Acked-by: David Hildenbrand (Arm) + Reviewed-by: Vlastimil Babka + Cc: Brendan Jackman + Cc: Chris Li + Cc: Hugh Dickins + Cc: Johannes Weiner + Cc: Kairui Song + Cc: Matthew Wilcox (Oracle) + Cc: Michal Hocko + Cc: Nicholas Piggin + Cc: Suren Baghdasaryan + Cc: + Signed-off-by: Andrew Morton +(cherry picked from commit ac1ea219590c09572ed5992dc233bbf7bb70fef9) + Signed-off-by: Jonathan Maple + +# Conflicts: +# mm/page_alloc.c +diff --cc mm/page_alloc.c +index 4e8615398f07,77dcec36946f..000000000000 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@@ -1151,9 -1428,11 +1151,14 @@@ static __always_inline bool free_pages_ + } + + page_cpupid_reset_last(page); +++<<<<<<< HEAD + + page->flags &= ~PAGE_FLAGS_CHECK_AT_PREP; +++======= ++ page->flags.f &= ~PAGE_FLAGS_CHECK_AT_PREP; ++ page->private = 0; +++>>>>>>> ac1ea219590c (mm/page_alloc: clear page->private in free_pages_prepare()) + reset_page_owner(page, order); + page_table_check_free(page, order); + - pgalloc_tag_sub(page, 1 << order); + + if (!PageHighMem(page)) { + debug_check_no_locks_freed(page_address(page), +* Unmerged path mm/page_alloc.c diff --git a/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/rebuild.details.txt b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/rebuild.details.txt new file mode 100644 index 0000000000000..dd558e62c6fea --- /dev/null +++ b/ciq/ciq_backports/kernel-5.14.0-687.12.1.el9_8/rebuild.details.txt @@ -0,0 +1,27 @@ +Rebuild_History BUILDABLE +Rebuilding Kernel from rpm changelog with Fuzz Limit: 87.50% +Number of commits in upstream range v5.14~1..kernel-mainline: 382157 +Number of commits in rpm: 66 +Number of commits matched with upstream: 60 (90.91%) +Number of commits in upstream but not in rpm: 382097 +Number of commits NOT found in upstream: 6 (9.09%) + +Rebuilding Kernel on Branch rocky9_8_rebuild_kernel-5.14.0-687.12.1.el9_8 for kernel-5.14.0-687.12.1.el9_8 +Clean Cherry Picks: 49 (81.67%) +Empty Cherry Picks: 5 (8.33%) +_______________________________ + +__EMPTY COMMITS__________________________ +31e62c2ebbfdc3fe3dbdf5e02c92a9dc67087a3a ptrace: slightly saner 'get_dumpable()' logic +48f6a5356a33dd78e7144ae1faef95ffc990aae0 net: skbuff: propagate shared-frag marker through frag-transfer helpers +0a8cf165566ba55a39fd0f4de172119dd646d39a smb: client: validate the whole DACL before rewriting it in cifsacl +a55a60886e612bedb0e9a402ba0dca544c4c6a51 smb: client: scope end_of_dacl to CIFS_DEBUG2 use in parse_dacl +ac1ea219590c09572ed5992dc233bbf7bb70fef9 mm/page_alloc: clear page->private in free_pages_prepare() + +__CHANGES NOT IN UPSTREAM________________ +Replace sbat with Rocky Linux sbat +Change bug tracker URL +Ensure appended release in sbat is removed' +redhat/configs: enable CONFIG_SCLP_OFB for s390x +x86/mm: flush IOMMU before freeing kernel page table pages +iommu/sva: add kernel page table IOTLB flush notification diff --git a/configs/kernel-5.14.0-aarch64-64k-debug.config b/configs/kernel-5.14.0-aarch64-64k-debug.config index ff66d73122e68..db2bae35d0125 100644 --- a/configs/kernel-5.14.0-aarch64-64k-debug.config +++ b/configs/kernel-5.14.0-aarch64-64k-debug.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_CONSTRUCTORS=y CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y diff --git a/configs/kernel-5.14.0-aarch64-64k.config b/configs/kernel-5.14.0-aarch64-64k.config index 3e0e32e47e560..c12f081cb8b61 100644 --- a/configs/kernel-5.14.0-aarch64-64k.config +++ b/configs/kernel-5.14.0-aarch64-64k.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-aarch64-debug.config b/configs/kernel-5.14.0-aarch64-debug.config index 6c118eee6f996..6ed7e0535ff43 100644 --- a/configs/kernel-5.14.0-aarch64-debug.config +++ b/configs/kernel-5.14.0-aarch64-debug.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_CONSTRUCTORS=y CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y diff --git a/configs/kernel-5.14.0-aarch64-rt-64k-debug.config b/configs/kernel-5.14.0-aarch64-rt-64k-debug.config index d553bec5f941a..87ffcfe3b30e6 100644 --- a/configs/kernel-5.14.0-aarch64-rt-64k-debug.config +++ b/configs/kernel-5.14.0-aarch64-rt-64k-debug.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-aarch64-rt-64k.config b/configs/kernel-5.14.0-aarch64-rt-64k.config index 932ff117432e3..f0f18c5e86622 100644 --- a/configs/kernel-5.14.0-aarch64-rt-64k.config +++ b/configs/kernel-5.14.0-aarch64-rt-64k.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-aarch64-rt-debug.config b/configs/kernel-5.14.0-aarch64-rt-debug.config index 86bd4b4537011..9a071bbb700e4 100644 --- a/configs/kernel-5.14.0-aarch64-rt-debug.config +++ b/configs/kernel-5.14.0-aarch64-rt-debug.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-aarch64-rt.config b/configs/kernel-5.14.0-aarch64-rt.config index 5103b85ee7411..c29be4314aba3 100644 --- a/configs/kernel-5.14.0-aarch64-rt.config +++ b/configs/kernel-5.14.0-aarch64-rt.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-aarch64.config b/configs/kernel-5.14.0-aarch64.config index 9056fe89ec4e9..5aecd40acd9a9 100644 --- a/configs/kernel-5.14.0-aarch64.config +++ b/configs/kernel-5.14.0-aarch64.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-ppc64le-debug.config b/configs/kernel-5.14.0-ppc64le-debug.config index e9a38fa963580..7d82e049d3e79 100644 --- a/configs/kernel-5.14.0-ppc64le-debug.config +++ b/configs/kernel-5.14.0-ppc64le-debug.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-ppc64le.config b/configs/kernel-5.14.0-ppc64le.config index 348d7dfdb77f7..191e94a5dbcc8 100644 --- a/configs/kernel-5.14.0-ppc64le.config +++ b/configs/kernel-5.14.0-ppc64le.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-s390x-debug.config b/configs/kernel-5.14.0-s390x-debug.config index 841c13617241f..ca5037b96d697 100644 --- a/configs/kernel-5.14.0-s390x-debug.config +++ b/configs/kernel-5.14.0-s390x-debug.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_CONSTRUCTORS=y CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y @@ -2345,7 +2345,7 @@ CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_HMC_DRV=m -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y CONFIG_S390_UV_UAPI=y CONFIG_S390_TAPE=m diff --git a/configs/kernel-5.14.0-s390x-zfcpdump.config b/configs/kernel-5.14.0-s390x-zfcpdump.config index aef09f4a574fd..17156c03ba9d3 100644 --- a/configs/kernel-5.14.0-s390x-zfcpdump.config +++ b/configs/kernel-5.14.0-s390x-zfcpdump.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y @@ -961,7 +961,7 @@ CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_HMC_DRV=y -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y # CONFIG_S390_UV_UAPI is not set # CONFIG_S390_TAPE is not set # CONFIG_VMCP is not set diff --git a/configs/kernel-5.14.0-s390x.config b/configs/kernel-5.14.0-s390x.config index 5550315f93f5c..19dafa50cbe7a 100644 --- a/configs/kernel-5.14.0-s390x.config +++ b/configs/kernel-5.14.0-s390x.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y @@ -2368,7 +2368,7 @@ CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_HMC_DRV=m -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y CONFIG_S390_UV_UAPI=y CONFIG_S390_TAPE=m diff --git a/configs/kernel-5.14.0-x86_64-debug.config b/configs/kernel-5.14.0-x86_64-debug.config index 9649a672f9d0b..9e1f6dca53c21 100644 --- a/configs/kernel-5.14.0-x86_64-debug.config +++ b/configs/kernel-5.14.0-x86_64-debug.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_CONSTRUCTORS=y CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y diff --git a/configs/kernel-5.14.0-x86_64-rt-debug.config b/configs/kernel-5.14.0-x86_64-rt-debug.config index 796aa556bfebd..8bf9cfb87adcd 100644 --- a/configs/kernel-5.14.0-x86_64-rt-debug.config +++ b/configs/kernel-5.14.0-x86_64-rt-debug.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-x86_64-rt.config b/configs/kernel-5.14.0-x86_64-rt.config index d9d00b46172d7..5cce2ebf65de1 100644 --- a/configs/kernel-5.14.0-x86_64-rt.config +++ b/configs/kernel-5.14.0-x86_64-rt.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-5.14.0-x86_64.config b/configs/kernel-5.14.0-x86_64.config index ea5730fc597a6..127949619ccbf 100644 --- a/configs/kernel-5.14.0-x86_64.config +++ b/configs/kernel-5.14.0-x86_64.config @@ -19,7 +19,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y diff --git a/configs/kernel-s390x-debug-rhel.config b/configs/kernel-s390x-debug-rhel.config index ae5215b78036f..68a946585746e 100644 --- a/configs/kernel-s390x-debug-rhel.config +++ b/configs/kernel-s390x-debug-rhel.config @@ -4740,7 +4740,7 @@ CONFIG_SCHEDSTATS=y CONFIG_SCHED_TOPOLOGY=y CONFIG_SCHED_TRACER=y CONFIG_SCLP_CONSOLE=y -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y CONFIG_SCLP_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_SCLP_VT220_TTY=y diff --git a/configs/kernel-s390x-rhel.config b/configs/kernel-s390x-rhel.config index 4a408b8cddc46..1d45cc8fce8f3 100644 --- a/configs/kernel-s390x-rhel.config +++ b/configs/kernel-s390x-rhel.config @@ -4720,7 +4720,7 @@ CONFIG_SCHEDSTATS=y CONFIG_SCHED_TOPOLOGY=y CONFIG_SCHED_TRACER=y CONFIG_SCLP_CONSOLE=y -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y CONFIG_SCLP_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_SCLP_VT220_TTY=y diff --git a/configs/kernel-s390x-zfcpdump-rhel.config b/configs/kernel-s390x-zfcpdump-rhel.config index f9a8e7c5532ff..9c62c52570b54 100644 --- a/configs/kernel-s390x-zfcpdump-rhel.config +++ b/configs/kernel-s390x-zfcpdump-rhel.config @@ -4738,7 +4738,7 @@ CONFIG_SCHED_STACK_END_CHECK=y CONFIG_SCHED_TOPOLOGY=y CONFIG_SCHED_TRACER=y CONFIG_SCLP_CONSOLE=y -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y CONFIG_SCLP_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_SCLP_VT220_TTY=y diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index ad8af3d70ac04..2e3fa520d6eb1 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -138,12 +139,17 @@ struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1, size_t len_2) { struct asymmetric_key_id *kid; - - kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2, - GFP_KERNEL); + size_t kid_sz; + size_t len; + + if (check_add_overflow(len_1, len_2, &len)) + return ERR_PTR(-EOVERFLOW); + if (check_add_overflow(sizeof(struct asymmetric_key_id), len, &kid_sz)) + return ERR_PTR(-EOVERFLOW); + kid = kmalloc(kid_sz, GFP_KERNEL); if (!kid) return ERR_PTR(-ENOMEM); - kid->len = len_1 + len_2; + kid->len = len; memcpy(kid->data, val_1, len_1); memcpy(kid->data + len_1, val_2, len_2); return kid; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index a7743cc65dcfd..9c60a7c7cbd68 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -2235,12 +2235,13 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) ret = nbd_start_device(nbd); out: - mutex_unlock(&nbd->config_lock); if (!ret) { set_bit(NBD_RT_HAS_CONFIG_REF, &config->runtime_flags); refcount_inc(&nbd->config_refs); nbd_connect_reply(info, nbd->index); } + mutex_unlock(&nbd->config_lock); + nbd_config_put(nbd); if (put_dev) nbd_put(nbd); diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c index 0e07d0523291a..8b91f00b9c31d 100644 --- a/drivers/crypto/tegra/tegra-se-aes.c +++ b/drivers/crypto/tegra/tegra-se-aes.c @@ -4,6 +4,7 @@ * Crypto driver to handle block cipher algorithms using NVIDIA Security Engine. */ +#include #include #include #include @@ -333,7 +334,9 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq) tegra_key_invalidate_reserved(ctx->se, key2_id, ctx->alg); out_finalize: + local_bh_disable(); crypto_finalize_skcipher_request(se->engine, req, ret); + local_bh_enable(); return 0; } @@ -1261,7 +1264,9 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); out_finalize: + local_bh_disable(); crypto_finalize_aead_request(ctx->se->engine, req, ret); + local_bh_enable(); return 0; } @@ -1347,7 +1352,9 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); out_finalize: + local_bh_disable(); crypto_finalize_aead_request(ctx->se->engine, req, ret); + local_bh_enable(); return 0; } @@ -1745,7 +1752,9 @@ static int tegra_cmac_do_one_req(struct crypto_engine *engine, void *areq) if (tegra_key_is_reserved(rctx->key_id)) tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + local_bh_disable(); crypto_finalize_hash_request(se->engine, req, ret); + local_bh_enable(); return 0; } diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c index 42d007b7af45d..90bf34eb35784 100644 --- a/drivers/crypto/tegra/tegra-se-hash.c +++ b/drivers/crypto/tegra/tegra-se-hash.c @@ -4,6 +4,7 @@ * Crypto driver to handle HASH algorithms using NVIDIA Security Engine. */ +#include #include #include #include @@ -543,7 +544,9 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq) } out: + local_bh_disable(); crypto_finalize_hash_request(se->engine, req, ret); + local_bh_enable(); return 0; } diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 83cbd64abf5a4..95ae786e98aab 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -842,11 +842,21 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin) return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); } +/** + * __dpll_pin_change_ntf - notify that the pin has been changed + * @pin: registered pin pointer + * + * Context: caller must hold dpll_lock. Suitable for use inside pin + * callbacks which are already invoked under dpll_lock. + * Return: 0 if succeeds, error code otherwise. + */ int __dpll_pin_change_ntf(struct dpll_pin *pin) { + lockdep_assert_held(&dpll_lock); dpll_pin_notify(pin, DPLL_PIN_CHANGED); return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); } +EXPORT_SYMBOL_GPL(__dpll_pin_change_ntf); /** * dpll_pin_change_ntf - notify that the pin has been changed diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h index dd28b56d27c56..a9cfd55f57fc4 100644 --- a/drivers/dpll/dpll_netlink.h +++ b/drivers/dpll/dpll_netlink.h @@ -11,5 +11,3 @@ int dpll_device_delete_ntf(struct dpll_device *dpll); int dpll_pin_create_ntf(struct dpll_pin *pin); int dpll_pin_delete_ntf(struct dpll_pin *pin); - -int __dpll_pin_change_ntf(struct dpll_pin *pin); diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c index 60bf70f3c2826..179fff5e7d547 100644 --- a/drivers/dpll/zl3073x/core.c +++ b/drivers/dpll/zl3073x/core.c @@ -983,11 +983,7 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls) } /* Add devres action to release DPLL related resources */ - rc = devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev); - if (rc) - goto error; - - return 0; + return devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev); error: zl3073x_dev_dpll_fini(zldev); @@ -1028,6 +1024,7 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev, "Unknown or non-match chip ID: 0x%0x\n", id); } + zldev->chip_id = id; /* Read revision, firmware version and custom config version */ rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision); diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h index 09bca2d0926d5..fd2af3c62a7d5 100644 --- a/drivers/dpll/zl3073x/core.h +++ b/drivers/dpll/zl3073x/core.h @@ -35,6 +35,7 @@ struct zl3073x_dpll; * @dev: pointer to device * @regmap: regmap to access device registers * @multiop_lock: to serialize multiple register operations + * @chip_id: chip ID read from hardware * @ref: array of input references' invariants * @out: array of outs' invariants * @synth: array of synths' invariants @@ -48,6 +49,7 @@ struct zl3073x_dev { struct device *dev; struct regmap *regmap; struct mutex multiop_lock; + u16 chip_id; /* Invariants */ struct zl3073x_ref ref[ZL3073X_NUM_REFS]; @@ -144,6 +146,32 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev, int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel); +/** + * zl3073x_dev_is_ref_phase_comp_32bit - check ref phase comp register size + * @zldev: pointer to zl3073x device + * + * Some chip IDs have a 32-bit wide ref_phase_offset_comp register instead + * of the default 48-bit. + * + * Return: true if the register is 32-bit, false if 48-bit + */ +static inline bool +zl3073x_dev_is_ref_phase_comp_32bit(struct zl3073x_dev *zldev) +{ + switch (zldev->chip_id) { + case 0x0E30: + case 0x0E93: + case 0x0E94: + case 0x0E95: + case 0x0E96: + case 0x0E97: + case 0x1F60: + return true; + default: + return false; + } +} + static inline bool zl3073x_is_n_pin(u8 id) { @@ -301,6 +329,36 @@ u8 zl3073x_dev_out_dpll_get(struct zl3073x_dev *zldev, u8 index) return zl3073x_synth_dpll_get(synth); } +/** + * zl3073x_dev_output_pin_freq_get - get output pin frequency + * @zldev: pointer to zl3073x device + * @id: output pin id + * + * Computes the output pin frequency based on the synth frequency, output + * divisor, and signal format. For N-div formats, N-pin frequency is + * additionally divided by esync_n_period. + * + * Return: frequency of the given output pin in Hz + */ +static inline u32 +zl3073x_dev_output_pin_freq_get(struct zl3073x_dev *zldev, u8 id) +{ + const struct zl3073x_synth *synth; + const struct zl3073x_out *out; + u8 out_id; + u32 freq; + + out_id = zl3073x_output_pin_out_get(id); + out = zl3073x_out_state_get(zldev, out_id); + synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); + freq = zl3073x_synth_freq_get(synth) / out->div; + + if (zl3073x_out_is_ndiv(out) && zl3073x_is_n_pin(id)) + freq /= out->esync_n_period; + + return freq; +} + /** * zl3073x_dev_out_is_diff - check if the given output is differential * @zldev: pointer to zl3073x device diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c index 897ed682dbf9c..8ffbede117c6f 100644 --- a/drivers/dpll/zl3073x/dpll.c +++ b/drivers/dpll/zl3073x/dpll.c @@ -475,8 +475,11 @@ zl3073x_dpll_input_pin_phase_adjust_get(const struct dpll_pin *dpll_pin, ref_id = zl3073x_input_pin_ref_get(pin->id); ref = zl3073x_ref_state_get(zldev, ref_id); - /* Perform sign extension for 48bit signed value */ - phase_comp = sign_extend64(ref->phase_comp, 47); + /* Perform sign extension based on register width */ + if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) + phase_comp = sign_extend64(ref->phase_comp, 31); + else + phase_comp = sign_extend64(ref->phase_comp, 47); /* Reverse two's complement negation applied during set and convert * to 32bit signed int @@ -916,46 +919,9 @@ zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin, struct netlink_ext_ack *extack) { struct zl3073x_dpll *zldpll = dpll_priv; - struct zl3073x_dev *zldev = zldpll->dev; struct zl3073x_dpll_pin *pin = pin_priv; - const struct zl3073x_synth *synth; - const struct zl3073x_out *out; - u32 synth_freq; - u8 out_id; - - out_id = zl3073x_output_pin_out_get(pin->id); - out = zl3073x_out_state_get(zldev, out_id); - - /* Get attached synth frequency */ - synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); - synth_freq = zl3073x_synth_freq_get(synth); - switch (zl3073x_out_signal_format_get(out)) { - case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: - case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: - /* In case of divided format we have to distiguish between - * given output pin type. - * - * For P-pin the resulting frequency is computed as simple - * division of synth frequency and output divisor. - * - * For N-pin we have to divide additionally by divisor stored - * in esync_n_period output mailbox register that is used as - * N-pin divisor for these modes. - */ - *frequency = synth_freq / out->div; - - if (!zl3073x_dpll_is_p_pin(pin)) - *frequency = (u32)*frequency / out->esync_n_period; - - break; - default: - /* In other modes the resulting frequency is computed as - * division of synth frequency and output divisor. - */ - *frequency = synth_freq / out->div; - break; - } + *frequency = zl3073x_dev_output_pin_freq_get(zldpll->dev, pin->id); return 0; } diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h index e8ea7a0e0f071..318f9bb8da3a0 100644 --- a/drivers/dpll/zl3073x/out.h +++ b/drivers/dpll/zl3073x/out.h @@ -79,6 +79,23 @@ static inline bool zl3073x_out_is_enabled(const struct zl3073x_out *out) return !!FIELD_GET(ZL_OUTPUT_CTRL_EN, out->ctrl); } +/** + * zl3073x_out_is_ndiv - check if the given output is in N-div mode + * @out: pointer to out state + * + * Return: true if output is in N-div mode, false otherwise + */ +static inline bool zl3073x_out_is_ndiv(const struct zl3073x_out *out) +{ + switch (zl3073x_out_signal_format_get(out)) { + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: + return true; + default: + return false; + } +} + /** * zl3073x_out_synth_get - get synth connected to given output * @out: pointer to out state diff --git a/drivers/dpll/zl3073x/prop.c b/drivers/dpll/zl3073x/prop.c index ad1f099cbe2b5..8523dc8c226e6 100644 --- a/drivers/dpll/zl3073x/prop.c +++ b/drivers/dpll/zl3073x/prop.c @@ -193,9 +193,10 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, { struct dpll_pin_frequency *ranges; struct zl3073x_pin_props *props; - int i, j, num_freqs, rc; + int i, j, num_freqs = 0, rc; + u64 *freqs = NULL; const char *type; - u64 *freqs; + u32 curr_freq; props = kzalloc(sizeof(*props), GFP_KERNEL); if (!props) @@ -207,6 +208,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, props->dpll_props.capabilities = DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE | DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; + curr_freq = zl3073x_dev_ref_freq_get(zldev, index); } else { u8 out, synth; u32 f; @@ -220,6 +222,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, synth = zl3073x_dev_out_synth_get(zldev, out); f = 2 * zl3073x_dev_synth_freq_get(zldev, synth); props->dpll_props.phase_gran = f ? div_u64(PSEC_PER_SEC, f) : 1; + curr_freq = zl3073x_dev_output_pin_freq_get(zldev, index); } props->dpll_props.phase_range.min = S32_MIN; @@ -230,7 +233,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, /* Get firmware node for the given pin */ rc = zl3073x_prop_pin_fwnode_get(zldev, props, dir, index); if (rc) - return props; /* Return if it does not exist */ + goto skip_fwnode_props; /* Look for label property and store the value as board label */ fwnode_property_read_string(props->fwnode, "label", @@ -264,9 +267,10 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, /* Read supported frequencies property if it is specified */ num_freqs = fwnode_property_count_u64(props->fwnode, "supported-frequencies-hz"); - if (num_freqs <= 0) - /* Return if the property does not exist or number is 0 */ - return props; + if (num_freqs <= 0) { + num_freqs = 0; + goto skip_fwnode_props; + } /* The firmware node specifies list of supported frequencies while * DPLL core pin properties requires list of frequency ranges. @@ -283,19 +287,25 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, "supported-frequencies-hz", freqs, num_freqs); - /* Allocate frequency ranges list and fill it */ - ranges = kcalloc(num_freqs, sizeof(*ranges), GFP_KERNEL); +skip_fwnode_props: + /* Allocate frequency ranges list - extra slot for current frequency */ + ranges = kcalloc(num_freqs + 1, sizeof(*ranges), GFP_KERNEL); if (!ranges) { rc = -ENOMEM; goto err_alloc_ranges; } - /* Convert list of frequencies to list of frequency ranges but - * filter-out frequencies that are not representable by device + /* Start with current frequency at index 0 */ + ranges[0] = (struct dpll_pin_frequency)DPLL_PIN_FREQUENCY(curr_freq); + + /* Add frequencies from firmware node, skipping current frequency + * and filtering out frequencies not representable by device */ - for (i = 0, j = 0; i < num_freqs; i++) { + for (i = 0, j = 1; i < num_freqs; i++) { struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]); + if (freqs[i] == curr_freq) + continue; if (zl3073x_pin_check_freq(zldev, dir, index, freqs[i])) { ranges[j] = freq; j++; diff --git a/drivers/dpll/zl3073x/ref.c b/drivers/dpll/zl3073x/ref.c index aa2de13effa87..6b65e61039999 100644 --- a/drivers/dpll/zl3073x/ref.c +++ b/drivers/dpll/zl3073x/ref.c @@ -121,8 +121,16 @@ int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) return rc; /* Read phase compensation register */ - rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, - &ref->phase_comp); + if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) { + u32 val; + + rc = zl3073x_read_u32(zldev, ZL_REG_REF_PHASE_OFFSET_COMP_32, + &val); + ref->phase_comp = val; + } else { + rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, + &ref->phase_comp); + } if (rc) return rc; @@ -179,9 +187,16 @@ int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, if (!rc && dref->sync_ctrl != ref->sync_ctrl) rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL, ref->sync_ctrl); - if (!rc && dref->phase_comp != ref->phase_comp) - rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, - ref->phase_comp); + if (!rc && dref->phase_comp != ref->phase_comp) { + if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) + rc = zl3073x_write_u32(zldev, + ZL_REG_REF_PHASE_OFFSET_COMP_32, + ref->phase_comp); + else + rc = zl3073x_write_u48(zldev, + ZL_REG_REF_PHASE_OFFSET_COMP, + ref->phase_comp); + } if (rc) return rc; diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h index efc7f59cd9f9c..0d8618f5ce8df 100644 --- a/drivers/dpll/zl3073x/ref.h +++ b/drivers/dpll/zl3073x/ref.h @@ -91,6 +91,8 @@ zl3073x_ref_freq_set(struct zl3073x_ref *ref, u32 freq) ref->freq_base = base; ref->freq_mult = mult; + ref->freq_ratio_m = 1; + ref->freq_ratio_n = 1; return 0; } diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h index d837bee72b178..5573d7188406b 100644 --- a/drivers/dpll/zl3073x/regs.h +++ b/drivers/dpll/zl3073x/regs.h @@ -194,6 +194,7 @@ #define ZL_REF_CONFIG_DIFF_EN BIT(2) #define ZL_REG_REF_PHASE_OFFSET_COMP ZL_REG(10, 0x28, 6) +#define ZL_REG_REF_PHASE_OFFSET_COMP_32 ZL_REG(10, 0x28, 4) #define ZL_REG_REF_SYNC_CTRL ZL_REG(10, 0x2e, 1) #define ZL_REF_SYNC_CTRL_MODE GENMASK(2, 0) diff --git a/drivers/gpu/drm/mgag200/mgag200_bmc.c b/drivers/gpu/drm/mgag200/mgag200_bmc.c index a689c71ff1653..bbdeb791c5b38 100644 --- a/drivers/gpu/drm/mgag200/mgag200_bmc.c +++ b/drivers/gpu/drm/mgag200/mgag200_bmc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include #include #include @@ -12,7 +13,7 @@ void mgag200_bmc_stop_scanout(struct mga_device *mdev) { u8 tmp; - int iter_max; + int ret; /* * 1 - The first step is to inform the BMC of an upcoming mode @@ -42,30 +43,22 @@ void mgag200_bmc_stop_scanout(struct mga_device *mdev) /* * 3a- The third step is to verify if there is an active scan. - * We are waiting for a 0 on remhsyncsts ). + * We are waiting for a 0 on remhsyncsts (). */ - iter_max = 300; - while (!(tmp & 0x1) && iter_max) { - WREG8(DAC_INDEX, MGA1064_SPAREREG); - tmp = RREG8(DAC_DATA); - udelay(1000); - iter_max--; - } + ret = read_poll_timeout(RREG_DAC, tmp, !(tmp & 0x1), + 1000, 300000, false, + MGA1064_SPAREREG); + if (ret == -ETIMEDOUT) + return; /* - * 3b- This step occurs only if the remove is actually + * 3b- This step occurs only if the remote BMC is actually * scanning. We are waiting for the end of the frame which is * a 1 on remvsyncsts (XSPAREREG<1>) */ - if (iter_max) { - iter_max = 300; - while ((tmp & 0x2) && iter_max) { - WREG8(DAC_INDEX, MGA1064_SPAREREG); - tmp = RREG8(DAC_DATA); - udelay(1000); - iter_max--; - } - } + (void)read_poll_timeout(RREG_DAC, tmp, (tmp & 0x2), + 1000, 300000, false, + MGA1064_SPAREREG); } void mgag200_bmc_start_scanout(struct mga_device *mdev) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index f4bf40cd7c88a..a875c4bf8cbe4 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -111,6 +111,12 @@ #define DAC_INDEX 0x3c00 #define DAC_DATA 0x3c0a +#define RREG_DAC(reg) \ + ({ \ + WREG8(DAC_INDEX, reg); \ + RREG8(DAC_DATA); \ + }) \ + #define WREG_DAC(reg, v) \ do { \ WREG8(DAC_INDEX, reg); \ diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 955b39d225244..da6e7410ee34b 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1207,10 +1207,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len) switch (data[0]) { case 0x04: + if (len < 32) { + dev_warn(wacom->pen_input->dev.parent, + "Report 0x04 too short: %zu bytes\n", len); + break; + } wacom_intuos_bt_process_data(wacom, data + i); i += 10; fallthrough; case 0x03: + if (i == 1 && len < 22) { + dev_warn(wacom->pen_input->dev.parent, + "Report 0x03 too short: %zu bytes\n", len); + break; + } wacom_intuos_bt_process_data(wacom, data + i); i += 10; wacom_intuos_bt_process_data(wacom, data + i); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 171d29d2770e3..b6a32c7c4a50f 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -303,9 +303,10 @@ struct i801_priv { /* * If set to true the host controller registers are reserved for - * ACPI AML use. + * ACPI AML use. Needs extra protection by acpi_lock. */ bool acpi_reserved; + struct mutex acpi_lock; }; #define FEATURE_SMBUS_PEC BIT(0) @@ -893,8 +894,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, int hwpec, ret; struct i801_priv *priv = i2c_get_adapdata(adap); - if (priv->acpi_reserved) + mutex_lock(&priv->acpi_lock); + if (priv->acpi_reserved) { + mutex_unlock(&priv->acpi_lock); return -EBUSY; + } pm_runtime_get_sync(&priv->pci_dev->dev); @@ -935,6 +939,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, pm_runtime_mark_last_busy(&priv->pci_dev->dev); pm_runtime_put_autosuspend(&priv->pci_dev->dev); + mutex_unlock(&priv->acpi_lock); return ret; } @@ -1462,7 +1467,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, * further access from the driver itself. This device is now owned * by the system firmware. */ - i2c_lock_bus(&priv->adapter, I2C_LOCK_SEGMENT); + mutex_lock(&priv->acpi_lock); if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) { priv->acpi_reserved = true; @@ -1482,7 +1487,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, else status = acpi_os_write_port(address, (u32)*value, bits); - i2c_unlock_bus(&priv->adapter, I2C_LOCK_SEGMENT); + mutex_unlock(&priv->acpi_lock); return status; } @@ -1542,6 +1547,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->adapter.dev.parent = &dev->dev; acpi_use_parent_companion(&priv->adapter.dev); priv->adapter.retries = 3; + mutex_init(&priv->acpi_lock); priv->pci_dev = dev; priv->features = id->driver_data; diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index 1a51cfd82808d..f2267d22af1f2 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -6,12 +6,21 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include "iommu-priv.h" static DEFINE_MUTEX(iommu_sva_lock); static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev, struct mm_struct *mm); +static int iommu_sva_track_mm(struct mm_struct *mm); +static void iommu_sva_untrack_mm(struct mm_struct *mm); /* Allocate a PASID for the mm within range (inclusive) */ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct device *dev) @@ -136,10 +145,20 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm out: refcount_set(&handle->users, 1); + ret = iommu_sva_track_mm(mm); + if (ret) + goto out_unwind; mutex_unlock(&iommu_sva_lock); handle->dev = dev; return handle; +out_unwind: + iommu_detach_device_pasid(domain, dev, iommu_mm->pasid); + if (--domain->users == 0) { + list_del(&domain->next); + iommu_domain_free(domain); + } + goto out_free_handle; out_free_domain: iommu_domain_free(domain); out_free_handle: @@ -170,6 +189,7 @@ void iommu_sva_unbind_device(struct iommu_sva *handle) return; } + iommu_sva_untrack_mm(domain->mm); iommu_detach_device_pasid(domain, dev, iommu_mm->pasid); if (--domain->users == 0) { list_del(&domain->next); @@ -312,3 +332,127 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev, return domain; } + +/* + * Track mm_structs with active SVA bindings so we can flush IOMMU + * cached translations when kernel page table pages are freed. + */ +struct sva_mm { + struct mm_struct *mm; + struct list_head list; + struct rcu_head rcu; + int refcount; +}; + +static DEFINE_SPINLOCK(sva_mm_lock); +static LIST_HEAD(sva_mm_list); +static atomic_t sva_mm_count = ATOMIC_INIT(0); + +/** + * iommu_sva_track_mm - Start tracking an mm for kernel PT change notification + * @mm: the mm_struct to track + * + * Called when SVA is bound for this mm. If the mm is already tracked, + * increments the refcount. Otherwise allocates a new tracking entry. + * + * Returns 0 on success, -ENOMEM on allocation failure. + */ +static int iommu_sva_track_mm(struct mm_struct *mm) +{ + struct sva_mm *smm; + unsigned long flags; + + spin_lock_irqsave(&sva_mm_lock, flags); + list_for_each_entry(smm, &sva_mm_list, list) { + if (smm->mm == mm) { + smm->refcount++; + spin_unlock_irqrestore(&sva_mm_lock, flags); + return 0; + } + } + spin_unlock_irqrestore(&sva_mm_lock, flags); + + smm = kzalloc(sizeof(*smm), GFP_KERNEL); + if (!smm) + return -ENOMEM; + + smm->mm = mm; + smm->refcount = 1; + + spin_lock_irqsave(&sva_mm_lock, flags); + { + struct sva_mm *existing; + + list_for_each_entry(existing, &sva_mm_list, list) { + if (existing->mm == mm) { + existing->refcount++; + spin_unlock_irqrestore(&sva_mm_lock, flags); + kfree(smm); + return 0; + } + } + } + list_add_rcu(&smm->list, &sva_mm_list); + atomic_inc(&sva_mm_count); + spin_unlock_irqrestore(&sva_mm_lock, flags); + return 0; +} + +/** + * iommu_sva_untrack_mm - Stop tracking an mm for kernel PT change notification + * @mm: the mm_struct to untrack + * + * Called when SVA is unbound for this mm. Decrements the refcount and + * removes the tracking entry when it reaches zero. + */ +static void iommu_sva_untrack_mm(struct mm_struct *mm) +{ + struct sva_mm *smm; + unsigned long flags; + + spin_lock_irqsave(&sva_mm_lock, flags); + list_for_each_entry(smm, &sva_mm_list, list) { + if (smm->mm == mm) { + if (--smm->refcount == 0) { + list_del_rcu(&smm->list); + atomic_dec(&sva_mm_count); + spin_unlock_irqrestore(&sva_mm_lock, flags); + kfree_rcu(smm, rcu); + return; + } + spin_unlock_irqrestore(&sva_mm_lock, flags); + return; + } + } + spin_unlock_irqrestore(&sva_mm_lock, flags); + WARN(1, "iommu_sva_untrack_mm: mm %px not found\n", mm); +} + +/** + * iommu_sva_invalidate_kva_range - Flush IOMMU caches before kernel PT free + * @start: Start of kernel virtual address range + * @end: End of kernel virtual address range + * + * Called from x86 mm code before freeing kernel page table pages. + * Iterates all tracked SVA-bound mm_structs and calls + * mmu_notifier_arch_invalidate_secondary_tlbs() for each, triggering + * IOTLB flushes via the drivers' invalidate_range callbacks. + * + * Fast path: atomic_read() returns 0 when no SVA is active. + */ +void iommu_sva_invalidate_kva_range(unsigned long start, unsigned long end) +{ + struct sva_mm *smm; + + if (!atomic_read(&sva_mm_count)) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(smm, &sva_mm_list, list) { + if (mmget_not_zero(smm->mm)) { + mmu_notifier_arch_invalidate_secondary_tlbs(smm->mm, start, end); + mmput_async(smm->mm); + } + } + rcu_read_unlock(); +} diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index 942cd47eb52da..aeec5b9a1dd5c 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -490,12 +490,20 @@ static int rebalance_children(struct shadow_spine *s, if (le32_to_cpu(n->header.nr_entries) == 1) { struct dm_block *child; + int is_shared; dm_block_t b = value64(n, 0); + r = dm_tm_block_is_shared(info->tm, b, &is_shared); + if (r) + return r; + r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child); if (r) return r; + if (is_shared) + inc_children(info->tm, dm_block_data(child), vt); + memcpy(n, dm_block_data(child), dm_bm_block_size(dm_tm_get_bm(info->tm))); diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c index ac071c5b4ce38..cbd6de027ec0f 100644 --- a/drivers/net/ethernet/intel/ice/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c @@ -1243,6 +1243,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf) return err; } + ice_init_dev_hw(pf); + /* load MSI-X values */ ice_set_min_max_msix(pf); diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 785bf5cc1b25e..94a16872126e6 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1162,8 +1162,6 @@ int ice_init_hw(struct ice_hw *hw) if (status) goto err_unroll_fltr_mgmt_struct; - ice_init_dev_hw(hw->back); - mutex_init(&hw->tnl_lock); ice_init_chk_recipe_reuse_support(hw); diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 0fff87dd31425..900ace62d7450 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1154,6 +1154,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, extack, ICE_DPLL_PIN_TYPE_INPUT); } +/** + * ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change + * @d: pointer to dplls struct + * @changed: the SW pin that was explicitly changed (already notified by dpll core) + * + * SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and + * SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO + * expander, the paired pin's state may also change. Send a change + * notification for the peer pin so userspace consumers monitoring the + * peer via dpll netlink learn about the update. + * + * Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is + * released. Uses __dpll_pin_change_ntf() because dpll_lock is + * still held by the dpll netlink layer. + */ +static void ice_dpll_sw_pin_notify_peer(struct ice_dplls *d, + struct ice_dpll_pin *changed) +{ + struct ice_dpll_pin *peer; + + peer = (changed >= d->sma && changed < d->sma + ICE_DPLL_PIN_SW_NUM) ? + &d->ufl[changed->idx] : &d->sma[changed->idx]; + if (peer->pin) + __dpll_pin_change_ntf(peer->pin); +} + /** * ice_dpll_sma_direction_set - set direction of SMA pin * @p: pointer to a pin @@ -1171,6 +1197,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, enum dpll_pin_direction direction, struct netlink_ext_ack *extack) { + struct ice_dplls *d = &p->pf->dplls; + struct ice_dpll_pin *peer; u8 data; int ret; @@ -1189,8 +1217,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, case ICE_DPLL_PIN_SW_2_IDX: if (direction == DPLL_PIN_DIRECTION_INPUT) { data &= ~ICE_SMA2_DIR_EN; + data |= ICE_SMA2_UFL2_RX_DIS; } else { - data &= ~ICE_SMA2_TX_EN; + data &= ~(ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS); data |= ICE_SMA2_DIR_EN; } break; @@ -1202,6 +1231,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, ret = ice_dpll_pin_state_update(p->pf, p, ICE_DPLL_PIN_TYPE_SOFTWARE, extack); + if (ret) + return ret; + + /* When a direction change activates the paired U.FL pin, enable + * its backing CGU pin so the pin reports as connected. Without + * this the U.FL routing is correct but the CGU pin stays disabled + * and userspace sees the pin as disconnected. Do not disable the + * backing pin when U.FL becomes inactive because the SMA pin may + * still be using it. + */ + peer = &d->ufl[p->idx]; + if (peer->active) { + struct ice_dpll_pin *target; + enum ice_dpll_pin_type type; + + if (peer->output) { + target = peer->output; + type = ICE_DPLL_PIN_TYPE_OUTPUT; + } else { + target = peer->input; + type = ICE_DPLL_PIN_TYPE_INPUT; + } + ret = ice_dpll_pin_enable(&p->pf->hw, target, + d->eec.dpll_idx, type, extack); + if (!ret) + ret = ice_dpll_pin_state_update(p->pf, target, + type, extack); + } return ret; } @@ -1253,6 +1310,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, data &= ~ICE_SMA1_MASK; enable = true; } else if (state == DPLL_PIN_STATE_DISCONNECTED) { + /* Skip if U.FL1 is not active, setting TX_EN + * while DIR_EN is set would also deactivate + * the paired SMA1 output. + */ + if (data & (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN)) { + ret = 0; + goto unlock; + } data |= ICE_SMA1_TX_EN; enable = false; } else { @@ -1267,6 +1332,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, data &= ~ICE_SMA2_UFL2_RX_DIS; enable = true; } else if (state == DPLL_PIN_STATE_DISCONNECTED) { + /* Skip if U.FL2 is not active, setting + * UFL2_RX_DIS could also disable the paired + * SMA2 input. + */ + if (!(data & ICE_SMA2_DIR_EN) || + (data & ICE_SMA2_UFL2_RX_DIS)) { + ret = 0; + goto unlock; + } data |= ICE_SMA2_UFL2_RX_DIS; enable = false; } else { @@ -1296,6 +1370,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, unlock: mutex_unlock(&pf->dplls.lock); + if (!ret) + ice_dpll_sw_pin_notify_peer(&pf->dplls, p); return ret; } @@ -1414,6 +1490,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv, unlock: mutex_unlock(&pf->dplls.lock); + if (!ret) + ice_dpll_sw_pin_notify_peer(&pf->dplls, sma); return ret; } @@ -1609,6 +1687,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv, mutex_lock(&pf->dplls.lock); ret = ice_dpll_sma_direction_set(p, direction, extack); mutex_unlock(&pf->dplls.lock); + if (!ret) + ice_dpll_sw_pin_notify_peer(&pf->dplls, p); return ret; } @@ -1915,7 +1995,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv, d->active_input == p->input->pin)) *phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; else if (d->phase_offset_monitor_period) - *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; + *phase_offset = (p->input && + p->direction == DPLL_PIN_DIRECTION_INPUT ? + p->input->phase_offset : + p->phase_offset) * ICE_DPLL_PHASE_OFFSET_FACTOR; else *phase_offset = 0; mutex_unlock(&pf->dplls.lock); @@ -2614,6 +2697,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) return pci_get_dsn(pf->pdev); } +/** + * ice_dpll_pin_ntf - notify pin change including any SW pin wrappers + * @dplls: pointer to dplls struct + * @pin: the dpll_pin that changed + * + * Send a change notification for @pin and for any registered SMA/U.FL pin + * whose backing CGU input matches @pin. + */ +static void ice_dpll_pin_ntf(struct ice_dplls *dplls, struct dpll_pin *pin) +{ + dpll_pin_change_ntf(pin); + for (int i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) { + if (dplls->sma[i].pin && dplls->sma[i].input && + dplls->sma[i].input->pin == pin) + dpll_pin_change_ntf(dplls->sma[i].pin); + if (dplls->ufl[i].pin && dplls->ufl[i].input && + dplls->ufl[i].input->pin == pin) + dpll_pin_change_ntf(dplls->ufl[i].pin); + } +} + /** * ice_dpll_notify_changes - notify dpll subsystem about changes * @d: pointer do dpll @@ -2622,6 +2726,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) */ static void ice_dpll_notify_changes(struct ice_dpll *d) { + struct ice_dplls *dplls = &d->pf->dplls; bool pin_notified = false; if (d->prev_dpll_state != d->dpll_state) { @@ -2630,17 +2735,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) } if (d->prev_input != d->active_input) { if (d->prev_input) - dpll_pin_change_ntf(d->prev_input); + ice_dpll_pin_ntf(dplls, d->prev_input); d->prev_input = d->active_input; if (d->active_input) { - dpll_pin_change_ntf(d->active_input); + ice_dpll_pin_ntf(dplls, d->active_input); pin_notified = true; } } if (d->prev_phase_offset != d->phase_offset) { d->prev_phase_offset = d->phase_offset; if (!pin_notified && d->active_input) - dpll_pin_change_ntf(d->active_input); + ice_dpll_pin_ntf(dplls, d->active_input); } } @@ -2669,6 +2774,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) /** * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes + * @dplls: pointer to dplls struct * @pins: array of ice_dpll_pin pointers registered within dpll subsystem * @pin_num: number of pins * @phase_offset_ntf_mask: bitmask of pin indexes to notify @@ -2678,15 +2784,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) * * Context: Must be called while pf->dplls.lock is released. */ -static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins, +static void ice_dpll_pins_notify_mask(struct ice_dplls *dplls, + struct ice_dpll_pin *pins, u8 pin_num, u32 phase_offset_ntf_mask) { - int i = 0; - - for (i = 0; i < pin_num; i++) - if (phase_offset_ntf_mask & (1 << i)) - dpll_pin_change_ntf(pins[i].pin); + for (int i = 0; i < pin_num; i++) + if (phase_offset_ntf_mask & BIT(i)) + ice_dpll_pin_ntf(dplls, pins[i].pin); } /** @@ -2862,7 +2967,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work) ice_dpll_notify_changes(de); ice_dpll_notify_changes(dp); if (phase_offset_ntf) - ice_dpll_pins_notify_mask(d->inputs, d->num_inputs, + ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs, phase_offset_ntf); resched: @@ -4019,6 +4124,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) struct ice_dpll_pin *pin; u32 phase_adj_max, caps; int i, ret; + u8 data; if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP) input_idx_offset = ICE_E810_RCLK_PINS_NUM; @@ -4078,6 +4184,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) } ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max); } + + /* Initialize the SMA control register to a known-good default state. + * Without this write the PCA9575 GPIO expander retains its power-on + * default (all outputs high) which makes all SW pins appear inactive. + * Set SMA1 and SMA2 as active inputs, disable U.FL1 output and + * U.FL2 input. + */ + ret = ice_read_sma_ctrl(&pf->hw, &data); + if (ret) + return ret; + data &= ~ICE_ALL_SMA_MASK; + data |= ICE_SMA1_TX_EN | ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS; + ret = ice_write_sma_ctrl(&pf->hw, data); + if (ret) + return ret; + ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE, NULL); if (ret) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b6dbdc3439989..6b1e6eeedacec 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -5339,6 +5339,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) return err; } + ice_init_dev_hw(pf); + adapter = ice_adapter_get(pdev); if (IS_ERR(adapter)) { err = PTR_ERR(adapter); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 3abed53c516fc..78c1d1ecab091 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -1296,12 +1296,10 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup) if (pf->hw.reset_ongoing) return; - if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) { + if (hw->mac_type == ICE_MAC_GENERIC_3K_E825 && + test_bit(ICE_FLAG_DPLL, pf->flags)) { int pin, err; - if (!test_bit(ICE_FLAG_DPLL, pf->flags)) - return; - mutex_lock(&pf->dplls.lock); for (pin = 0; pin < ICE_SYNCE_CLK_NUM; pin++) { enum ice_synce_clk clk_pin; @@ -1314,15 +1312,19 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup) port_num, &active, clk_pin); - if (WARN_ON_ONCE(err)) { - mutex_unlock(&pf->dplls.lock); - return; + if (err) { + dev_err_once(ice_pf_to_dev(pf), + "Failed to read SyncE bypass mux for pin %d, err %d\n", + pin, err); + break; } err = ice_tspll_cfg_synce_ethdiv_e825c(hw, clk_pin); - if (active && WARN_ON_ONCE(err)) { - mutex_unlock(&pf->dplls.lock); - return; + if (active && err) { + dev_err_once(ice_pf_to_dev(pf), + "Failed to configure SyncE ETH divider for pin %d, err %d\n", + pin, err); + break; } } mutex_unlock(&pf->dplls.lock); @@ -1334,9 +1336,12 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup) /* Do not reconfigure E810 or E830 PHY */ return; case ICE_MAC_GENERIC: - case ICE_MAC_GENERIC_3K_E825: ice_ptp_port_phy_restart(ptp_port); return; + case ICE_MAC_GENERIC_3K_E825: + if (linkup) + ice_ptp_port_phy_restart(ptp_port); + return; default: dev_warn(ice_pf_to_dev(pf), "%s: Unknown PHY type\n", __func__); } @@ -2705,7 +2710,7 @@ static bool ice_any_port_has_timestamps(struct ice_pf *pf) bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) { struct ice_hw *hw = &pf->hw; - unsigned int i; + int ret; /* Check software indicator */ switch (pf->ptp.tx_interrupt_mode) { @@ -2726,16 +2731,19 @@ bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) } /* Check hardware indicator */ - for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { - u64 tstamp_ready = 0; - int err; - - err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); - if (err || tstamp_ready) - return true; + ret = ice_check_phy_tx_tstamp_ready(hw); + if (ret < 0) { + dev_dbg(ice_pf_to_dev(pf), "Unable to read PHY Tx timestamp ready bitmap, err %d\n", + ret); + /* Stop triggering IRQs if we're unable to read PHY */ + return false; } - return false; + /* ice_check_phy_tx_tstamp_ready() returns 1 if there are timestamps + * available, 0 if there are no waiting timestamps, and a negative + * value if there was an error (which we checked for above). + */ + return ret > 0; } /** @@ -2819,8 +2827,7 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) { struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; - bool trigger_oicr = false; - unsigned int i; + int ret; if (!pf->ptp.port.tx.has_ready_bitmap) return; @@ -2828,21 +2835,11 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) if (!ice_pf_src_tmr_owned(pf)) return; - for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { - u64 tstamp_ready; - int err; - - err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); - if (!err && tstamp_ready) { - trigger_oicr = true; - break; - } - } - - if (trigger_oicr) { - /* Trigger a software interrupt, to ensure this data - * gets processed. - */ + ret = ice_check_phy_tx_tstamp_ready(hw); + if (ret < 0) { + dev_dbg(dev, "PTP periodic task unable to read PHY timestamp ready bitmap, err %d\n", + ret); + } else if (ret) { dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n"); wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index 61c0a0d93ea89..d362b2bb5f967 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -377,6 +377,31 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay) * The following functions operate on devices with the ETH 56G PHY. */ +/** + * ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization + * @hw: pointer to HW struct + * + * Perform E825C-specific PTP hardware clock initialization steps. + * + * Return: 0 on success, or a negative error value on failure. + */ +static int ice_ptp_init_phc_e825c(struct ice_hw *hw) +{ + int err; + + /* Soft reset all ports, to ensure everything is at a clean state */ + for (int port = 0; port < hw->ptp.num_lports; port++) { + err = ice_ptp_phy_soft_reset_eth56g(hw, port); + if (err) { + ice_debug(hw, ICE_DBG_PTP, "Failed to soft reset port %d, err %d\n", + port, err); + return err; + } + } + + return 0; +} + /** * ice_ptp_get_dest_dev_e825 - get destination PHY for given port number * @hw: pointer to the HW struct @@ -1847,6 +1872,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port) * @ena: enable or disable interrupt * @threshold: interrupt threshold * + * The threshold cannot be 0 while the interrupt is enabled. + * * Configure TX timestamp interrupt for the specified port * * Return: @@ -1858,19 +1885,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold) int err; u32 val; + if (ena && !threshold) + return -EINVAL; + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); if (err) return err; + val &= ~PHY_TS_INT_CONFIG_ENA_M; if (ena) { - val |= PHY_TS_INT_CONFIG_ENA_M; val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M; val |= FIELD_PREP(PHY_TS_INT_CONFIG_THRESHOLD_M, threshold); - } else { - val &= ~PHY_TS_INT_CONFIG_ENA_M; + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, + val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, + "Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", + port, !!ena, threshold); + return err; + } + val |= PHY_TS_INT_CONFIG_ENA_M; + } + + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, + "Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", + port, !!ena, threshold); + return err; + } + + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, + "Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", + port, !!ena, threshold); + return err; } - return ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); + return 0; } /** @@ -2115,6 +2168,35 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port) return 0; } +/** + * ice_check_phy_tx_tstamp_ready_eth56g - Check Tx memory status for all ports + * @hw: pointer to the HW struct + * + * Check the PHY_REG_TX_MEMORY_STATUS for all ports. A set bit indicates + * a waiting timestamp. + * + * Return: 1 if any port has at least one timestamp ready bit set, + * 0 otherwise, and a negative error code if unable to read the bitmap. + */ +static int ice_check_phy_tx_tstamp_ready_eth56g(struct ice_hw *hw) +{ + int port; + + for (port = 0; port < hw->ptp.num_lports; port++) { + u64 tstamp_ready; + int err; + + err = ice_get_phy_tx_tstamp_ready(hw, port, &tstamp_ready); + if (err) + return err; + + if (tstamp_ready) + return 1; + } + + return 0; +} + /** * ice_ptp_read_tx_hwtstamp_status_eth56g - Get TX timestamp status * @hw: pointer to the HW struct @@ -2137,13 +2219,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) *ts_status = 0; for (phy = 0; phy < params->num_phys; phy++) { + u8 port; int err; - err = ice_read_phy_eth56g(hw, phy, PHY_PTP_INT_STATUS, &status); + /* ice_read_phy_eth56g expects a port index, so use the first + * port of the PHY + */ + port = phy * hw->ptp.ports_per_phy; + + err = ice_read_phy_eth56g(hw, port, PHY_PTP_INT_STATUS, &status); if (err) return err; - *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy); + *ts_status |= (status & mask) << port; } ice_debug(hw, ICE_DBG_PTP, "PHY interrupt err: %x\n", *ts_status); @@ -2151,6 +2239,69 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) return 0; } +/** + * ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G + * @hw: pointer to the HW structure + * @port: PHY port number + * + * Trigger a soft reset of the ETH56G PHY by toggling the soft reset + * bit in the PHY global register. The reset sequence consists of: + * 1. Clearing the soft reset bit + * 2. Asserting the soft reset bit + * 3. Clearing the soft reset bit again + * + * Short delays are inserted between each step to allow the hardware + * to settle. This provides a controlled way to reinitialize the PHY + * without requiring a full device reset. + * + * Return: 0 on success, or a negative error code on failure when + * reading or writing the PHY register. + */ +int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port) +{ + u32 global_val; + int err; + + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, &global_val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read PHY_REG_GLOBAL for port %d, err %d\n", + port, err); + return err; + } + + global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; + ice_debug(hw, ICE_DBG_PTP, "Clearing soft reset bit for port %d, val: 0x%x\n", + port, global_val); + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", + port, err); + return err; + } + + usleep_range(5000, 6000); + + global_val |= PHY_REG_GLOBAL_SOFT_RESET_M; + ice_debug(hw, ICE_DBG_PTP, "Set soft reset bit for port %d, val: 0x%x\n", + port, global_val); + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", + port, err); + return err; + } + usleep_range(5000, 6000); + + global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; + ice_debug(hw, ICE_DBG_PTP, "Clear soft reset bit for port %d, val: 0x%x\n", + port, global_val); + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); + if (err) + ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", + port, err); + return err; +} + /** * ice_get_phy_tx_tstamp_ready_eth56g - Read the Tx memory status register * @hw: pointer to the HW struct @@ -4202,6 +4353,35 @@ ice_get_phy_tx_tstamp_ready_e82x(struct ice_hw *hw, u8 quad, u64 *tstamp_ready) return 0; } +/** + * ice_check_phy_tx_tstamp_ready_e82x - Check Tx memory status for all quads + * @hw: pointer to the HW struct + * + * Check the Q_REG_TX_MEMORY_STATUS for all quads. A set bit indicates + * a waiting timestamp. + * + * Return: 1 if any quad has at least one timestamp ready bit set, + * 0 otherwise, and a negative error value if unable to read the bitmap. + */ +static int ice_check_phy_tx_tstamp_ready_e82x(struct ice_hw *hw) +{ + int quad; + + for (quad = 0; quad < ICE_GET_QUAD_NUM(hw->ptp.num_lports); quad++) { + u64 tstamp_ready; + int err; + + err = ice_get_phy_tx_tstamp_ready(hw, quad, &tstamp_ready); + if (err) + return err; + + if (tstamp_ready) + return 1; + } + + return 0; +} + /** * ice_phy_cfg_intr_e82x - Configure TX timestamp interrupt * @hw: pointer to the HW struct @@ -4755,6 +4935,23 @@ ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready) return 0; } +/** + * ice_check_phy_tx_tstamp_ready_e810 - Check Tx memory status register + * @hw: pointer to the HW struct + * + * The E810 devices do not have a Tx memory status register. Note this is + * intentionally different behavior from ice_get_phy_tx_tstamp_ready_e810 + * which always says that all bits are ready. This function is called in cases + * where code will trigger interrupts if timestamps are waiting, and should + * not be called for E810 hardware. + * + * Return: 0. + */ +static int ice_check_phy_tx_tstamp_ready_e810(struct ice_hw *hw) +{ + return 0; +} + /* E810 SMA functions * * The following functions operate specifically on E810 hardware and are used @@ -5009,6 +5206,21 @@ static void ice_get_phy_tx_tstamp_ready_e830(const struct ice_hw *hw, u8 port, *tstamp_ready |= rd32(hw, E830_PRTMAC_TS_TX_MEM_VALID_L); } +/** + * ice_check_phy_tx_tstamp_ready_e830 - Check Tx memory status register + * @hw: pointer to the HW struct + * + * Return: 1 if the device has waiting timestamps, 0 otherwise. + */ +static int ice_check_phy_tx_tstamp_ready_e830(struct ice_hw *hw) +{ + u64 tstamp_ready; + + ice_get_phy_tx_tstamp_ready_e830(hw, 0, &tstamp_ready); + + return !!tstamp_ready; +} + /** * ice_ptp_init_phy_e830 - initialize PHY parameters * @ptp: pointer to the PTP HW struct @@ -5564,7 +5776,7 @@ int ice_ptp_init_phc(struct ice_hw *hw) case ICE_MAC_GENERIC: return ice_ptp_init_phc_e82x(hw); case ICE_MAC_GENERIC_3K_E825: - return 0; + return ice_ptp_init_phc_e825c(hw); default: return -EOPNOTSUPP; } @@ -5601,6 +5813,33 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready) } } +/** + * ice_check_phy_tx_tstamp_ready - Check PHY Tx timestamp memory status + * @hw: pointer to the HW struct + * + * Check the PHY for Tx timestamp memory status on all ports. If you need to + * see individual timestamp status for each index, use + * ice_get_phy_tx_tstamp_ready() instead. + * + * Return: 1 if any port has timestamps available, 0 if there are no timestamps + * available, and a negative error code on failure. + */ +int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw) +{ + switch (hw->mac_type) { + case ICE_MAC_E810: + return ice_check_phy_tx_tstamp_ready_e810(hw); + case ICE_MAC_E830: + return ice_check_phy_tx_tstamp_ready_e830(hw); + case ICE_MAC_GENERIC: + return ice_check_phy_tx_tstamp_ready_e82x(hw); + case ICE_MAC_GENERIC_3K_E825: + return ice_check_phy_tx_tstamp_ready_eth56g(hw); + default: + return -EOPNOTSUPP; + } +} + /** * ice_cgu_get_pin_desc_e823 - get pin description array * @hw: pointer to the hw struct diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index 5896b346e5790..1b58b054f4a5b 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -300,6 +300,7 @@ void ice_ptp_reset_ts_memory(struct ice_hw *hw); int ice_ptp_init_phc(struct ice_hw *hw); void ice_ptp_init_hw(struct ice_hw *hw); int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready); +int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw); int ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port, enum ice_ptp_tmr_cmd configured_cmd); @@ -374,6 +375,7 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset); int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port); int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold); int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port); +int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port); #define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL #define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL @@ -676,6 +678,9 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw) #define ICE_P0_GNSS_PRSNT_N BIT(4) /* ETH56G PHY register addresses */ +#define PHY_REG_GLOBAL 0x0 +#define PHY_REG_GLOBAL_SOFT_RESET_M BIT(11) + /* Timestamp PHY incval registers */ #define PHY_REG_TIMETUS_L 0x8 #define PHY_REG_TIMETUS_U 0xC diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index de9e81ccee664..e53a1e4247cb1 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) ice_vf_ctrl_invalidate_vsi(vf); ice_vf_pre_vsi_rebuild(vf); - ice_vf_rebuild_vsi(vf); + if (ice_vf_rebuild_vsi(vf)) { + dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n", + vf->vf_id); + mutex_unlock(&vf->cfg_lock); + continue; + } ice_vf_post_vsi_rebuild(vf); ice_eswitch_attach_vf(pf, vf); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index c2d98ee6652f3..1d25dc9ebca8b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -153,6 +153,11 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, bphy_err(drvr, "invalid interface index: %u\n", ifevent->ifidx); return; } + if (ifevent->bsscfgidx >= BRCMF_MAX_IFS) { + bphy_err(drvr, "invalid bsscfg index: %u\n", + ifevent->bsscfgidx); + return; + } ifp = drvr->iflist[ifevent->bsscfgidx]; diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index c66cfdb5eb03c..9b3a964edce2d 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1131,6 +1131,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, kfree(payload); } +/* + * The current SCSI handling on the host side does not correctly handle: + * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, + * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. + */ +static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) +{ + switch (opcode) { + case INQUIRY: + case MODE_SENSE: + case MODE_SENSE_10: + return true; + case MAINTENANCE_IN: + case PERSISTENT_RESERVE_IN: + return hv_dev_is_fc(device); + default: + return false; + } +} + static void storvsc_on_io_completion(struct storvsc_device *stor_device, struct vstor_packet *vstor_packet, struct storvsc_cmd_request *request) @@ -1141,22 +1161,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, stor_pkt = &request->vstor_packet; /* - * The current SCSI handling on the host side does - * not correctly handle: - * INQUIRY command with page code parameter set to 0x80 - * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c - * MAINTENANCE_IN is not supported by HyperV FC passthrough - * * Setup srb and scsi status so this won't be fatal. * We do this so we can distinguish truly fatal failues * (srb status == 0x4) and off-line the device in that case. */ - if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || - (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || - (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) || - (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && - hv_dev_is_fc(device))) { + if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { vstor_packet->vm_srb.scsi_status = 0; vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 04423ebe8f766..263b9e4855d47 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -465,7 +465,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, }; struct pnfs_layout_segment *lseg, *next; - set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); + if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) + return !list_empty(&lo->plh_segs); clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) pnfs_clear_lseg_state(lseg, lseg_list); diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 24ceced87cfe8..ec49e7ac9cfa5 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -363,6 +363,25 @@ static const struct inode_operations proc_dir_inode_operations = { .setattr = proc_notify_change, }; +static void pde_set_flags(struct proc_dir_entry *pde) +{ + const struct proc_ops *proc_ops = pde->proc_ops; + + if (!proc_ops) + return; + + if (proc_ops->proc_flags & PROC_ENTRY_PERMANENT) + pde->flags |= PROC_ENTRY_PERMANENT; + if (proc_ops->proc_read_iter) + pde->flags |= PROC_ENTRY_proc_read_iter; +#ifdef CONFIG_COMPAT + if (proc_ops->proc_compat_ioctl) + pde->flags |= PROC_ENTRY_proc_compat_ioctl; +#endif + if (proc_ops->proc_lseek) + pde->flags |= PROC_ENTRY_proc_lseek; +} + /* returns the registered entry, or frees dp and returns NULL on failure */ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, struct proc_dir_entry *dp) @@ -370,6 +389,9 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, if (proc_alloc_inum(&dp->low_ino)) goto out_free_entry; + if (!S_ISDIR(dp->mode)) + pde_set_flags(dp); + write_lock(&proc_subdir_lock); dp->parent = dir; if (pde_subdir_insert(dir, dp) == false) { @@ -558,18 +580,6 @@ struct proc_dir_entry *proc_create_reg(const char *name, umode_t mode, return p; } -static void pde_set_flags(struct proc_dir_entry *pde) -{ - if (pde->proc_ops->proc_flags & PROC_ENTRY_PERMANENT) - pde->flags |= PROC_ENTRY_PERMANENT; - if (pde->proc_ops->proc_read_iter) - pde->flags |= PROC_ENTRY_proc_read_iter; -#ifdef CONFIG_COMPAT - if (pde->proc_ops->proc_compat_ioctl) - pde->flags |= PROC_ENTRY_proc_compat_ioctl; -#endif -} - struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops, void *data) @@ -580,7 +590,6 @@ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, if (!p) return NULL; p->proc_ops = proc_ops; - pde_set_flags(p); return proc_register(parent, p); } EXPORT_SYMBOL(proc_create_data); @@ -631,7 +640,6 @@ struct proc_dir_entry *proc_create_seq_private(const char *name, umode_t mode, p->proc_ops = &proc_seq_ops; p->seq_ops = ops; p->state_size = state_size; - pde_set_flags(p); return proc_register(parent, p); } EXPORT_SYMBOL(proc_create_seq_private); @@ -662,7 +670,6 @@ struct proc_dir_entry *proc_create_single_data(const char *name, umode_t mode, return NULL; p->proc_ops = &proc_single_ops; p->single_show = show; - pde_set_flags(p); return proc_register(parent, p); } EXPORT_SYMBOL(proc_create_single_data); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index f005a3e067e76..32cf53d701fa7 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -487,7 +487,7 @@ static int proc_reg_open(struct inode *inode, struct file *file) typeof_member(struct proc_ops, proc_release) release; struct pde_opener *pdeo; - if (!pde->proc_ops->proc_lseek) + if (!pde_has_proc_lseek(pde)) file->f_mode &= ~FMODE_LSEEK; if (pde_is_permanent(pde)) { diff --git a/fs/proc/internal.h b/fs/proc/internal.h index a2ff84c996c64..e85c531ec1614 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -93,6 +93,11 @@ static inline bool pde_has_proc_compat_ioctl(const struct proc_dir_entry *pde) #endif } +static inline bool pde_has_proc_lseek(const struct proc_dir_entry *pde) +{ + return pde->flags & PROC_ENTRY_proc_lseek; +} + extern struct kmem_cache *proc_dir_entry_cache; void pde_free(struct proc_dir_entry *pde); diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c index 345d788b1cb20..2206506c2e2db 100644 --- a/fs/smb/client/cifsacl.c +++ b/fs/smb/client/cifsacl.c @@ -757,6 +757,77 @@ static void dump_ace(struct smb_ace *pace, char *end_of_acl) } #endif +static int validate_dacl(struct smb_acl *pdacl, char *end_of_acl) +{ + int i, ace_hdr_size, ace_size, min_ace_size; + u16 dacl_size, num_aces; + char *acl_base, *end_of_dacl; + struct smb_ace *pace; + + if (!pdacl) + return 0; + + if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl)) { + cifs_dbg(VFS, "ACL too small to parse DACL\n"); + return -EINVAL; + } + + dacl_size = le16_to_cpu(pdacl->size); + if (dacl_size < sizeof(struct smb_acl) || + end_of_acl < (char *)pdacl + dacl_size) { + cifs_dbg(VFS, "ACL too small to parse DACL\n"); + return -EINVAL; + } + + num_aces = le16_to_cpu(pdacl->num_aces); + if (!num_aces) + return 0; + + ace_hdr_size = offsetof(struct smb_ace, sid) + + offsetof(struct smb_sid, sub_auth); + min_ace_size = ace_hdr_size + sizeof(__le32); + if (num_aces > (dacl_size - sizeof(struct smb_acl)) / min_ace_size) { + cifs_dbg(VFS, "ACL too small to parse DACL\n"); + return -EINVAL; + } + + end_of_dacl = (char *)pdacl + dacl_size; + acl_base = (char *)pdacl; + ace_size = sizeof(struct smb_acl); + + for (i = 0; i < num_aces; ++i) { + if (end_of_dacl - acl_base < ace_size) { + cifs_dbg(VFS, "ACL too small to parse ACE\n"); + return -EINVAL; + } + + pace = (struct smb_ace *)(acl_base + ace_size); + acl_base = (char *)pace; + + if (end_of_dacl - acl_base < ace_hdr_size || + pace->sid.num_subauth == 0 || + pace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) { + cifs_dbg(VFS, "ACL too small to parse ACE\n"); + return -EINVAL; + } + + ace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth; + if (end_of_dacl - acl_base < ace_size || + le16_to_cpu(pace->size) < ace_size) { + cifs_dbg(VFS, "ACL too small to parse ACE\n"); + return -EINVAL; + } + + ace_size = le16_to_cpu(pace->size); + if (end_of_dacl - acl_base < ace_size) { + cifs_dbg(VFS, "ACL too small to parse ACE\n"); + return -EINVAL; + } + } + + return 0; +} + static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, struct smb_sid *pownersid, struct smb_sid *pgrpsid, struct cifs_fattr *fattr, bool mode_from_special_sid) @@ -776,12 +847,8 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, return; } - /* validate that we do not go past end of acl */ - if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) || - end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { - cifs_dbg(VFS, "ACL too small to parse DACL\n"); + if (validate_dacl(pdacl, end_of_acl)) return; - } cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n", le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), @@ -799,38 +866,20 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, if (num_aces > 0) { umode_t denied_mode = 0; - if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) / - (offsetof(struct smb_ace, sid) + - offsetof(struct smb_sid, sub_auth) + sizeof(__le16))) - return; - ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), GFP_KERNEL); if (!ppace) return; for (i = 0; i < num_aces; ++i) { - if (end_of_acl - acl_base < acl_size) - break; - ppace[i] = (struct smb_ace *) (acl_base + acl_size); - acl_base = (char *)ppace[i]; - acl_size = offsetof(struct smb_ace, sid) + - offsetof(struct smb_sid, sub_auth); - - if (end_of_acl - acl_base < acl_size || - ppace[i]->sid.num_subauth == 0 || - ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || - (end_of_acl - acl_base < - acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || - (le16_to_cpu(ppace[i]->size) < - acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) - break; #ifdef CONFIG_CIFS_DEBUG2 - dump_ace(ppace[i], end_of_acl); + dump_ace(ppace[i], + (char *)pdacl + le16_to_cpu(pdacl->size)); #endif if (mode_from_special_sid && + ppace[i]->sid.num_subauth >= 3 && (compare_sids(&(ppace[i]->sid), &sid_unix_NFS_mode) == 0)) { /* @@ -870,6 +919,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, (void *)ppace[i], sizeof(struct smb_ace)); */ + acl_base = (char *)ppace[i]; acl_size = le16_to_cpu(ppace[i]->size); } @@ -1214,6 +1264,17 @@ static int parse_sid(struct smb_sid *psid, char *end_of_acl) return 0; } +static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset) +{ + if (acl_len < sizeof(struct smb_acl)) + return false; + + if (dacloffset < sizeof(struct smb_ntsd)) + return false; + + return dacloffset <= acl_len - sizeof(struct smb_acl); +} + /* Convert CIFS ACL to POSIX form */ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, @@ -1234,7 +1295,6 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, group_sid_ptr = (struct smb_sid *)((char *)pntsd + le32_to_cpu(pntsd->gsidoffset)); dacloffset = le32_to_cpu(pntsd->dacloffset); - dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n", pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), le32_to_cpu(pntsd->gsidoffset), @@ -1265,11 +1325,18 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, return rc; } - if (dacloffset) + if (dacloffset) { + if (!dacl_offset_valid(acl_len, dacloffset)) { + cifs_dbg(VFS, "Server returned illegal DACL offset\n"); + return -EINVAL; + } + + dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr, fattr, get_mode_from_special_sid); - else + } else { cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */ + } return rc; } @@ -1292,11 +1359,15 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd, dacloffset = le32_to_cpu(pntsd->dacloffset); if (dacloffset) { - dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); - if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) { - cifs_dbg(VFS, "Server returned illegal ACL size\n"); + if (!dacl_offset_valid(secdesclen, dacloffset)) { + cifs_dbg(VFS, "Server returned illegal DACL offset\n"); return -EINVAL; } + + dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); + rc = validate_dacl(dacl_ptr, end_of_acl); + if (rc) + return rc; } owner_sid_ptr = (struct smb_sid *)((char *)pntsd + @@ -1668,7 +1739,19 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2); dacloffset = le32_to_cpu(pntsd->dacloffset); if (dacloffset) { + if (!dacl_offset_valid(secdesclen, dacloffset)) { + cifs_dbg(VFS, "Server returned illegal DACL offset\n"); + rc = -EINVAL; + goto id_mode_to_cifs_acl_exit; + } + dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); + rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen); + if (rc) { + kfree(pntsd); + cifs_put_tlink(tlink); + return rc; + } if (mode_from_sid) nsecdesclen += le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace); @@ -1684,7 +1767,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, * descriptor parameters, and security descriptor itself */ nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN); - pnntsd = kmalloc(nsecdesclen, GFP_KERNEL); + pnntsd = kzalloc(nsecdesclen, GFP_KERNEL); if (!pnntsd) { kfree(pntsd); cifs_put_tlink(tlink); @@ -1704,6 +1787,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag); cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc); } +id_mode_to_cifs_acl_exit: cifs_put_tlink(tlink); kfree(pnntsd); diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 21338c06e0262..296a231e8f03f 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -2015,7 +2015,7 @@ int smb3_init_fs_context(struct fs_context *fc) ctx->backupuid_specified = false; /* no backup intent for a user */ ctx->backupgid_specified = false; /* no backup intent for a group */ - ctx->retrans = 1; + ctx->retrans = 0; ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT; ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT; ctx->nonativesocket = 0; diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index fddb55605e0cc..bfcac9036c112 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -1489,6 +1489,7 @@ xfs_attr3_leaf_add_work( struct xfs_attr_leaf_name_local *name_loc; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_mount *mp; + int old_end, new_end; int tmp; int i; @@ -1581,17 +1582,49 @@ xfs_attr3_leaf_add_work( if (be16_to_cpu(entry->nameidx) < ichdr->firstused) ichdr->firstused = be16_to_cpu(entry->nameidx); - ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t) - + xfs_attr3_leaf_hdr_size(leaf)); - tmp = (ichdr->count - 1) * sizeof(xfs_attr_leaf_entry_t) - + xfs_attr3_leaf_hdr_size(leaf); + new_end = ichdr->count * sizeof(struct xfs_attr_leaf_entry) + + xfs_attr3_leaf_hdr_size(leaf); + old_end = new_end - sizeof(struct xfs_attr_leaf_entry); + + ASSERT(ichdr->firstused >= new_end); for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { - if (ichdr->freemap[i].base == tmp) { - ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t); + int diff = 0; + + if (ichdr->freemap[i].base == old_end) { + /* + * This freemap entry starts at the old end of the + * leaf entry array, so we need to adjust its base + * upward to accomodate the larger array. + */ + diff = sizeof(struct xfs_attr_leaf_entry); + } else if (ichdr->freemap[i].size > 0 && + ichdr->freemap[i].base < new_end) { + /* + * This freemap entry starts in the space claimed by + * the new leaf entry. Adjust its base upward to + * reflect that. + */ + diff = new_end - ichdr->freemap[i].base; + } + + if (diff) { + ichdr->freemap[i].base += diff; ichdr->freemap[i].size -= - min_t(uint16_t, ichdr->freemap[i].size, - sizeof(xfs_attr_leaf_entry_t)); + min_t(uint16_t, ichdr->freemap[i].size, diff); + } + + /* + * Don't leave zero-length freemaps with nonzero base lying + * around, because we don't want the code in _remove that + * matches on base address to get confused and create + * overlapping freemaps. If we end up with no freemap entries + * then the next _add will compact the leaf block and + * regenerate the freemaps. + */ + if (ichdr->freemap[i].size == 0 && ichdr->freemap[i].base > 0) { + ichdr->freemap[i].base = 0; + ichdr->holes = 1; } } ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index); diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 8862389ed50af..6961f6e95d451 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -306,6 +306,7 @@ int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin, int dpll_device_change_ntf(struct dpll_device *dpll); +int __dpll_pin_change_ntf(struct dpll_pin *pin); int dpll_pin_change_ntf(struct dpll_pin *pin); int register_dpll_notifier(struct notifier_block *nb); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index c30d12e16473d..cf266c0e4f738 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -1615,6 +1615,7 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm); void iommu_sva_unbind_device(struct iommu_sva *handle); u32 iommu_sva_get_pasid(struct iommu_sva *handle); +void iommu_sva_invalidate_kva_range(unsigned long start, unsigned long end); #else static inline struct iommu_sva * iommu_sva_bind_device(struct device *dev, struct mm_struct *mm) @@ -1630,6 +1631,8 @@ static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle) { return IOMMU_PASID_INVALID; } +static inline void iommu_sva_invalidate_kva_range(unsigned long start, + unsigned long end) {} static inline void mm_pasid_init(struct mm_struct *mm) {} static inline bool mm_valid_pasid(struct mm_struct *mm) { return false; } diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 6f7b89b520d6c..b71392fe84d0d 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -27,6 +27,7 @@ enum { PROC_ENTRY_proc_read_iter = 1U << 1, PROC_ENTRY_proc_compat_ioctl = 1U << 2, + PROC_ENTRY_proc_lseek = 1U << 3, }; struct proc_ops { diff --git a/kernel.sbat b/kernel.sbat index 69e498558aa05..9c9f2d48db162 100644 --- a/kernel.sbat +++ b/kernel.sbat @@ -1,2 +1,2 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md -kernel.rhel,1,Red Hat,kernel-core,5.14.0-687.10.1.el9_8.x86_64,mailto:secalert@redhat.com +kernel.rhel,1,Red Hat,kernel-core,5.14.0-687.12.1.el9_8.x86_64,mailto:secalert@redhat.com diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 4e8615398f074..85587366d39a3 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1152,6 +1152,7 @@ static __always_inline bool free_pages_prepare(struct page *page, page_cpupid_reset_last(page); page->flags &= ~PAGE_FLAGS_CHECK_AT_PREP; + page->private = 0; reset_page_owner(page, order); page_table_check_free(page, order); @@ -2476,7 +2477,7 @@ static void free_unref_page_commit(struct zone *zone, struct per_cpu_pages *pcp, * stops will be drained from vmstat refresh context. */ if (order && order <= PAGE_ALLOC_COSTLY_ORDER) { - free_high = (pcp->free_count >= (batch + pcp->high_min / 2) && + free_high = (pcp->free_count >= batch && (pcp->flags & PCPF_PREV_FREE_HIGH_ORDER) && (!(pcp->flags & PCPF_FREE_HIGH_BATCH) || pcp->count >= batch)); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a758452e49b5f..3756c2a152d22 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7163,6 +7163,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key) if (key->initiator != 0x00 && key->initiator != 0x01) return false; + if (key->enc_size > sizeof(key->val)) + return false; + switch (key->addr.type) { case BDADDR_LE_PUBLIC: return true; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 5f6fb2c3611a4..ec3ae5fce5e56 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -298,7 +298,7 @@ static int sco_chan_add(struct sco_conn *conn, struct sock *sk, int err = 0; sco_conn_lock(conn); - if (conn->sk) + if (conn->sk || sco_pi(sk)->conn) err = -EBUSY; else __sco_chan_add(conn, sk, parent); @@ -353,9 +353,20 @@ static int sco_connect(struct sock *sk) lock_sock(sk); + /* Recheck state after reacquiring the socket lock, as another + * thread may have changed it (e.g., closed the socket). + */ + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { + release_sock(sk); + hci_conn_drop(hcon); + err = -EBADFD; + goto unlock; + } + err = sco_chan_add(conn, sk, NULL); if (err) { release_sock(sk); + hci_conn_drop(hcon); goto unlock; } @@ -399,7 +410,7 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) struct sock *sk; sco_conn_lock(conn); - sk = conn->sk; + sk = sco_sock_hold(conn); sco_conn_unlock(conn); if (!sk) @@ -408,11 +419,15 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) BT_DBG("sk %p len %u", sk, skb->len); if (sk->sk_state != BT_CONNECTED) - goto drop; + goto drop_put; - if (!sock_queue_rcv_skb(sk, skb)) + if (!sock_queue_rcv_skb(sk, skb)) { + sock_put(sk); return; + } +drop_put: + sock_put(sk); drop: kfree_skb(skb); } @@ -649,13 +664,18 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen addr->sa_family != AF_BLUETOOTH) return -EINVAL; - if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) + lock_sock(sk); + + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { + release_sock(sk); return -EBADFD; + } - if (sk->sk_type != SOCK_SEQPACKET) - err = -EINVAL; + if (sk->sk_type != SOCK_SEQPACKET) { + release_sock(sk); + return -EINVAL; + } - lock_sock(sk); /* Set destination address and psm */ bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr); release_sock(sk); diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index d704f7ed300c2..da69a27e8332c 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c @@ -22,8 +22,7 @@ eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par) unsigned char eui64[8]; if (!(skb_mac_header(skb) >= skb->head && - skb_mac_header(skb) + ETH_HLEN <= skb->data) && - par->fragoff != 0) { + skb_mac_header(skb) + ETH_HLEN <= skb->data)) { par->hotdrop = true; return false; } diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c index 540d97715bd23..ca103c9461903 100644 --- a/net/netfilter/nf_conntrack_h323_asn1.c +++ b/net/netfilter/nf_conntrack_h323_asn1.c @@ -922,6 +922,8 @@ int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931) break; p++; len--; + if (len <= 0) + break; return DecodeH323_UserInformation(buf, p, len, &q931->UUIE); } diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index b0ac1604600fb..cc44b8f443cb9 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -468,7 +468,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) */ synchronize_rcu(); - nf_ct_expect_iterate_destroy(expect_iter_me, NULL); + nf_ct_expect_iterate_destroy(expect_iter_me, me); nf_ct_iterate_destroy(unhelp, me); } EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 3193d8cada59b..9b55eaa22166c 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -8411,6 +8411,7 @@ static int nf_tables_newflowtable(struct sk_buff *skb, return 0; err_flowtable_hooks: + synchronize_rcu(); nft_trans_destroy(trans); err_flowtable_trans: nft_flowtable_hooks_destroy(&flowtable->hook_list); diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c index 37704ab017992..0d32d4841cb32 100644 --- a/net/netfilter/xt_tcpmss.c +++ b/net/netfilter/xt_tcpmss.c @@ -61,7 +61,7 @@ tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par) return (mssval >= info->mss_min && mssval <= info->mss_max) ^ info->invert; } - if (op[i] < 2) + if (op[i] < 2 || i == optlen - 1) i++; else i += op[i+1] ? : 1; diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 5cc8e407e7911..8ea37c2c3c549 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -603,8 +603,12 @@ TC_INDIRECT_SCOPE int tcf_csum_act(struct sk_buff *skb, protocol = skb->protocol; orig_vlan_tag_present = true; } else { - struct vlan_hdr *vlan = (struct vlan_hdr *)skb->data; + struct vlan_hdr *vlan; + if (!pskb_may_pull(skb, VLAN_HLEN)) + goto drop; + + vlan = (struct vlan_hdr *)skb->data; protocol = vlan->h_vlan_encapsulated_proto; skb_pull(skb, VLAN_HLEN); skb_reset_network_header(skb); diff --git a/redhat/configs/rhel/generic/s390x/CONFIG_SCLP_OFB b/redhat/configs/rhel/generic/s390x/CONFIG_SCLP_OFB index 9861bafbcfd65..62cca9859dd6d 100644 --- a/redhat/configs/rhel/generic/s390x/CONFIG_SCLP_OFB +++ b/redhat/configs/rhel/generic/s390x/CONFIG_SCLP_OFB @@ -1 +1 @@ -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y diff --git a/redhat/kernel.changelog-9.8 b/redhat/kernel.changelog-9.8 index ad84fb3d31e0c..cea231288e0b5 100644 --- a/redhat/kernel.changelog-9.8 +++ b/redhat/kernel.changelog-9.8 @@ -1,3 +1,64 @@ +* Mon May 25 2026 CKI KWF Bot [5.14.0-687.12.1.el9_8] +- dm-thin: fix metadata refcount underflow (Benjamin Marzinski) [RHEL-169626] +- netfilter: xt_tcpmss: check remaining length before reading optlen (CKI Backport Bot) [RHEL-174216] {CVE-2026-43190} +- wifi: brcmfmac: validate bsscfg indices in IF events (CKI Backport Bot) [RHEL-173848] {CVE-2026-43110} +- Bluetooth: SCO: fix race conditions in sco_sock_connect() (CKI Backport Bot) [RHEL-172599] {CVE-2026-43023} +- Bluetooth: MGMT: validate LTK enc_size on load (CKI Backport Bot) [RHEL-172572] {CVE-2026-43020} +- crypto: tegra - Disable softirqs before finalizing request (CKI Backport Bot) [RHEL-170914] +- proc: fix type confusion in pde_set_flags() (Abhi Das) [RHEL-163343] {CVE-2025-38653} +- proc: fix missing pde_set_flags() for net proc files (Abhi Das) [RHEL-163343] {CVE-2025-38653} +- proc: use the same treatment to check proc_lseek as ones for proc_read_iter et.al (CKI Backport Bot) [RHEL-163343] {CVE-2025-38653} +- pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN (Olga Kornievskaia) [RHEL-157470] +Resolves: RHEL-157470, RHEL-163343, RHEL-169626, RHEL-170914, RHEL-172572, RHEL-172599, RHEL-173848, RHEL-174216 + +* Tue May 19 2026 CKI KWF Bot [5.14.0-687.11.1.el9_8] +- mm/page_alloc: clear page->private in free_pages_prepare() (Rafael Aquini) [RHEL-174750] {CVE-2026-43303} +- ice: fix infinite recursion in ice_cfg_tx_topo via ice_init_dev_hw (CKI Backport Bot) [RHEL-175441] +- smb: client: validate dacloffset before building DACL pointers (Paulo Alcantara) [RHEL-172821] +- smb: client: use kzalloc to zero-initialize security descriptor buffer (Paulo Alcantara) [RHEL-172821] +- smb: client: scope end_of_dacl to CIFS_DEBUG2 use in parse_dacl (Paulo Alcantara) [RHEL-172821] +- smb: client: require a full NFS mode SID before reading mode bits (Paulo Alcantara) [RHEL-172821] +- smb: client: validate the whole DACL before rewriting it in cifsacl (Paulo Alcantara) [RHEL-172821] {CVE-2026-31709} +- Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing sock_hold (David Marlin) [RHEL-165063] {CVE-2026-31408} +- xfs: fix freemap adjustments when adding xattrs to leaf blocks (CKI Backport Bot) [RHEL-174058] {CVE-2026-43158} +- xfs: delete attr leaf freemap entries when empty (CKI Backport Bot) [RHEL-174058] {CVE-2026-43158} +- redhat/configs: enable CONFIG_SCLP_OFB for s390x (Jan Polensky) [RHEL-172927] +- HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq (CKI Backport Bot) [RHEL-172740] {CVE-2026-43051} +- netfilter: nf_conntrack_helper: pass helper to expect cleanup (CKI Backport Bot) [RHEL-172620] {CVE-2026-43027} +- s390/pci: Avoid deadlock between PCI error recovery and mlx5 crdump (Ramesh Chhetri) [RHEL-166859] +- ice: add dpll peer notification for paired SMA and U.FL pins (Petr Oros) [RHEL-171829] +- ice: fix missing dpll notifications for SW pins (Petr Oros) [RHEL-171829] +- dpll: export __dpll_pin_change_ntf() for use under dpll_lock (Petr Oros) [RHEL-171829] +- ice: fix SMA and U.FL pin state changes affecting paired pin (Petr Oros) [RHEL-162179] +- ice: fix missing SMA pin initialization in DPLL subsystem (Petr Oros) [RHEL-171832] +- ice: fix NULL pointer dereference in ice_reset_all_vfs() (Petr Oros) [RHEL-172257] +- dpll: zl3073x: Remove redundant cleanup in devm_dpll_init() (CKI Backport Bot) [RHEL-164442] +- dpll: zl3073x: fix REF_PHASE_OFFSET_COMP register width for some chip IDs (CKI Backport Bot) [RHEL-164442] +- dpll: zl3073x: Fix ref frequency setting (CKI Backport Bot) [RHEL-164442] +- dpll: zl3073x: Include current frequency in supported frequencies list (CKI Backport Bot) [RHEL-164442] +- dpll: zl3073x: Add output pin frequency helper (CKI Backport Bot) [RHEL-164442] +- scsi: storvsc: Handle PERSISTENT_RESERVE_IN truncation for Hyper-V vFC (Vitaly Kuznetsov) [RHEL-171378] +- netfilter: ip6t_eui64: reject invalid MAC header for all packets (CKI Backport Bot) [RHEL-171155] {CVE-2026-31685} +- net: sched: act_csum: validate nested VLAN headers (CKI Backport Bot) [RHEL-171138] {CVE-2026-31684} +- cifs: make default value of retrans as zero (Paulo Alcantara) [RHEL-170960] +- ice: fix ice_ptp_read_tx_hwtstamp_status_eth56g (Petr Oros) [RHEL-170701] +- ice: fix ready bitmap check for non-E822 devices (Petr Oros) [RHEL-170701] +- ice: perform PHY soft reset for E825C ports at initialization (Petr Oros) [RHEL-170701] +- ice: fix timestamp interrupt configuration for E825C (Petr Oros) [RHEL-170701] +- drm/mgag200: fix mgag200_bmc_stop_scanout() (Jocelyn Falempe) [RHEL-150179] +- nbd: defer config unlock in nbd_genl_connect (Jeff Moyer) [RHEL-166950] {CVE-2025-68366} +- x86/mm: flush IOMMU before freeing kernel page table pages (Jerry Snitselaar) [RHEL-167100] {CVE-2025-71089} +- iommu/sva: add kernel page table IOTLB flush notification (Jerry Snitselaar) [RHEL-167100] {CVE-2025-71089} +- netfilter: nf_conntrack_h323: check for zero length in DecodeQ931() (CKI Backport Bot) [RHEL-166987] {CVE-2026-23455} +- crypto: asymmetric_keys - prevent overflow in asymmetric_key_generate_id (CKI Backport Bot) [RHEL-166927] {CVE-2025-68724} +- ima: don't clear IMA_DIGSIG flag when setting or removing non-IMA xattr (Bruno Meneguele) [RHEL-169734] {CVE-2025-68183} +- i2c: i801: Revert "i2c: i801: replace acpi_lock with I2C bus lock" (David Arcari) [RHEL-155312] +- ice: fix PTP timestamping broken by SyncE code on E825C (Petr Oros) [RHEL-162182] +- ice: fix missing TX timestamps interrupts on E825 devices (CKI Backport Bot) [RHEL-162185] +- Revert "mm: pcp: increase pcp->free_count threshold to trigger free_high" (Luiz Capitulino) [RHEL-163464] +- netfilter: nf_tables: release flowtable after rcu grace period on error (CKI Backport Bot) [RHEL-160461] {CVE-2026-23392} +Resolves: RHEL-150179, RHEL-155312, RHEL-160461, RHEL-162179, RHEL-162182, RHEL-162185, RHEL-163464, RHEL-164442, RHEL-165063, RHEL-166859, RHEL-166927, RHEL-166950, RHEL-166987, RHEL-167100, RHEL-169734, RHEL-170701, RHEL-170960, RHEL-171138, RHEL-171155, RHEL-171378, RHEL-171829, RHEL-171832, RHEL-172257, RHEL-172620, RHEL-172740, RHEL-172821, RHEL-172927, RHEL-174058, RHEL-174750, RHEL-175441 + * Mon May 18 2026 CKI KWF Bot [5.14.0-687.10.1.el9_8] - net: skbuff: propagate shared-frag marker through frag-transfer helpers (Sabrina Dubroca) [RHEL-176064] {CVE-2026-46300} - net: move skb_gro_receive_list from udp to core (Sabrina Dubroca) [RHEL-176064] {CVE-2026-46300} diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 4d88e03381b77..146268b885061 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -560,6 +560,15 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, return 0; } +/* + * ima_reset_appraise_flags - reset ima_iint_cache flags + * + * @digsig: whether to clear/set IMA_DIGSIG flag, tristate values + * 0: clear IMA_DIGSIG + * 1: set IMA_DIGSIG + * -1: don't change IMA_DIGSIG + * + */ static void ima_reset_appraise_flags(struct inode *inode, int digsig) { struct integrity_iint_cache *iint; @@ -572,9 +581,9 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig) return; iint->measured_pcrs = 0; set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags); - if (digsig) + if (digsig == 1) set_bit(IMA_DIGSIG, &iint->atomic_flags); - else + else if (digsig == 0) clear_bit(IMA_DIGSIG, &iint->atomic_flags); } @@ -653,6 +662,8 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG); } else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) { digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG); + } else { + digsig = -1; } if (result == 1 || evm_revalidate_status(xattr_name)) { result = validate_hash_algo(dentry, xvalue, xattr_value_len); @@ -668,18 +679,20 @@ int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name, struct posix_acl *kacl) { if (evm_revalidate_status(acl_name)) - ima_reset_appraise_flags(d_backing_inode(dentry), 0); + ima_reset_appraise_flags(d_backing_inode(dentry), -1); return 0; } int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) { - int result; + int result, digsig = -1; result = ima_protect_xattr(dentry, xattr_name, NULL, 0); if (result == 1 || evm_revalidate_status(xattr_name)) { - ima_reset_appraise_flags(d_backing_inode(dentry), 0); + if (!strcmp(xattr_name, XATTR_NAME_IMA)) + digsig = 0; + ima_reset_appraise_flags(d_backing_inode(dentry), digsig); if (result == 1) result = 0; }