Recreate RHEL 5.14.0-687.17.1 from CS9/upstream backports

This commit is contained in:
Andrew Lukoshko 2026-06-22 10:34:19 +00:00
parent 018222497a
commit 6e8d3350cc
28 changed files with 3013 additions and 2 deletions

View File

@ -0,0 +1,59 @@
From 2b985d3a024b9e8c24e21671b34e855569763808 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Fri, 10 Apr 2026 09:20:04 +0200
Subject: [PATCH] xen/privcmd: fix double free via VMA splitting
commit 24daca4fc07f3ff8cd0e3f629cd982187f48436a upstream.
privcmd_vm_ops defines .close (privcmd_close), but neither .may_split
nor .open. When userspace does a partial munmap() on a privcmd mapping,
the kernel splits the VMA via __split_vma(). Since may_split is NULL,
the split is allowed. vm_area_dup() copies vm_private_data (a pages
array allocated in alloc_empty_pages()) into the new VMA without any
fixup, because there is no .open callback.
Both VMAs now point to the same pages array. When the unmapped portion
is closed, privcmd_close() calls:
- xen_unmap_domain_gfn_range()
- xen_free_unpopulated_pages()
- kvfree(pages)
The surviving VMA still holds the dangling pointer. When it is later
destroyed, the same sequence runs again, which leads to a double free.
Fix this issue by adding a .may_split callback denying the VMA split.
This is XSA-487 / CVE-2026-31787
Fixes: d71f513985c2 ("xen: privcmd: support autotranslated physmap guests.")
Reported-by: Atharva Vartak <atharva.a.vartak@gmail.com>
Suggested-by: Atharva Vartak <atharva.a.vartak@gmail.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 8d0f4f2..a867792 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -914,6 +914,12 @@ static void privcmd_close(struct vm_area_struct *vma)
kfree(pages);
}
+static int privcmd_may_split(struct vm_area_struct *area, unsigned long addr)
+{
+ /* Forbid splitting, avoids double free via privcmd_close(). */
+ return -EINVAL;
+}
+
static vm_fault_t privcmd_fault(struct vm_fault *vmf)
{
printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
@@ -925,6 +931,7 @@ static vm_fault_t privcmd_fault(struct vm_fault *vmf)
static const struct vm_operations_struct privcmd_vm_ops = {
.close = privcmd_close,
+ .may_split = privcmd_may_split,
.fault = privcmd_fault
};

View File

@ -0,0 +1,60 @@
From 3eefd9e9213a567e4b2121832ee201264486407c Mon Sep 17 00:00:00 2001
From: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
Date: Fri, 1 May 2026 23:14:11 +0000
Subject: [PATCH] Bluetooth: hci_sync: fix stack buffer overflow in
hci_le_big_create_sync
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
JIRA: https://redhat.atlassian.net/browse/RHEL-172859
CVE: CVE-2026-31772
commit bc39a094730ce062fa034a529c93147c096cb488
Author: hkbinbin <hkbinbinbin@gmail.com>
Date: Tue Mar 31 05:39:16 2026 +0000
Bluetooth: hci_sync: fix stack buffer overflow in hci_le_big_create_sync
hci_le_big_create_sync() uses DEFINE_FLEX to allocate a
struct hci_cp_le_big_create_sync on the stack with room for 0x11 (17)
BIS entries. However, conn->num_bis can hold up to HCI_MAX_ISO_BIS (31)
entries — validated against ISO_MAX_NUM_BIS (0x1f) in the caller
hci_conn_big_create_sync(). When conn->num_bis is between 18 and 31,
the memcpy that copies conn->bis into cp->bis writes up to 14 bytes
past the stack buffer, corrupting adjacent stack memory.
This is trivially reproducible: binding an ISO socket with
bc_num_bis = ISO_MAX_NUM_BIS (31) and calling listen() will
eventually trigger hci_le_big_create_sync() from the HCI command
sync worker, causing a KASAN-detectable stack-out-of-bounds write:
BUG: KASAN: stack-out-of-bounds in hci_le_big_create_sync+0x256/0x3b0
Write of size 31 at addr ffffc90000487b48 by task kworker/u9:0/71
Fix this by changing the DEFINE_FLEX count from the incorrect 0x11 to
HCI_MAX_ISO_BIS, which matches the maximum number of BIS entries that
conn->bis can actually carry.
Fixes: 42ecf1947135 ("Bluetooth: ISO: Do not emit LE BIG Create Sync if previous is pending")
Cc: stable@vger.kernel.org
Signed-off-by: hkbinbin <hkbinbinbin@gmail.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index e302afc..b571278 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -7126,7 +7126,8 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)
static int hci_le_big_create_sync(struct hci_dev *hdev, void *data)
{
- DEFINE_FLEX(struct hci_cp_le_big_create_sync, cp, bis, num_bis, 0x11);
+ DEFINE_FLEX(struct hci_cp_le_big_create_sync, cp, bis, num_bis,
+ HCI_MAX_ISO_BIS);
struct hci_conn *conn = data;
struct bt_iso_qos *qos = &conn->iso_qos;
int err;

View File

@ -0,0 +1,77 @@
From 424e95d62110cdbc8fd12b40918f37e408e35a92 Mon Sep 17 00:00:00 2001
From: Oliver Hartkopp <socketcan@hartkopp.net>
Date: Thu, 19 Mar 2026 16:47:45 +0100
Subject: [PATCH] can: isotp: fix tx.buf use-after-free in isotp_sendmsg()
isotp_sendmsg() uses only cmpxchg() on so->tx.state to serialize access
to so->tx.buf. isotp_release() waits for ISOTP_IDLE via
wait_event_interruptible() and then calls kfree(so->tx.buf).
If a signal interrupts the wait_event_interruptible() inside close()
while tx.state is ISOTP_SENDING, the loop exits early and release
proceeds to force ISOTP_SHUTDOWN and continues to kfree(so->tx.buf)
while sendmsg may still be reading so->tx.buf for the final CAN frame
in isotp_fill_dataframe().
The so->tx.buf can be allocated once when the standard tx.buf length needs
to be extended. Move the kfree() of this potentially extended tx.buf to
sk_destruct time when either isotp_sendmsg() and isotp_release() are done.
Fixes: 96d1c81e6a04 ("can: isotp: add module parameter for maximum pdu size")
Cc: stable@vger.kernel.org
Reported-by: Ali Norouzi <ali.norouzi@keysight.com>
Co-developed-by: Ali Norouzi <ali.norouzi@keysight.com>
Signed-off-by: Ali Norouzi <ali.norouzi@keysight.com>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20260319-fix-can-gw-and-can-isotp-v2-2-c45d52c6d2d8@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
diff --git a/net/can/isotp.c b/net/can/isotp.c
index 7363470..311f0af 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -1229,12 +1229,6 @@ static int isotp_release(struct socket *sock)
so->ifindex = 0;
so->bound = 0;
- if (so->rx.buf != so->rx.sbuf)
- kfree(so->rx.buf);
-
- if (so->tx.buf != so->tx.sbuf)
- kfree(so->tx.buf);
-
sock_orphan(sk);
sock->sk = NULL;
@@ -1602,6 +1596,21 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
return NOTIFY_DONE;
}
+static void isotp_sock_destruct(struct sock *sk)
+{
+ struct isotp_sock *so = isotp_sk(sk);
+
+ /* do the standard CAN sock destruct work */
+ can_sock_destruct(sk);
+
+ /* free potential extended PDU buffers */
+ if (so->rx.buf != so->rx.sbuf)
+ kfree(so->rx.buf);
+
+ if (so->tx.buf != so->tx.sbuf)
+ kfree(so->tx.buf);
+}
+
static int isotp_init(struct sock *sk)
{
struct isotp_sock *so = isotp_sk(sk);
@@ -1648,6 +1657,9 @@ static int isotp_init(struct sock *sk)
list_add_tail(&so->notifier, &isotp_notifier_list);
spin_unlock(&isotp_notifier_lock);
+ /* re-assign default can_sock_destruct() reference */
+ sk->sk_destruct = isotp_sock_destruct;
+
return 0;
}

View File

@ -0,0 +1,279 @@
From 781c8893a5da8522ae4ded93e5ef3adbe9559300 Mon Sep 17 00:00:00 2001
From: Ivan Vecera <ivecera@redhat.com>
Date: Tue, 28 Apr 2026 17:49:06 +0200
Subject: [PATCH] dpll: add pin operational state
Add pin-operstate enum and operstate_on_dpll_get callback to report
the actual hardware status of a pin with respect to its parent DPLL
device. Unlike pin-state (which reflects administrative intent set
by the user), operstate reflects what the hardware is actually doing.
Defined operational states:
- active: pin is qualified and actively used by the DPLL
- standby: pin is qualified but not actively used by the DPLL
- no-signal: pin does not have a valid signal
- qual-failed: pin signal failed qualification
The operstate is reported inside the pin-parent-device nested
attribute alongside the existing state and phase-offset attributes.
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Reviewed-by: Petr Oros <poros@redhat.com>
Link: https://patch.msgid.link/20260428154907.2820654-2-ivecera@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst
index 93c191b..37eaef7 100644
--- a/Documentation/driver-api/dpll.rst
+++ b/Documentation/driver-api/dpll.rst
@@ -65,35 +65,43 @@ request, where user provides attributes that result in single pin match.
Pin selection
=============
-In general, selected pin (the one which signal is driving the dpll
-device) can be obtained from ``DPLL_A_PIN_STATE`` attribute, and only
-one pin shall be in ``DPLL_PIN_STATE_CONNECTED`` state for any dpll
-device.
+Pin state (``DPLL_A_PIN_STATE``) reflects the administrative intent set
+by the user. Pin operational state (``DPLL_A_PIN_OPERSTATE``) reflects
+what the hardware is actually doing with the pin.
Pin selection can be done either manually or automatically, depending
on hardware capabilities and active dpll device work mode
(``DPLL_A_MODE`` attribute). The consequence is that there are
-differences for each mode in terms of available pin states, as well as
-for the states the user can request for a dpll device.
+differences for each mode in terms of available pin states the user can
+request for a dpll device.
-In manual mode (``DPLL_MODE_MANUAL``) the user can request or receive
-one of following pin states:
+In manual mode (``DPLL_MODE_MANUAL``) the user can request one of
+following pin states:
-- ``DPLL_PIN_STATE_CONNECTED`` - the pin is used to drive dpll device
-- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not used to drive dpll
+- ``DPLL_PIN_STATE_CONNECTED`` - the pin is selected to drive dpll
device
+- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not selected to drive
+ dpll device
-In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request or
-receive one of following pin states:
+In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request one of
+following pin states:
- ``DPLL_PIN_STATE_SELECTABLE`` - the pin shall be considered as valid
input for automatic selection algorithm
- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as
a valid input for automatic selection algorithm
-In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can only receive
-pin state ``DPLL_PIN_STATE_CONNECTED`` once automatic selection
-algorithm locks a dpll device with one of the inputs.
+The actual hardware status of a pin is reported via the operational
+state (``DPLL_A_PIN_OPERSTATE``) attribute nested under the parent
+device:
+
+- ``DPLL_PIN_OPERSTATE_ACTIVE`` - pin is qualified and actively used
+ by the DPLL
+- ``DPLL_PIN_OPERSTATE_STANDBY`` - pin is qualified but not actively
+ used by the DPLL
+- ``DPLL_PIN_OPERSTATE_NO_SIGNAL`` - pin does not have a valid signal
+- ``DPLL_PIN_OPERSTATE_QUAL_FAILED`` - pin signal failed qualification
+ checks
Shared pins
===========
diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml
index cb5da35..a47d7da 100644
--- a/Documentation/netlink/specs/dpll.yaml
+++ b/Documentation/netlink/specs/dpll.yaml
@@ -212,6 +212,27 @@ definitions:
name: selectable
doc: pin enabled for automatic input selection
render-max: true
+ -
+ type: enum
+ name: pin-operstate
+ doc: |
+ defines possible operational states of a pin with respect to its
+ parent DPLL device, valid values for DPLL_A_PIN_OPERSTATE attribute
+ entries:
+ -
+ name: active
+ doc: pin is qualified and actively used by the DPLL
+ value: 1
+ -
+ name: standby
+ doc: pin is qualified but not actively used by the DPLL
+ -
+ name: no-signal
+ doc: pin does not have a valid signal
+ -
+ name: qual-failed
+ doc: pin signal failed qualification (e.g. frequency or phase monitor)
+ render-max: true
-
type: flags
name: pin-capabilities
@@ -488,6 +509,14 @@ attribute-sets:
Value of (DPLL_A_PIN_MEASURED_FREQUENCY %
DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is a fractional part
of a measured frequency value.
+ -
+ name: operstate
+ type: u32
+ enum: pin-operstate
+ doc: |
+ Operational state of the pin with respect to its parent DPLL
+ device. Unlike state (which reflects the administrative intent),
+ operstate reflects the actual hardware status.
-
name: pin-parent-device
@@ -501,6 +530,8 @@ attribute-sets:
name: prio
-
name: state
+ -
+ name: operstate
-
name: phase-offset
-
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index 0ff1658..ea63602 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -324,6 +324,30 @@ dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin,
return 0;
}
+static int
+dpll_msg_add_pin_operstate(struct sk_buff *msg, struct dpll_pin *pin,
+ struct dpll_pin_ref *ref,
+ struct netlink_ext_ack *extack)
+{
+ const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
+ struct dpll_device *dpll = ref->dpll;
+ enum dpll_pin_operstate operstate;
+ int ret;
+
+ if (!ops->operstate_on_dpll_get)
+ return 0;
+ ret = ops->operstate_on_dpll_get(pin,
+ dpll_pin_on_dpll_priv(dpll, pin),
+ dpll, dpll_priv(dpll),
+ &operstate, extack);
+ if (ret)
+ return ret;
+ if (nla_put_u32(msg, DPLL_A_PIN_OPERSTATE, operstate))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
static int
dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
@@ -650,6 +674,9 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
if (ret)
goto nest_cancel;
ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack);
+ if (ret)
+ goto nest_cancel;
+ ret = dpll_msg_add_pin_operstate(msg, pin, ref, extack);
if (ret)
goto nest_cancel;
ret = dpll_msg_add_pin_prio(msg, pin, ref, extack);
diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c
index da92aa8..6439884 100644
--- a/drivers/dpll/dpll_nl.c
+++ b/drivers/dpll/dpll_nl.c
@@ -11,11 +11,12 @@
#include <uapi/linux/dpll.h>
/* Common nested types */
-const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1] = {
+const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE + 1] = {
[DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, },
[DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
[DPLL_A_PIN_PRIO] = { .type = NLA_U32, },
[DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
+ [DPLL_A_PIN_OPERSTATE] = NLA_POLICY_RANGE(NLA_U32, 1, 4),
[DPLL_A_PIN_PHASE_OFFSET] = { .type = NLA_S64, },
};
diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h
index 3da10cf..8cf3b73 100644
--- a/drivers/dpll/dpll_nl.h
+++ b/drivers/dpll/dpll_nl.h
@@ -12,7 +12,7 @@
#include <uapi/linux/dpll.h>
/* Common nested types */
-extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1];
+extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE + 1];
extern const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1];
extern const struct nla_policy dpll_reference_sync_nl_policy[DPLL_A_PIN_STATE + 1];
diff --git a/include/linux/dpll.h b/include/linux/dpll.h
index 7f8fa58..c5e333a 100644
--- a/include/linux/dpll.h
+++ b/include/linux/dpll.h
@@ -96,6 +96,12 @@ struct dpll_pin_ops {
const struct dpll_device *dpll,
void *dpll_priv, enum dpll_pin_state *state,
struct netlink_ext_ack *extack);
+ int (*operstate_on_dpll_get)(const struct dpll_pin *pin,
+ void *pin_priv,
+ const struct dpll_device *dpll,
+ void *dpll_priv,
+ enum dpll_pin_operstate *operstate,
+ struct netlink_ext_ack *extack);
int (*state_on_pin_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *parent_pin,
void *parent_pin_priv,
diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h
index 93614cc..aa45b79 100644
--- a/include/uapi/linux/dpll.h
+++ b/include/uapi/linux/dpll.h
@@ -177,6 +177,28 @@ enum dpll_pin_state {
DPLL_PIN_STATE_MAX = (__DPLL_PIN_STATE_MAX - 1)
};
+/**
+ * enum dpll_pin_operstate - defines possible operational states of a pin with
+ * respect to its parent DPLL device, valid values for DPLL_A_PIN_OPERSTATE
+ * attribute
+ * @DPLL_PIN_OPERSTATE_ACTIVE: pin is qualified and actively used by the DPLL
+ * @DPLL_PIN_OPERSTATE_STANDBY: pin is qualified but not actively used by the
+ * DPLL
+ * @DPLL_PIN_OPERSTATE_NO_SIGNAL: pin does not have a valid signal
+ * @DPLL_PIN_OPERSTATE_QUAL_FAILED: pin signal failed qualification (e.g.
+ * frequency or phase monitor)
+ */
+enum dpll_pin_operstate {
+ DPLL_PIN_OPERSTATE_ACTIVE = 1,
+ DPLL_PIN_OPERSTATE_STANDBY,
+ DPLL_PIN_OPERSTATE_NO_SIGNAL,
+ DPLL_PIN_OPERSTATE_QUAL_FAILED,
+
+ /* private: */
+ __DPLL_PIN_OPERSTATE_MAX,
+ DPLL_PIN_OPERSTATE_MAX = (__DPLL_PIN_OPERSTATE_MAX - 1)
+};
+
/**
* enum dpll_pin_capabilities - defines possible capabilities of a pin, valid
* flags on DPLL_A_PIN_CAPABILITIES attribute
@@ -256,6 +278,7 @@ enum dpll_a_pin {
DPLL_A_PIN_PHASE_ADJUST_GRAN,
DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT,
DPLL_A_PIN_MEASURED_FREQUENCY,
+ DPLL_A_PIN_OPERSTATE,
__DPLL_A_PIN_MAX,
DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1)

View File

@ -0,0 +1,239 @@
From c53f8f8dce776e032b1a11fb4d9b6e12bb63d958 Mon Sep 17 00:00:00 2001
From: Ivan Vecera <ivecera@redhat.com>
Date: Tue, 28 Apr 2026 17:49:07 +0200
Subject: [PATCH] dpll: zl3073x: implement pin operational state reporting
Implement operstate_on_dpll_get callback for input pins to report
the actual hardware status:
- active: pin is the currently locked reference
- standby: signal is valid but pin is not actively used
- no-signal: reference monitor reports Loss of Signal (LOS)
- qual-failed: reference monitor reports a qualification failure
(SCM, CFM, GST, PFM, eSync or Split-XO)
Separate administrative state (state_on_dpll_get) from operational
state: admin state now reports purely the user-requested intent
(connected in reflock mode, selectable in auto mode).
Switch periodic monitoring to track operstate changes instead of
the mixed admin/oper state that was previously reported.
Add ref_mon_status bit definitions to regs.h.
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Reviewed-by: Petr Oros <poros@redhat.com>
Link: https://patch.msgid.link/20260428154907.2820654-3-ivecera@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 55195dc..2c8bd21 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -38,7 +38,7 @@
* @prio: pin priority <0, 14>
* @esync_control: embedded sync is controllable
* @phase_gran: phase adjustment granularity
- * @pin_state: last saved pin state
+ * @operstate: last saved operational state
* @phase_offset: last saved pin phase offset
* @freq_offset: last saved fractional frequency offset
* @measured_freq: last saved measured frequency
@@ -55,7 +55,7 @@ struct zl3073x_dpll_pin {
u8 prio;
bool esync_control;
s32 phase_gran;
- enum dpll_pin_state pin_state;
+ enum dpll_pin_operstate operstate;
s64 phase_offset;
s64 freq_offset;
u32 measured_freq;
@@ -500,46 +500,41 @@ zl3073x_dpll_input_pin_phase_adjust_set(const struct dpll_pin *dpll_pin,
}
/**
- * zl3073x_dpll_ref_state_get - get status for given input pin
+ * zl3073x_dpll_ref_operstate_get - get operational state for input pin
* @pin: pointer to pin
- * @state: place to store status
+ * @operstate: place to store operational state
*
- * Checks current status for the given input pin and stores the value
- * to @state.
+ * Returns the actual hardware state of the pin: whether it is actively
+ * used by the DPLL, has no signal, failed qualification, or is simply
+ * not in use.
*
* Return: 0 on success, <0 on error
*/
static int
-zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin,
- enum dpll_pin_state *state)
+zl3073x_dpll_ref_operstate_get(struct zl3073x_dpll_pin *pin,
+ enum dpll_pin_operstate *operstate)
{
struct zl3073x_dpll *zldpll = pin->dpll;
struct zl3073x_dev *zldev = zldpll->dev;
- const struct zl3073x_chan *chan;
- u8 ref;
-
- chan = zl3073x_chan_state_get(zldev, zldpll->id);
- ref = zl3073x_input_pin_ref_get(pin->id);
+ const struct zl3073x_ref *ref;
+ u8 ref_id;
- /* Check if the pin reference is connected */
- if (ref == zl3073x_dpll_connected_ref_get(zldpll)) {
- *state = DPLL_PIN_STATE_CONNECTED;
- return 0;
- }
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
- /* If the DPLL is running in automatic mode and the reference is
- * selectable and its monitor does not report any error then report
- * pin as selectable.
- */
- if (zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_AUTO &&
- zl3073x_dev_ref_is_status_ok(zldev, ref) &&
- zl3073x_chan_ref_is_selectable(chan, ref)) {
- *state = DPLL_PIN_STATE_SELECTABLE;
+ /* Check if this pin is the currently locked reference */
+ if (ref_id == zl3073x_dpll_connected_ref_get(zldpll)) {
+ *operstate = DPLL_PIN_OPERSTATE_ACTIVE;
return 0;
}
- /* Otherwise report the pin as disconnected */
- *state = DPLL_PIN_STATE_DISCONNECTED;
+ /* Check reference monitor status */
+ ref = zl3073x_ref_state_get(zldev, ref_id);
+ if (ref->mon_status & ZL_REF_MON_STATUS_LOS)
+ *operstate = DPLL_PIN_OPERSTATE_NO_SIGNAL;
+ else if (!zl3073x_ref_is_status_ok(ref))
+ *operstate = DPLL_PIN_OPERSTATE_QUAL_FAILED;
+ else
+ *operstate = DPLL_PIN_OPERSTATE_STANDBY;
return 0;
}
@@ -551,10 +546,48 @@ zl3073x_dpll_input_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin,
void *dpll_priv,
enum dpll_pin_state *state,
struct netlink_ext_ack *extack)
+{
+ struct zl3073x_dpll *zldpll = dpll_priv;
+ struct zl3073x_dpll_pin *pin = pin_priv;
+ const struct zl3073x_chan *chan;
+ u8 mode, ref;
+
+ chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id);
+ ref = zl3073x_input_pin_ref_get(pin->id);
+ mode = zl3073x_chan_mode_get(chan);
+
+ switch (mode) {
+ case ZL_DPLL_MODE_REFSEL_MODE_REFLOCK:
+ if (ref == zl3073x_chan_ref_get(chan))
+ *state = DPLL_PIN_STATE_CONNECTED;
+ else
+ *state = DPLL_PIN_STATE_DISCONNECTED;
+ break;
+ case ZL_DPLL_MODE_REFSEL_MODE_AUTO:
+ if (zl3073x_chan_ref_is_selectable(chan, ref))
+ *state = DPLL_PIN_STATE_SELECTABLE;
+ else
+ *state = DPLL_PIN_STATE_DISCONNECTED;
+ break;
+ default:
+ *state = DPLL_PIN_STATE_DISCONNECTED;
+ break;
+ }
+
+ return 0;
+}
+
+static int
+zl3073x_dpll_input_pin_operstate_on_dpll_get(const struct dpll_pin *dpll_pin,
+ void *pin_priv,
+ const struct dpll_device *dpll,
+ void *dpll_priv,
+ enum dpll_pin_operstate *operstate,
+ struct netlink_ext_ack *extack)
{
struct zl3073x_dpll_pin *pin = pin_priv;
- return zl3073x_dpll_ref_state_get(pin, state);
+ return zl3073x_dpll_ref_operstate_get(pin, operstate);
}
static int
@@ -1248,6 +1281,7 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
.frequency_get = zl3073x_dpll_input_pin_frequency_get,
.frequency_set = zl3073x_dpll_input_pin_frequency_set,
.measured_freq_get = zl3073x_dpll_input_pin_measured_freq_get,
+ .operstate_on_dpll_get = zl3073x_dpll_input_pin_operstate_on_dpll_get,
.phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get,
.phase_adjust_get = zl3073x_dpll_input_pin_phase_adjust_get,
.phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set,
@@ -1663,7 +1697,7 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)
* 2) For other pins use appropriate ref_phase register if the phase
* monitor feature is enabled.
*/
- if (pin->pin_state == DPLL_PIN_STATE_CONNECTED)
+ if (pin->operstate == DPLL_PIN_OPERSTATE_ACTIVE)
reg = ZL_REG_DPLL_PHASE_ERR_DATA(zldpll->id);
else if (zldpll->phase_monitor)
reg = ZL_REG_REF_PHASE(ref_id);
@@ -1828,7 +1862,7 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
}
list_for_each_entry(pin, &zldpll->pins, list) {
- enum dpll_pin_state state;
+ enum dpll_pin_operstate operstate;
bool pin_changed = false;
/* Output pins change checks are not necessary because output
@@ -1837,18 +1871,18 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
if (!zl3073x_dpll_is_input_pin(pin))
continue;
- rc = zl3073x_dpll_ref_state_get(pin, &state);
+ rc = zl3073x_dpll_ref_operstate_get(pin, &operstate);
if (rc) {
dev_err(dev,
- "Failed to get %s on DPLL%u state: %pe\n",
+ "Failed to get %s on DPLL%u oper state: %pe\n",
pin->label, zldpll->id, ERR_PTR(rc));
return;
}
- if (state != pin->pin_state) {
- dev_dbg(dev, "%s state changed: %u->%u\n", pin->label,
- pin->pin_state, state);
- pin->pin_state = state;
+ if (operstate != pin->operstate) {
+ dev_dbg(dev, "%s oper state changed: %u->%u\n",
+ pin->label, pin->operstate, operstate);
+ pin->operstate = operstate;
pin_changed = true;
}
diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h
index d425dc6..8015808 100644
--- a/drivers/dpll/zl3073x/regs.h
+++ b/drivers/dpll/zl3073x/regs.h
@@ -98,7 +98,14 @@
#define ZL_REG_REF_MON_STATUS(_idx) \
ZL_REG_IDX(_idx, 2, 0x02, 1, ZL3073X_NUM_REFS, 1)
-#define ZL_REF_MON_STATUS_OK 0 /* all bits zeroed */
+#define ZL_REF_MON_STATUS_OK 0
+#define ZL_REF_MON_STATUS_LOS BIT(0)
+#define ZL_REF_MON_STATUS_SCM BIT(1)
+#define ZL_REF_MON_STATUS_CFM BIT(2)
+#define ZL_REF_MON_STATUS_GST BIT(3)
+#define ZL_REF_MON_STATUS_PFM BIT(4)
+#define ZL_REF_MON_STATUS_ESYNC BIT(6)
+#define ZL_REF_MON_STATUS_SPLIT_XO BIT(7)
#define ZL_REG_DPLL_MON_STATUS(_idx) \
ZL_REG_IDX(_idx, 2, 0x10, 1, ZL3073X_MAX_CHANNELS, 1)

View File

@ -0,0 +1,354 @@
From 9c11fcb2e9a54d0f1467380831e2e4bb68f7498d Mon Sep 17 00:00:00 2001
From: Ivan Vecera <ivecera@redhat.com>
Date: Mon, 11 May 2026 17:58:15 +0200
Subject: [PATCH] dpll: add fractional frequency offset to pin-parent-device
Add both fractional-frequency-offset (PPM) and
fractional-frequency-offset-ppt (PPT) attributes to the
pin-parent-device nested attribute set, alongside the existing
top-level pin attributes. Both carry the same measurement at
different precisions.
Introduce enum dpll_ffo_type and struct dpll_ffo_param to
distinguish FFO contexts: DPLL_FFO_PORT_RXTX_RATE for the RX vs
TX symbol rate offset reported at the top level, and
DPLL_FFO_PIN_DEVICE for the pin vs parent DPLL offset reported
in the pin-parent-device nest.
Add a supported_ffo bitmask to struct dpll_pin_ops so drivers
declare which FFO types they support. The core only calls ffo_get
for types the driver has opted into, eliminating the need for
per-driver NULL pointer guards. Validate at pin registration time
that supported_ffo is not set without an ffo_get callback.
Update mlx5 (DPLL_FFO_PORT_RXTX_RATE) and zl3073x
(DPLL_FFO_PORT_RXTX_RATE) drivers to use the new API.
Add documentation for both FFO types to dpll.rst.
Changes v3 -> v4:
- Replace dpll=NULL overloading with enum dpll_ffo_type and
struct dpll_ffo_param (Jakub Kicinski)
- Add supported_ffo opt-in bitmask in dpll_pin_ops for fail-close
driver validation (Jakub Kicinski)
- Add WARN_ON in dpll_pin_register for supported_ffo without
ffo_get callback
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Link: https://patch.msgid.link/20260511155816.99936-2-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst
index 37eaef7..bae1476 100644
--- a/Documentation/driver-api/dpll.rst
+++ b/Documentation/driver-api/dpll.rst
@@ -258,6 +258,26 @@ in the ``DPLL_A_PIN_PHASE_OFFSET`` attribute.
``DPLL_A_PHASE_OFFSET_MONITOR`` attr state of a feature
=============================== ========================
+Fractional frequency offset
+===========================
+
+The fractional frequency offset (FFO) is reported through two attributes
+that carry the same measurement at different precisions:
+
+- ``DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET`` in PPM (parts per million)
+- ``DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT`` in PPT (parts per trillion)
+
+Both attributes appear at the top level of a pin and inside each
+``pin-parent-device`` nest. Two FFO types are defined:
+
+- ``DPLL_FFO_PORT_RXTX_RATE`` - RX vs TX symbol rate offset (top-level)
+- ``DPLL_FFO_PIN_DEVICE`` - pin vs parent DPLL offset (per-parent)
+
+The driver declares which types it supports via the ``supported_ffo``
+bitmask in ``struct dpll_pin_ops``. The core only calls the ``ffo_get``
+callback for types the driver has opted into. The requested type is
+passed to the driver in the ``struct dpll_ffo_param``.
+
Frequency monitor
=================
diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml
index a47d7da..4ba8adc 100644
--- a/Documentation/netlink/specs/dpll.yaml
+++ b/Documentation/netlink/specs/dpll.yaml
@@ -448,12 +448,14 @@ attribute-sets:
name: fractional-frequency-offset
type: sint
doc: |
- The FFO (Fractional Frequency Offset) between the RX and TX
- symbol rate on the media associated with the pin:
- (rx_frequency-tx_frequency)/rx_frequency
+ The FFO (Fractional Frequency Offset) of the pin.
+ At top level this represents the RX vs TX symbol rate
+ offset on the media associated with the pin. Inside
+ the pin-parent-device nest it represents the frequency
+ offset between the pin and its parent DPLL device.
Value is in PPM (parts per million).
- This may be implemented for example for pin of type
- PIN_TYPE_SYNCE_ETH_PORT.
+ This is a lower-precision version of
+ fractional-frequency-offset-ppt.
-
name: esync-frequency
type: u64
@@ -492,12 +494,14 @@ attribute-sets:
name: fractional-frequency-offset-ppt
type: sint
doc: |
- The FFO (Fractional Frequency Offset) of the pin with respect to
- the nominal frequency.
- Value = (frequency_measured - frequency_nominal) / frequency_nominal
+ The FFO (Fractional Frequency Offset) of the pin.
+ At top level this represents the RX vs TX symbol rate
+ offset on the media associated with the pin. Inside
+ the pin-parent-device nest it represents the frequency
+ offset between the pin and its parent DPLL device.
Value is in PPT (parts per trillion, 10^-12).
- Note: This attribute provides higher resolution than the standard
- fractional-frequency-offset (which is in PPM).
+ This is a higher-precision version of
+ fractional-frequency-offset.
-
name: measured-frequency
type: u64
@@ -534,6 +538,10 @@ attribute-sets:
name: operstate
-
name: phase-offset
+ -
+ name: fractional-frequency-offset
+ -
+ name: fractional-frequency-offset-ppt
-
name: pin-parent-pin
subset-of: pin
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
index 84e1b63..8b260a3 100644
--- a/drivers/dpll/dpll_core.c
+++ b/drivers/dpll/dpll_core.c
@@ -883,7 +883,8 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
WARN_ON(!ops->direction_get) ||
WARN_ON(ops->measured_freq_get &&
(!dpll_device_ops(dpll)->freq_monitor_get ||
- !dpll_device_ops(dpll)->freq_monitor_set)))
+ !dpll_device_ops(dpll)->freq_monitor_set)) ||
+ WARN_ON(ops->supported_ffo && !ops->ffo_get))
return -EINVAL;
mutex_lock(&dpll_lock);
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index ea63602..6a4ddd7 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -417,31 +417,34 @@ dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin,
static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
+ enum dpll_ffo_type type,
struct netlink_ext_ack *extack)
{
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
- struct dpll_device *dpll = ref->dpll;
- s64 ffo;
+ struct dpll_ffo_param ffo = { .type = type };
int ret;
- if (!ops->ffo_get)
- return 0;
- ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
- dpll, dpll_priv(dpll), &ffo, extack);
+ /* RHEL: To maintain backward compatibility with older binary modules,
+ * we must accept a value of zero for .supported_ffo when the type is
+ * DPLL_FFO_PORT_RXTX_RATE.
+ */
+ if (!ops->ffo_get ||
+ !((ops->supported_ffo & BIT(type)) ||
+ (!ops->supported_ffo && type == DPLL_FFO_PORT_RXTX_RATE)))
+ return 0;
+ ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(ref->dpll, pin),
+ ref->dpll, dpll_priv(ref->dpll), &ffo, extack);
if (ret) {
if (ret == -ENODATA)
return 0;
return ret;
}
- /* Put the FFO value in PPM to preserve compatibility with older
- * programs.
- */
- ret = nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
- div_s64(ffo, 1000000));
- if (ret)
+ if (nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
+ div_s64(ffo.ffo, 1000000)))
return -EMSGSIZE;
- return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT,
- ffo);
+ return nla_put_sint(msg,
+ DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT,
+ ffo.ffo);
}
static int dpll_msg_add_measured_freq(struct sk_buff *msg, struct dpll_pin *pin,
@@ -686,6 +689,10 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
if (ret)
goto nest_cancel;
ret = dpll_msg_add_phase_offset(msg, pin, ref, extack);
+ if (ret)
+ goto nest_cancel;
+ ret = dpll_msg_add_ffo(msg, pin, ref,
+ DPLL_FFO_PIN_DEVICE, extack);
if (ret)
goto nest_cancel;
nla_nest_end(msg, attr);
@@ -748,7 +755,8 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack);
if (ret)
return ret;
- ret = dpll_msg_add_ffo(msg, pin, ref, extack);
+ ret = dpll_msg_add_ffo(msg, pin, ref,
+ DPLL_FFO_PORT_RXTX_RATE, extack);
if (ret)
return ret;
ret = dpll_msg_add_measured_freq(msg, pin, ref, extack);
diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c
index 6439884..268999d 100644
--- a/drivers/dpll/dpll_nl.c
+++ b/drivers/dpll/dpll_nl.c
@@ -18,6 +18,8 @@ const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE +
[DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
[DPLL_A_PIN_OPERSTATE] = NLA_POLICY_RANGE(NLA_U32, 1, 4),
[DPLL_A_PIN_PHASE_OFFSET] = { .type = NLA_S64, },
+ [DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET] = { .type = NLA_SINT, },
+ [DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT] = { .type = NLA_SINT, },
};
const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1] = {
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 2c8bd21..b159dff 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -295,11 +295,12 @@ zl3073x_dpll_input_pin_ref_sync_set(const struct dpll_pin *dpll_pin,
static int
zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
- s64 *ffo, struct netlink_ext_ack *extack)
+ struct dpll_ffo_param *ffo,
+ struct netlink_ext_ack *extack)
{
struct zl3073x_dpll_pin *pin = pin_priv;
- *ffo = pin->freq_offset;
+ ffo->ffo = pin->freq_offset;
return 0;
}
@@ -1274,6 +1275,7 @@ zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll,
}
static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
+ .supported_ffo = BIT(DPLL_FFO_PORT_RXTX_RATE),
.direction_get = zl3073x_dpll_pin_direction_get,
.esync_get = zl3073x_dpll_input_pin_esync_get,
.esync_set = zl3073x_dpll_input_pin_esync_set,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
index 3981dd8..3756c02 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
@@ -300,7 +300,8 @@ static int mlx5_dpll_state_on_dpll_set(const struct dpll_pin *pin,
static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
- s64 *ffo, struct netlink_ext_ack *extack)
+ struct dpll_ffo_param *ffo,
+ struct netlink_ext_ack *extack)
{
struct mlx5_dpll_synce_status synce_status;
struct mlx5_dpll *mdpll = pin_priv;
@@ -309,10 +310,11 @@ static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv,
err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
return err;
- return mlx5_dpll_pin_ffo_get(&synce_status, ffo);
+ return mlx5_dpll_pin_ffo_get(&synce_status, &ffo->ffo);
}
static const struct dpll_pin_ops mlx5_dpll_pins_ops = {
+ .supported_ffo = BIT(DPLL_FFO_PORT_RXTX_RATE),
.direction_get = mlx5_dpll_pin_direction_get,
.state_on_dpll_get = mlx5_dpll_state_on_dpll_get,
.state_on_dpll_set = mlx5_dpll_state_on_dpll_set,
diff --git a/include/linux/dpll.h b/include/linux/dpll.h
index c5e333a..4a8854a 100644
--- a/include/linux/dpll.h
+++ b/include/linux/dpll.h
@@ -71,6 +71,22 @@ struct dpll_device_ops {
RH_KABI_RESERVE(10)
};
+enum dpll_ffo_type {
+ DPLL_FFO_PORT_RXTX_RATE,
+ DPLL_FFO_PIN_DEVICE,
+
+ __DPLL_FFO_TYPE_MAX,
+};
+
+/* RHEL: we have to keep 'ffo' field to be first to preserve compatibility
+ * with older .ffo_get() callbacks that accepts 's64 *' as parameter instead
+ * of 'struct dpll_ffo_param *'
+ */
+struct dpll_ffo_param {
+ s64 ffo;
+ enum dpll_ffo_type type;
+};
+
struct dpll_pin_ops {
int (*frequency_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
@@ -96,12 +112,6 @@ struct dpll_pin_ops {
const struct dpll_device *dpll,
void *dpll_priv, enum dpll_pin_state *state,
struct netlink_ext_ack *extack);
- int (*operstate_on_dpll_get)(const struct dpll_pin *pin,
- void *pin_priv,
- const struct dpll_device *dpll,
- void *dpll_priv,
- enum dpll_pin_operstate *operstate,
- struct netlink_ext_ack *extack);
int (*state_on_pin_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *parent_pin,
void *parent_pin_priv,
@@ -130,9 +140,13 @@ struct dpll_pin_ops {
const struct dpll_device *dpll, void *dpll_priv,
const s32 phase_adjust,
struct netlink_ext_ack *extack);
- int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv,
+ RH_KABI_REPLACE(int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
- s64 *ffo, struct netlink_ext_ack *extack);
+ s64 *ffo, struct netlink_ext_ack *extack),
+ int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv,
+ const struct dpll_device *dpll, void *dpll_priv,
+ struct dpll_ffo_param *ffo,
+ struct netlink_ext_ack *extack))
int (*esync_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
u64 freq, struct netlink_ext_ack *extack);
@@ -155,8 +169,13 @@ struct dpll_pin_ops {
const struct dpll_device *dpll,
void *dpll_priv, u64 *measured_freq,
struct netlink_ext_ack *extack))
- RH_KABI_RESERVE(2)
- RH_KABI_RESERVE(3)
+ RH_KABI_USE(2, int (*operstate_on_dpll_get)(const struct dpll_pin *pin,
+ void *pin_priv,
+ const struct dpll_device *dpll,
+ void *dpll_priv,
+ enum dpll_pin_operstate *operstate,
+ struct netlink_ext_ack *extack))
+ RH_KABI_USE(3, unsigned long supported_ffo)
RH_KABI_RESERVE(4)
RH_KABI_RESERVE(5)
RH_KABI_RESERVE(6)

View File

@ -0,0 +1,347 @@
From 54e65df8cf18a741745645aed7ae91514d437b43 Mon Sep 17 00:00:00 2001
From: Ivan Vecera <ivecera@redhat.com>
Date: Mon, 11 May 2026 17:58:16 +0200
Subject: [PATCH] dpll: zl3073x: report FFO as DPLL vs input reference offset
Replace the per-reference frequency offset measurement (which was
redundant with measured-frequency) with a direct read of the DPLL's
delta frequency offset vs its tracked input reference.
The new implementation uses the dpll_df_offset_x register with
ref_ofst=1 via the dpll_df_read_x semaphore mechanism. This
provides 2^-48 resolution (~3.5 fE) and reports the actual
frequency difference between the DPLL and its active input.
Switch supported_ffo from DPLL_FFO_PORT_RXTX_RATE to
DPLL_FFO_PIN_DEVICE so FFO is reported only in the per-parent
context for the active input pin.
Use atomic64_t for freq_offset to prevent torn reads on 32-bit
architectures between the periodic worker and netlink callbacks.
Rewrite ffo_check to compare the cached df_offset converted to PPT
instead of using the old per-reference measurement. Remove the
ref_ffo_update periodic measurement and the ref ffo field since
they are no longer needed.
Changes v3 -> v4:
- Switch to DPLL_FFO_PIN_DEVICE, remove dpll=NULL guard
- Use atomic64_t for freq_offset (torn read on 32-bit)
Reviewed-by: Petr Oros <poros@redhat.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Link: https://patch.msgid.link/20260511155816.99936-3-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
diff --git a/drivers/dpll/zl3073x/chan.c b/drivers/dpll/zl3073x/chan.c
index 2f48ca2..2fe3c3d 100644
--- a/drivers/dpll/zl3073x/chan.c
+++ b/drivers/dpll/zl3073x/chan.c
@@ -18,6 +18,7 @@
int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
{
struct zl3073x_chan *chan = &zldev->chan[index];
+ u64 val;
int rc;
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(index),
@@ -25,8 +26,34 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
if (rc)
return rc;
- return zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index),
- &chan->refsel_status);
+ rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index),
+ &chan->refsel_status);
+ if (rc)
+ return rc;
+
+ /* Read df_offset vs tracked reference */
+ rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index),
+ ZL_DPLL_DF_READ_SEM);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_DF_READ(index),
+ ZL_DPLL_DF_READ_SEM | ZL_DPLL_DF_READ_REF_OFST);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index),
+ ZL_DPLL_DF_READ_SEM);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_DF_OFFSET(index), &val);
+ if (rc)
+ return rc;
+
+ chan->df_offset = sign_extend64(val, 47);
+
+ return 0;
}
/**
diff --git a/drivers/dpll/zl3073x/chan.h b/drivers/dpll/zl3073x/chan.h
index 481da21..4353809 100644
--- a/drivers/dpll/zl3073x/chan.h
+++ b/drivers/dpll/zl3073x/chan.h
@@ -17,6 +17,7 @@ struct zl3073x_dev;
* @ref_prio: reference priority registers (4 bits per ref, P/N packed)
* @mon_status: monitor status register value
* @refsel_status: reference selection status register value
+ * @df_offset: frequency offset vs tracked reference in 2^-48 steps
*/
struct zl3073x_chan {
struct_group(cfg,
@@ -26,6 +27,7 @@ struct zl3073x_chan {
struct_group(stat,
u8 mon_status;
u8 refsel_status;
+ s64 df_offset;
);
};
@@ -37,6 +39,18 @@ int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index,
int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index);
+/**
+ * zl3073x_chan_df_offset_get - get cached df_offset vs tracked reference
+ * @chan: pointer to channel state
+ *
+ * Return: frequency offset in 2^-48 steps
+ */
+static inline s64
+zl3073x_chan_df_offset_get(const struct zl3073x_chan *chan)
+{
+ return chan->df_offset;
+}
+
/**
* zl3073x_chan_mode_get - get DPLL channel operating mode
* @chan: pointer to channel state
diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
index 024f0a2..7d2ad4b 100644
--- a/drivers/dpll/zl3073x/core.c
+++ b/drivers/dpll/zl3073x/core.c
@@ -704,44 +704,6 @@ zl3073x_ref_freq_meas_update(struct zl3073x_dev *zldev)
return 0;
}
-/**
- * zl3073x_ref_ffo_update - update reference fractional frequency offsets
- * @zldev: pointer to zl3073x_dev structure
- *
- * The function asks device to latch the latest measured fractional
- * frequency offset values, reads and stores them into the ref state.
- *
- * Return: 0 on success, <0 on error
- */
-static int
-zl3073x_ref_ffo_update(struct zl3073x_dev *zldev)
-{
- int i, rc;
-
- rc = zl3073x_ref_freq_meas_latch(zldev,
- ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF);
- if (rc)
- return rc;
-
- /* Read DPLL-to-REFx frequency offset measurements */
- for (i = 0; i < ZL3073X_NUM_REFS; i++) {
- s32 value;
-
- /* Read value stored in units of 2^-32 signed */
- rc = zl3073x_read_u32(zldev, ZL_REG_REF_FREQ(i), &value);
- if (rc)
- return rc;
-
- /* Convert to ppt
- * ffo = (10^12 * value) / 2^32
- * ffo = ( 5^12 * value) / 2^20
- */
- zldev->ref[i].ffo = mul_s64_u64_shr(value, 244140625, 20);
- }
-
- return 0;
-}
-
static void
zl3073x_dev_periodic_work(struct kthread_work *work)
{
@@ -776,13 +738,6 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
}
}
- /* Update references' fractional frequency offsets */
- rc = zl3073x_ref_ffo_update(zldev);
- if (rc)
- dev_warn(zldev->dev,
- "Failed to update fractional frequency offsets: %pe\n",
- ERR_PTR(rc));
-
list_for_each_entry(zldpll, &zldev->dplls, list)
zl3073x_dpll_changes_check(zldpll);
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index b159dff..6b714ec 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/atomic.h>
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/bug.h>
@@ -57,7 +58,7 @@ struct zl3073x_dpll_pin {
s32 phase_gran;
enum dpll_pin_operstate operstate;
s64 phase_offset;
- s64 freq_offset;
+ atomic64_t freq_offset;
u32 measured_freq;
};
@@ -300,7 +301,10 @@ zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv,
{
struct zl3073x_dpll_pin *pin = pin_priv;
- ffo->ffo = pin->freq_offset;
+ if (pin->operstate != DPLL_PIN_OPERSTATE_ACTIVE)
+ return -ENODATA;
+
+ ffo->ffo = atomic64_read(&pin->freq_offset);
return 0;
}
@@ -1275,7 +1279,7 @@ zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll,
}
static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
- .supported_ffo = BIT(DPLL_FFO_PORT_RXTX_RATE),
+ .supported_ffo = BIT(DPLL_FFO_PIN_DEVICE),
.direction_get = zl3073x_dpll_pin_direction_get,
.esync_get = zl3073x_dpll_input_pin_esync_get,
.esync_set = zl3073x_dpll_input_pin_esync_set,
@@ -1731,37 +1735,29 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)
}
/**
- * zl3073x_dpll_pin_ffo_check - check for pin fractional frequency offset change
+ * zl3073x_dpll_pin_ffo_check - check for FFO change on active pin
* @pin: pin to check
*
- * Check for the given pin's fractional frequency change.
- *
- * Return: true on fractional frequency offset change, false otherwise
+ * Return: true on change, false otherwise
*/
static bool
zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin)
{
struct zl3073x_dpll *zldpll = pin->dpll;
struct zl3073x_dev *zldev = zldpll->dev;
- const struct zl3073x_ref *ref;
- u8 ref_id;
+ const struct zl3073x_chan *chan;
s64 ffo;
- /* Get reference monitor status */
- ref_id = zl3073x_input_pin_ref_get(pin->id);
- ref = zl3073x_ref_state_get(zldev, ref_id);
-
- /* Do not report ffo changes if the reference monitor report errors */
- if (!zl3073x_ref_is_status_ok(ref))
+ if (pin->operstate != DPLL_PIN_OPERSTATE_ACTIVE)
return false;
- /* Compare with previous value */
- ffo = zl3073x_ref_ffo_get(ref);
- if (pin->freq_offset != ffo) {
- dev_dbg(zldev->dev, "%s freq offset changed: %lld -> %lld\n",
- pin->label, pin->freq_offset, ffo);
- pin->freq_offset = ffo;
+ chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id);
+ ffo = mul_s64_u64_shr(zl3073x_chan_df_offset_get(chan),
+ 244140625, 36);
+ if (atomic64_xchg(&pin->freq_offset, ffo) != ffo) {
+ dev_dbg(zldev->dev, "%s freq offset changed to: %lld\n",
+ pin->label, ffo);
return true;
}
diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h
index 55e80e4..e140ca3 100644
--- a/drivers/dpll/zl3073x/ref.h
+++ b/drivers/dpll/zl3073x/ref.h
@@ -22,7 +22,6 @@ struct zl3073x_dev;
* @freq_ratio_n: FEC mode divisor
* @sync_ctrl: reference sync control
* @config: reference config
- * @ffo: current fractional frequency offset
* @meas_freq: measured input frequency in Hz
* @mon_status: reference monitor status
*/
@@ -40,7 +39,6 @@ struct zl3073x_ref {
u8 config;
);
struct_group(stat, /* Status */
- s64 ffo;
u32 meas_freq;
u8 mon_status;
);
@@ -58,18 +56,6 @@ int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index);
int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);
-/**
- * zl3073x_ref_ffo_get - get current fractional frequency offset
- * @ref: pointer to ref state
- *
- * Return: the latest measured fractional frequency offset
- */
-static inline s64
-zl3073x_ref_ffo_get(const struct zl3073x_ref *ref)
-{
- return ref->ffo;
-}
-
/**
* zl3073x_ref_meas_freq_get - get measured input frequency
* @ref: pointer to ref state
diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h
index 8015808..9578f00 100644
--- a/drivers/dpll/zl3073x/regs.h
+++ b/drivers/dpll/zl3073x/regs.h
@@ -164,6 +164,11 @@
#define ZL_DPLL_MODE_REFSEL_MODE_NCO 4
#define ZL_DPLL_MODE_REFSEL_REF GENMASK(7, 4)
+#define ZL_REG_DPLL_DF_READ(_idx) \
+ ZL_REG_IDX(_idx, 5, 0x28, 1, ZL3073X_MAX_CHANNELS, 1)
+#define ZL_DPLL_DF_READ_SEM BIT(4)
+#define ZL_DPLL_DF_READ_REF_OFST BIT(3)
+
#define ZL_REG_DPLL_MEAS_CTRL ZL_REG(5, 0x50, 1)
#define ZL_DPLL_MEAS_CTRL_EN BIT(0)
#define ZL_DPLL_MEAS_CTRL_AVG_FACTOR GENMASK(7, 4)
@@ -176,6 +181,16 @@
#define ZL_REG_DPLL_PHASE_ERR_DATA(_idx) \
ZL_REG_IDX(_idx, 5, 0x55, 6, ZL3073X_MAX_CHANNELS, 6)
+/*******************************
+ * Register Pages 6-7, DPLL Data
+ *******************************/
+
+#define ZL_REG_DPLL_DF_OFFSET_03(_idx) \
+ ZL_REG_IDX(_idx, 6, 0x00, 6, 4, 0x20)
+#define ZL_REG_DPLL_DF_OFFSET_4 ZL_REG(7, 0x00, 6)
+#define ZL_REG_DPLL_DF_OFFSET(_idx) \
+ ((_idx) < 4 ? ZL_REG_DPLL_DF_OFFSET_03(_idx) : ZL_REG_DPLL_DF_OFFSET_4)
+
/***********************************
* Register Page 9, Synth and Output
***********************************/

View File

@ -0,0 +1,100 @@
From f6e1f25fa5e733570f6d6fe37a4dfed2a0deba47 Mon Sep 17 00:00:00 2001
From: Jiayuan Chen <jiayuan.chen@linux.dev>
Date: Mon, 6 Apr 2026 11:15:10 +0800
Subject: [PATCH] mptcp: fix slab-use-after-free in __inet_lookup_established
commit 9b55b253907e7431210483519c5ad711a37dafa1 upstream.
The ehash table lookups are lockless and rely on
SLAB_TYPESAFE_BY_RCU to guarantee socket memory stability
during RCU read-side critical sections. Both tcp_prot and
tcpv6_prot have their slab caches created with this flag
via proto_register().
However, MPTCP's mptcp_subflow_init() copies tcpv6_prot into
tcpv6_prot_override during inet_init() (fs_initcall, level 5),
before inet6_init() (module_init/device_initcall, level 6) has
called proto_register(&tcpv6_prot). At that point,
tcpv6_prot.slab is still NULL, so tcpv6_prot_override.slab
remains NULL permanently.
This causes MPTCP v6 subflow child sockets to be allocated via
kmalloc (falling into kmalloc-4k) instead of the TCPv6 slab
cache. The kmalloc-4k cache lacks SLAB_TYPESAFE_BY_RCU, so
when these sockets are freed without SOCK_RCU_FREE (which is
cleared for child sockets by design), the memory can be
immediately reused. Concurrent ehash lookups under
rcu_read_lock can then access freed memory, triggering a
slab-use-after-free in __inet_lookup_established.
Fix this by splitting the IPv6-specific initialization out of
mptcp_subflow_init() into a new mptcp_subflow_v6_init(), called
from mptcp_proto_v6_init() before protocol registration. This
ensures tcpv6_prot_override.slab correctly inherits the
SLAB_TYPESAFE_BY_RCU slab cache.
Fixes: b19bc2945b40 ("mptcp: implement delegated actions")
Cc: stable@vger.kernel.org
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20260406031512.189159-1-jiayuan.chen@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index fae51f3..a8d345c 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -4248,6 +4248,8 @@ int __init mptcp_proto_v6_init(void)
{
int err;
+ mptcp_subflow_v6_init();
+
mptcp_v6_prot = mptcp_prot;
strscpy(mptcp_v6_prot.name, "MPTCPv6", sizeof(mptcp_v6_prot.name));
mptcp_v6_prot.slab = NULL;
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index fc9ad56..161ed3c 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -794,6 +794,7 @@ static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
void __init mptcp_proto_init(void);
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
int __init mptcp_proto_v6_init(void);
+void __init mptcp_subflow_v6_init(void);
#endif
struct sock *mptcp_sk_clone_init(const struct sock *sk,
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index a37c9cb..b6cd4d5 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -2103,7 +2103,15 @@ void __init mptcp_subflow_init(void)
tcp_prot_override.release_cb = tcp_release_cb_override;
tcp_prot_override.diag_destroy = tcp_abort_override;
+ mptcp_diag_subflow_init(&subflow_ulp_ops);
+
+ if (tcp_register_ulp(&subflow_ulp_ops) != 0)
+ panic("MPTCP: failed to register subflows to ULP\n");
+}
+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+void __init mptcp_subflow_v6_init(void)
+{
/* In struct mptcp_subflow_request_sock, we assume the TCP request sock
* structures for v4 and v6 have the same size. It should not changed in
* the future but better to make sure to be warned if it is no longer
@@ -2139,10 +2147,5 @@ void __init mptcp_subflow_init(void)
tcpv6_prot_override = tcpv6_prot;
tcpv6_prot_override.release_cb = tcp_release_cb_override;
tcpv6_prot_override.diag_destroy = tcp_abort_override;
-#endif
-
- mptcp_diag_subflow_init(&subflow_ulp_ops);
-
- if (tcp_register_ulp(&subflow_ulp_ops) != 0)
- panic("MPTCP: failed to register subflows to ULP\n");
}
+#endif

View File

@ -0,0 +1,95 @@
From 6985e4baf50b86327426ca5d5cf4787ac165aacd Mon Sep 17 00:00:00 2001
From: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
Date: Thu, 23 Apr 2026 22:42:57 +0000
Subject: [PATCH] ice: Fix NULL pointer dereference in ice_vsi_set_napi_queues
JIRA: https://redhat.atlassian.net/browse/RHEL-99101
commit 9bb30be4d89ff9a8d7ab1aa0eb2edaca83431f85
Author: Aaron Ma <aaron.ma@canonical.com>
Date: Thu Dec 25 14:21:21 2025 +0800
ice: Fix NULL pointer dereference in ice_vsi_set_napi_queues
Add NULL pointer checks in ice_vsi_set_napi_queues() to prevent crashes
during resume from suspend when rings[q_idx]->q_vector is NULL.
Tested adaptor:
60:00.0 Ethernet controller [0200]: Intel Corporation Ethernet Controller E810-XXV for SFP [8086:159b] (rev 02)
Subsystem: Intel Corporation Ethernet Network Adapter E810-XXV-2 [8086:4003]
SR-IOV state: both disabled and enabled can reproduce this issue.
kernel version: v6.18
Reproduce steps:
Boot up and execute suspend like systemctl suspend or rtcwake.
Log:
<1>[ 231.443607] BUG: kernel NULL pointer dereference, address: 0000000000000040
<1>[ 231.444052] #PF: supervisor read access in kernel mode
<1>[ 231.444484] #PF: error_code(0x0000) - not-present page
<6>[ 231.444913] PGD 0 P4D 0
<4>[ 231.445342] Oops: Oops: 0000 [#1] SMP NOPTI
<4>[ 231.446635] RIP: 0010:netif_queue_set_napi+0xa/0x170
<4>[ 231.447067] Code: 31 f6 31 ff c3 cc cc cc cc 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 48 85 c9 74 0b <48> 83 79 30 00 0f 84 39 01 00 00 55 41 89 d1 49 89 f8 89 f2 48 89
<4>[ 231.447513] RSP: 0018:ffffcc780fc078c0 EFLAGS: 00010202
<4>[ 231.447961] RAX: ffff8b848ca30400 RBX: ffff8b848caf2028 RCX: 0000000000000010
<4>[ 231.448443] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8b848dbd4000
<4>[ 231.448896] RBP: ffffcc780fc078e8 R08: 0000000000000000 R09: 0000000000000000
<4>[ 231.449345] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000001
<4>[ 231.449817] R13: ffff8b848dbd4000 R14: ffff8b84833390c8 R15: 0000000000000000
<4>[ 231.450265] FS: 00007c7b29e9d740(0000) GS:ffff8b8c068e2000(0000) knlGS:0000000000000000
<4>[ 231.450715] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
<4>[ 231.451179] CR2: 0000000000000040 CR3: 000000030626f004 CR4: 0000000000f72ef0
<4>[ 231.451629] PKRU: 55555554
<4>[ 231.452076] Call Trace:
<4>[ 231.452549] <TASK>
<4>[ 231.452996] ? ice_vsi_set_napi_queues+0x4d/0x110 [ice]
<4>[ 231.453482] ice_resume+0xfd/0x220 [ice]
<4>[ 231.453977] ? __pfx_pci_pm_resume+0x10/0x10
<4>[ 231.454425] pci_pm_resume+0x8c/0x140
<4>[ 231.454872] ? __pfx_pci_pm_resume+0x10/0x10
<4>[ 231.455347] dpm_run_callback+0x5f/0x160
<4>[ 231.455796] ? dpm_wait_for_superior+0x107/0x170
<4>[ 231.456244] device_resume+0x177/0x270
<4>[ 231.456708] dpm_resume+0x209/0x2f0
<4>[ 231.457151] dpm_resume_end+0x15/0x30
<4>[ 231.457596] suspend_devices_and_enter+0x1da/0x2b0
<4>[ 231.458054] enter_state+0x10e/0x570
Add defensive checks for both the ring pointer and its q_vector
before dereferencing, allowing the system to resume successfully even when
q_vectors are unmapped.
Fixes: 2a5dc090b92cf ("ice: move netif_queue_set_napi to rtnl-protected sections")
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 72c91bd..60b32b4 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -2789,12 +2789,14 @@ void ice_vsi_set_napi_queues(struct ice_vsi *vsi)
ASSERT_RTNL();
ice_for_each_rxq(vsi, q_idx)
- netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_RX,
- &vsi->rx_rings[q_idx]->q_vector->napi);
+ if (vsi->rx_rings[q_idx] && vsi->rx_rings[q_idx]->q_vector)
+ netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_RX,
+ &vsi->rx_rings[q_idx]->q_vector->napi);
ice_for_each_txq(vsi, q_idx)
- netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_TX,
- &vsi->tx_rings[q_idx]->q_vector->napi);
+ if (vsi->tx_rings[q_idx] && vsi->tx_rings[q_idx]->q_vector)
+ netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_TX,
+ &vsi->tx_rings[q_idx]->q_vector->napi);
/* Also set the interrupt number for the NAPI */
ice_for_each_q_vector(vsi, v_idx) {
struct ice_q_vector *q_vector = vsi->q_vectors[v_idx];

View File

@ -0,0 +1,89 @@
From d28311539ac9f65e29308ea219ecaa48aa5e76e5 Mon Sep 17 00:00:00 2001
From: Shuvam Pandey <shuvampandey1@gmail.com>
Date: Fri, 8 May 2026 21:33:20 -0400
Subject: [PATCH] Bluetooth: hci_event: fix potential UAF in SSP passkey
handlers
[ Upstream commit 85fa3512048793076eef658f66489112dcc91993 ]
hci_conn lookup and field access must be covered by hdev lock in
hci_user_passkey_notify_evt() and hci_keypress_notify_evt(), otherwise
the connection can be freed concurrently.
Extend the hci_dev_lock critical section to cover all conn usage in both
handlers.
Keep the existing keypress notification behavior unchanged by routing
the early exits through a common unlock path.
Fixes: 92a25256f142 ("Bluetooth: mgmt: Implement support for passkey notification")
Cc: stable@vger.kernel.org
Signed-off-by: Shuvam Pandey <shuvampandey1@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index f5054bb..262a918 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -5418,9 +5418,11 @@ static void hci_user_passkey_notify_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "");
+ hci_dev_lock(hdev);
+
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
- return;
+ goto unlock;
conn->passkey_notify = __le32_to_cpu(ev->passkey);
conn->passkey_entered = 0;
@@ -5429,6 +5431,9 @@ static void hci_user_passkey_notify_evt(struct hci_dev *hdev, void *data,
mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
conn->dst_type, conn->passkey_notify,
conn->passkey_entered);
+
+unlock:
+ hci_dev_unlock(hdev);
}
static void hci_keypress_notify_evt(struct hci_dev *hdev, void *data,
@@ -5439,14 +5444,16 @@ static void hci_keypress_notify_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "");
+ hci_dev_lock(hdev);
+
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
- return;
+ goto unlock;
switch (ev->type) {
case HCI_KEYPRESS_STARTED:
conn->passkey_entered = 0;
- return;
+ goto unlock;
case HCI_KEYPRESS_ENTERED:
conn->passkey_entered++;
@@ -5461,13 +5468,16 @@ static void hci_keypress_notify_evt(struct hci_dev *hdev, void *data,
break;
case HCI_KEYPRESS_COMPLETED:
- return;
+ goto unlock;
}
if (hci_dev_test_flag(hdev, HCI_MGMT))
mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
conn->dst_type, conn->passkey_notify,
conn->passkey_entered);
+
+unlock:
+ hci_dev_unlock(hdev);
}
static void hci_simple_pair_complete_evt(struct hci_dev *hdev, void *data,

View File

@ -0,0 +1,33 @@
From ac8eb3e18f41e2cc8492cc1d358bcb786c850270 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <benjamin.berg@intel.com>
Date: Tue, 5 May 2026 15:15:40 +0200
Subject: [PATCH] wifi: mac80211: use safe list iteration in radar detect work
The call to ieee80211_dfs_cac_cancel can cause the iterated chanctx to
be freed and removed from the list. Guard against this to avoid a
slab-use-after-free error.
Cc: stable@vger.kernel.org
Fixes: bca8bc0399ac ("wifi: mac80211: handle ieee80211_radar_detected() for MLO")
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Link: https://patch.msgid.link/20260505151539.236d63a1b736.I35dbb9e96a2d4a480be208770fdd99ba3b817b79@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index c993153..62e1a37 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3565,11 +3565,11 @@ void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, radar_detected_work);
struct cfg80211_chan_def chandef;
- struct ieee80211_chanctx *ctx;
+ struct ieee80211_chanctx *ctx, *tmp;
lockdep_assert_wiphy(local->hw.wiphy);
- list_for_each_entry(ctx, &local->chanctx_list, list) {
+ list_for_each_entry_safe(ctx, tmp, &local->chanctx_list, list) {
if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
continue;

View File

@ -0,0 +1,35 @@
From 7a5b81e0c87a075afd572f659d8eb68c9c4cd2ba Mon Sep 17 00:00:00 2001
From: Catherine <enderaoelyther@gmail.com>
Date: Fri, 24 Apr 2026 21:14:36 +0800
Subject: [PATCH] wifi: mac80211: drop stray 'static' from fast-RX rx_result
ieee80211_invoke_fast_rx() is documented as safe for parallel RX, but
its per-invocation rx_result is declared static. Concurrent callers then
share one instance and can overwrite each other's result between
ieee80211_rx_mesh_data() and the switch on res.
That can make a packet that was queued or consumed by
ieee80211_rx_mesh_data() fall through into ieee80211_rx_8023(), or make
a packet that should continue return as queued.
Make res an automatic variable so each invocation keeps its own result.
Fixes: 3468e1e0c639 ("wifi: mac80211: add mesh fast-rx support")
Cc: stable@vger.kernel.org
Signed-off-by: Catherine <enderaoelyther@gmail.com>
Link: https://patch.msgid.link/20260424131435.83212-2-enderaoelyther@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4e34435..02f1315 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4819,7 +4819,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
struct sk_buff *skb = rx->skb;
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
- static ieee80211_rx_result res;
+ ieee80211_rx_result res;
int orig_len = skb->len;
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
int snap_offs = hdrlen;

View File

@ -0,0 +1,30 @@
From 6dd2d4ad9c8429523b1c220c5132bd551c006425 Mon Sep 17 00:00:00 2001
From: Jason Gunthorpe <jgg@nvidia.com>
Date: Tue, 28 Apr 2026 13:17:37 -0300
Subject: [PATCH] RDMA/mana: Validate rx_hash_key_len
Sashiko points out that rx_hash_key_len comes from a uAPI structure and is
blindly passed to memcpy, allowing the userspace to trash kernel
memory. Bounds check it so the memcpy cannot overflow.
Cc: stable@vger.kernel.org
Fixes: 0266a177631d ("RDMA/mana_ib: Add a driver for Microsoft Azure Network Adapter")
Link: https://sashiko.dev/#/patchset/0-v2-1c49eeb88c48%2B91-rdma_udata_rep_jgg%40nvidia.com?part=1
Link: https://patch.msgid.link/r/4-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com
Reviewed-by: Long Li <longli@microsoft.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
index 48c1f49..8eb956e 100644
--- a/drivers/infiniband/hw/mana/qp.c
+++ b/drivers/infiniband/hw/mana/qp.c
@@ -21,6 +21,9 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev,
gc = mdev_to_gc(dev);
+ if (rx_hash_key_len > sizeof(req->hashkey))
+ return -EINVAL;
+
req_buf_size = struct_size(req, indir_tab, MANA_INDIRECT_TABLE_DEF_SIZE);
req = kzalloc(req_buf_size, GFP_KERNEL);
if (!req)

View File

@ -0,0 +1,56 @@
From 283fc9e44ff5b5ac967439b4951b80bd4299f4e4 Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes.berg@intel.com>
Date: Tue, 5 May 2026 15:15:34 +0200
Subject: [PATCH] wifi: mac80211: remove station if connection prep fails
If connection preparation fails for MLO connections, then the
interface is completely reset to non-MLD. In this case, we must
not keep the station since it's related to the link of the vif
being removed. Delete an existing station. Any "new_sta" is
already being removed, so that doesn't need changes.
This fixes a use-after-free/double-free in debugfs if that's
enabled, because a vif going from MLD (and to MLD, but that's
not relevant here) recreates its entire debugfs.
Cc: stable@vger.kernel.org
Fixes: 81151ce462e5 ("wifi: mac80211: support MLO authentication/association with one link")
Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260505151533.c4e52deb06ad.Iafe56cec7de8512626169496b134bce3a6c17010@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e185f2a..7ba68a0 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -8890,7 +8890,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss = (void *)cbss->priv;
struct sta_info *new_sta = NULL;
struct ieee80211_link_data *link;
- bool have_sta = false;
+ struct sta_info *have_sta = NULL;
bool mlo;
int err;
u16 new_links;
@@ -8909,11 +8909,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
mlo = false;
}
- if (assoc) {
- rcu_read_lock();
+ if (assoc)
have_sta = sta_info_get(sdata, ap_mld_addr);
- rcu_read_unlock();
- }
if (mlo && !have_sta &&
WARN_ON(sdata->vif.valid_links || sdata->vif.active_links))
@@ -9072,6 +9069,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
out_release_chan:
ieee80211_link_release_channel(link);
out_err:
+ if (mlo && have_sta)
+ WARN_ON(__sta_info_destroy(have_sta));
ieee80211_vif_set_links(sdata, 0, 0);
return err;
}

View File

@ -0,0 +1,57 @@
From e123d9302d223767bd910bfbcfe607bae909f8ac Mon Sep 17 00:00:00 2001
From: Pavan Chebbi <pavan.chebbi@broadcom.com>
Date: Thu, 19 Feb 2026 10:53:11 -0800
Subject: [PATCH] bnxt_en: Fix RSS context delete logic
We need to free the corresponding RSS context VNIC
in FW everytime an RSS context is deleted in driver.
Commit 667ac333dbb7 added a check to delete the VNIC
in FW only when netif_running() is true to help delete
RSS contexts with interface down.
Having that condition will make the driver leak VNICs
in FW whenever close() happens with active RSS contexts.
On the subsequent open(), as part of RSS context restoration,
we will end up trying to create extra VNICs for which we
did not make any reservation. FW can fail this request,
thereby making us lose active RSS contexts.
Suppose an RSS context is deleted already and we try to
process a delete request again, then the HWRM functions
will check for validity of the request and they simply
return if the resource is already freed. So, even for
delete-when-down cases, netif_running() check is not
necessary.
Remove the netif_running() condition check when deleting
an RSS context.
Reported-by: Jakub Kicinski <kicinski@meta.com>
Fixes: 667ac333dbb7 ("eth: bnxt: allow deleting RSS contexts when the device is down")
Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Link: https://patch.msgid.link/20260219185313.2682148-2-michael.chan@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 3177d4b..a178578 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -10731,12 +10731,10 @@ void bnxt_del_one_rss_ctx(struct bnxt *bp, struct bnxt_rss_ctx *rss_ctx,
struct bnxt_ntuple_filter *ntp_fltr;
int i;
- if (netif_running(bp->dev)) {
- bnxt_hwrm_vnic_free_one(bp, &rss_ctx->vnic);
- for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) {
- if (vnic->fw_rss_cos_lb_ctx[i] != INVALID_HW_RING_ID)
- bnxt_hwrm_vnic_ctx_free_one(bp, vnic, i);
- }
+ bnxt_hwrm_vnic_free_one(bp, &rss_ctx->vnic);
+ for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) {
+ if (vnic->fw_rss_cos_lb_ctx[i] != INVALID_HW_RING_ID)
+ bnxt_hwrm_vnic_ctx_free_one(bp, vnic, i);
}
if (!all)
return;

View File

@ -0,0 +1,40 @@
From 602fb357b195d846887987a68024330a593ab1b9 Mon Sep 17 00:00:00 2001
From: Andreas Gruenbacher <agruenba@redhat.com>
Date: Fri, 20 Oct 2023 01:32:15 +0200
Subject: [PATCH] gfs2: Add metapath_dibh helper
[ Upstream commit 92099f0c92270c8c7a79e6bc6e0312ad248ea331 ]
Add a metapath_dibh() helper for extracting the inode's buffer head from
a metapath.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 66e5fd0..f19f031 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -317,6 +317,12 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
}
}
+static inline struct buffer_head *
+metapath_dibh(struct metapath *mp)
+{
+ return mp->mp_bh[0];
+}
+
static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp,
unsigned int x, unsigned int h)
{
@@ -661,7 +667,7 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
- struct buffer_head *dibh = mp->mp_bh[0];
+ struct buffer_head *dibh = metapath_dibh(mp);
u64 bn;
unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
size_t dblks = iomap->length >> inode->i_blkbits;

View File

@ -0,0 +1,76 @@
From 1cae1bafdf9caa9b462b19af06b1a06902e4e142 Mon Sep 17 00:00:00 2001
From: Deepanshu Kartikey <kartikey406@gmail.com>
Date: Fri, 30 Jan 2026 14:51:34 +0530
Subject: [PATCH] gfs2: Fix use-after-free in iomap inline data write path
[ Upstream commit faddeb848305e79db89ee0479bb0e33380656321 ]
The inline data buffer head (dibh) is being released prematurely in
gfs2_iomap_begin() via release_metapath() while iomap->inline_data
still points to dibh->b_data. This causes a use-after-free when
iomap_write_end_inline() later attempts to write to the inline data
area.
The bug sequence:
1. gfs2_iomap_begin() calls gfs2_meta_inode_buffer() to read inode
metadata into dibh
2. Sets iomap->inline_data = dibh->b_data + sizeof(struct gfs2_dinode)
3. Calls release_metapath() which calls brelse(dibh), dropping refcount
to 0
4. kswapd reclaims the page (~39ms later in the syzbot report)
5. iomap_write_end_inline() tries to memcpy() to iomap->inline_data
6. KASAN detects use-after-free write to freed memory
Fix by storing dibh in iomap->private and incrementing its refcount
with get_bh() in gfs2_iomap_begin(). The buffer is then properly
released in gfs2_iomap_end() after the inline write completes,
ensuring the page stays alive for the entire iomap operation.
Note: A C reproducer is not available for this issue. The fix is based
on analysis of the KASAN report and code review showing the buffer head
is freed before use.
[agruenba: Take buffer head reference in gfs2_iomap_begin() to avoid
leaks in gfs2_iomap_get() and gfs2_iomap_alloc().]
Reported-by: syzbot+ea1cd4aa4d1e98458a55@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=ea1cd4aa4d1e98458a55
Fixes: d0a22a4b03b8 ("gfs2: Fix iomap write page reclaim deadlock")
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index f19f031..05f348c 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1122,10 +1122,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
goto out_unlock;
break;
default:
- goto out_unlock;
+ goto out;
}
ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp);
+ if (ret)
+ goto out_unlock;
+
+out:
+ if (iomap->type == IOMAP_INLINE) {
+ iomap->private = metapath_dibh(&mp);
+ get_bh(iomap->private);
+ }
out_unlock:
release_metapath(&mp);
@@ -1139,6 +1147,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
+ if (iomap->private)
+ brelse(iomap->private);
+
switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) {
case IOMAP_WRITE:
if (flags & IOMAP_DIRECT)

View File

@ -0,0 +1,64 @@
From ed98cf22bd574bbcd5906e0ee217dfe65f5f8c8a Mon Sep 17 00:00:00 2001
From: Mete Durlu <mdurlu@redhat.com>
Date: Fri, 13 Mar 2026 16:09:40 +0100
Subject: [PATCH] s390/ap: Expose ap_bindings_complete_count counter via sysfs
JIRA: https://issues.redhat.com/browse/RHEL-155897
commit 51d921a613b1e89a47c2c262bbef1d7b0b032ac7
Author: Harald Freudenberger <freude@linux.ibm.com>
Date: Fri Oct 17 16:51:52 2025 +0200
s390/ap: Expose ap_bindings_complete_count counter via sysfs
The AP bus udev event BINDINGS=complete is sent out when the
first time all devices detected by the AP bus scan have been
bound to device drivers. This is the ideal time to for example
change the AP bus masks apmask and aqmask to re-establish a
persistent change on the decision about which cards/domains
should be available for the host and which should go into the
pool for kvm guests.
However, if exactly this initial udev event is sent out early
in the boot process a udev rule may not have been established
yet and thus this event will never be recognized. To have
some indication about if the AP bus binding complete has
already happened, the internal ap_bindings_complete_count
counter is exposed via sysfs with this patch.
Suggested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Mete Durlu <mdurlu@redhat.com>
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index de8a250..48ffeaf 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -1585,6 +1585,15 @@ static ssize_t bindings_show(const struct bus_type *bus, char *buf)
static BUS_ATTR_RO(bindings);
+static ssize_t bindings_complete_count_show(const struct bus_type *bus,
+ char *buf)
+{
+ return sysfs_emit(buf, "%llu\n",
+ atomic64_read(&ap_bindings_complete_count));
+}
+
+static BUS_ATTR_RO(bindings_complete_count);
+
static ssize_t features_show(const struct bus_type *bus, char *buf)
{
int n = 0;
@@ -1625,6 +1634,7 @@ static struct attribute *ap_bus_attrs[] = {
&bus_attr_aqmask.attr,
&bus_attr_scans.attr,
&bus_attr_bindings.attr,
+ &bus_attr_bindings_complete_count.attr,
&bus_attr_features.attr,
NULL,
};

View File

@ -0,0 +1,104 @@
From cd82512d5e7852beab3b8cb254c60b061fc549ac Mon Sep 17 00:00:00 2001
From: Mamatha Inamdar <minamdar@redhat.com>
Date: Thu, 30 Apr 2026 20:30:14 -0400
Subject: [PATCH] ibmveth: Disable GSO for packets with small MSS
JIRA: https://issues.redhat.com/browse/RHEL-164873
commit cc427d24ac6442ffdeafd157a63c7c5b73ed4de4
Author: Mingming Cao <mmc@linux.ibm.com>
Date: Fri Apr 24 09:29:17 2026 -0700
ibmveth: Disable GSO for packets with small MSS
Some physical adapters on Power systems do not support segmentation
offload when the MSS is less than 224 bytes. Attempting to send such
packets causes the adapter to freeze, stopping all traffic until
manually reset.
Implement ndo_features_check to disable GSO for packets with small MSS
values. The network stack will perform software segmentation instead.
The 224-byte minimum matches ibmvnic
commit <f10b09ef687f> ("ibmvnic: Enforce stronger sanity checks
on GSO packets")
which uses the same physical adapters in SEA configurations.
The issue occurs specifically when the hardware attempts to perform
segmentation (gso_segs > 1) with a small MSS. Single-segment GSO packets
(gso_segs == 1) do not trigger the problematic LSO code path and are
transmitted normally without segmentation.
Add an ndo_features_check callback to disable GSO when MSS < 224 bytes.
Also call vlan_features_check() to ensure proper handling of VLAN packets,
particularly QinQ (802.1ad) configurations where the hardware parser may
not support certain offload features.
Validated using iptables to force small MSS values. Without the fix,
the adapter freezes. With the fix, packets are segmented in software
and transmission succeeds. Comprehensive regression testing completedd
(MSS tests, performance, stability).
Fixes: 8641dd85799f ("ibmveth: Add support for TSO")
Cc: stable@vger.kernel.org
Reviewed-by: Brian King <bjking1@linux.ibm.com>
Tested-by: Shaik Abdulla <shaik.abdulla1@ibm.com>
Tested-by: Naveed Ahmed <naveedaus@in.ibm.com>
Signed-off-by: Mingming Cao <mmc@linux.ibm.com>
Link: https://patch.msgid.link/20260424162917.65725-1-mmc@linux.ibm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Mamatha Inamdar <minamdar@redhat.com>
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 7f94e84..02a95cf 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1756,6 +1756,27 @@ static int ibmveth_set_mac_addr(struct net_device *dev, void *p)
return 0;
}
+static netdev_features_t ibmveth_features_check(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
+{
+ /* Some physical adapters do not support segmentation offload with
+ * MSS < 224. Disable GSO for such packets to avoid adapter freeze.
+ * Note: Single-segment packets (gso_segs == 1) don't need this check
+ * as they bypass the LSO path and are transmitted without segmentation.
+ */
+ if (skb_is_gso(skb)) {
+ if (skb_shinfo(skb)->gso_size < IBMVETH_MIN_LSO_MSS) {
+ netdev_warn_once(dev,
+ "MSS %u too small for LSO, disabling GSO\n",
+ skb_shinfo(skb)->gso_size);
+ features &= ~NETIF_F_GSO_MASK;
+ }
+ }
+
+ return vlan_features_check(skb, features);
+}
+
static const struct net_device_ops ibmveth_netdev_ops = {
.ndo_open = ibmveth_open,
.ndo_stop = ibmveth_close,
@@ -1767,6 +1788,7 @@ static const struct net_device_ops ibmveth_netdev_ops = {
.ndo_set_features = ibmveth_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ibmveth_set_mac_addr,
+ .ndo_features_check = ibmveth_features_check,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ibmveth_poll_controller,
#endif
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index dc8aae1..059ca49 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
@@ -37,6 +37,7 @@
#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002UL
#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001UL
+#define IBMVETH_MIN_LSO_MSS 224 /* Minimum MSS for LSO */
/* hcall macros */
#define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)

View File

@ -0,0 +1,66 @@
From 532af53c2c278d6a7197be0afd8b5d3839e686e3 Mon Sep 17 00:00:00 2001
From: Mete Durlu <mdurlu@redhat.com>
Date: Thu, 16 Apr 2026 18:10:09 +0200
Subject: [PATCH] s390/mm: Add missing secure storage access fixups for donated
memory
JIRA: https://redhat.atlassian.net/browse/RHEL-168793
Conflicts: Conflicts due to rhel9 kernel version, no functional changes.
commit b00be77302d7ec4ad0367bb236494fce7172b730
Author: Janosch Frank <frankja@linux.ibm.com>
Date: Wed Mar 4 10:18:37 2026 +0000
s390/mm: Add missing secure storage access fixups for donated memory
There are special cases where secure storage access exceptions happen
in a kernel context for pages that don't have the PG_arch_1 bit
set. That bit is set for non-exported guest secure storage (memory)
but is absent on storage donated to the Ultravisor since the kernel
isn't allowed to export donated pages.
Prior to this patch we would try to export the page by calling
arch_make_folio_accessible() which would instantly return since the
arch bit is absent signifying that the page was already exported and
no further action is necessary. This leads to secure storage access
exception loops which can never be resolved.
With this patch we unconditionally try to export and if that fails we
fixup.
Fixes: 084ea4d611a3 ("s390/mm: add (non)secure page access exceptions handlers")
Reported-by: Heiko Carstens <hca@linux.ibm.com>
Suggested-by: Heiko Carstens <hca@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Tested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Mete Durlu <mdurlu@redhat.com>
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 78adfec..1fb5815 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -547,10 +547,18 @@ void do_secure_storage_access(struct pt_regs *regs)
page = phys_to_page(addr);
if (unlikely(!try_get_page(page)))
break;
- rc = arch_make_page_accessible(page);
+
+ rc = uv_convert_from_secure(addr);
+ if (!rc)
+ clear_bit(PG_arch_1, &page->flags);
put_page(page);
+ /*
+ * There are some valid fixup types for kernel
+ * accesses to donated secure memory. zeropad is one
+ * of them.
+ */
if (rc)
- BUG();
+ return handle_fault_error_nolock(regs, 0);
break;
default:
unreachable();

View File

@ -0,0 +1,107 @@
From 0a6ada5e5f985332a38b2ab39c21a5696a4cfdfb Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <jkysela@redhat.com>
Date: Thu, 23 Apr 2026 11:04:41 +0200
Subject: [PATCH] ALSA: usb-audio: Add sanity check for OOB writes at silencing
JIRA: https://issues.redhat.com/browse/RHEL-168091
commit fba2105a157fffcf19825e4eea498346738c9948
Author: Takashi Iwai <tiwai@suse.de>
Date: Mon Feb 16 15:12:07 2026 +0100
ALSA: usb-audio: Add sanity check for OOB writes at silencing
At silencing the playback URB packets in the implicit fb mode before
the actual playback, we blindly assume that the received packets fit
with the buffer size. But when the setup in the capture stream
differs from the playback stream (e.g. due to the USB core limitation
of max packet size), such an inconsistency may lead to OOB writes to
the buffer, resulting in a crash.
For addressing it, add a sanity check of the transfer buffer size at
prepare_silent_urb(), and stop the data copy if the received data
overflows. Also, report back the transfer error properly from there,
too.
Note that this doesn't fix the root cause of the playback error
itself, but this merely covers the kernel Oops.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=221076
Link: https://patch.msgid.link/20260216141209.1849200-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <jkysela@redhat.com>
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index fc6c0cc..d30d1d4 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -275,8 +275,8 @@ static inline bool has_tx_length_quirk(struct snd_usb_audio *chip)
return chip->quirk_flags & QUIRK_FLAG_TX_LENGTH;
}
-static void prepare_silent_urb(struct snd_usb_endpoint *ep,
- struct snd_urb_ctx *ctx)
+static int prepare_silent_urb(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *ctx)
{
struct urb *urb = ctx->urb;
unsigned int offs = 0;
@@ -289,28 +289,34 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep,
extra = sizeof(packet_length);
for (i = 0; i < ctx->packets; ++i) {
- unsigned int offset;
- unsigned int length;
- int counts;
-
- counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
- length = counts * ep->stride; /* number of silent bytes */
- offset = offs * ep->stride + extra * i;
- urb->iso_frame_desc[i].offset = offset;
+ int length;
+
+ length = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
+ if (length < 0)
+ return length;
+ length *= ep->stride; /* number of silent bytes */
+ if (offs + length + extra > ctx->buffer_size)
+ break;
+ urb->iso_frame_desc[i].offset = offs;
urb->iso_frame_desc[i].length = length + extra;
if (extra) {
packet_length = cpu_to_le32(length);
- memcpy(urb->transfer_buffer + offset,
+ memcpy(urb->transfer_buffer + offs,
&packet_length, sizeof(packet_length));
+ offs += extra;
}
- memset(urb->transfer_buffer + offset + extra,
+ memset(urb->transfer_buffer + offs,
ep->silence_value, length);
- offs += counts;
+ offs += length;
}
- urb->number_of_packets = ctx->packets;
- urb->transfer_buffer_length = offs * ep->stride + ctx->packets * extra;
+ if (!offs)
+ return -EPIPE;
+
+ urb->number_of_packets = i;
+ urb->transfer_buffer_length = offs;
ctx->queued = 0;
+ return 0;
}
/*
@@ -332,8 +338,7 @@ static int prepare_outbound_urb(struct snd_usb_endpoint *ep,
if (data_subs && ep->prepare_data_urb)
return ep->prepare_data_urb(data_subs, urb, in_stream_lock);
/* no data provider, so send silence */
- prepare_silent_urb(ep, ctx);
- break;
+ return prepare_silent_urb(ep, ctx);
case SND_USB_ENDPOINT_TYPE_SYNC:
if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) {

View File

@ -0,0 +1,56 @@
From 2f3e5b5a77374869a5c36c783c310be9c26493e0 Mon Sep 17 00:00:00 2001
From: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
Date: Thu, 28 May 2026 15:18:57 +0000
Subject: [PATCH] exit: prevent preemption of oopsing TASK_DEAD task
JIRA: https://redhat.atlassian.net/browse/RHEL-180008
CVE: CVE-2026-46173
Backported from tree(s): linux
commit c1fa0bb633e4a6b11e83ffc57fa5abe8ebb87891
Author: Jann Horn <jannh@google.com>
Date: Mon May 11 08:55:11 2026 -0700
exit: prevent preemption of oopsing TASK_DEAD task
When an already-exiting task oopses, make_task_dead() currently calls
do_task_dead() with preemption enabled. That is forbidden:
do_task_dead() calls __schedule(), which has a comment saying "WARNING:
must be called with preemption disabled!".
If an oopsing task is preempted in do_task_dead(), between becoming
TASK_DEAD and entering the scheduler explicitly, bad things happen:
finish_task_switch() assumes that once the scheduler has switched away
from a TASK_DEAD task, the task can never run again and its stack is no
longer needed; but that assumption apparently doesn't hold if the dead
task was preempted (the SM_PREEMPT case).
This means that the scheduler ends up repeatedly dropping references on
the dead task's stack, which can lead to use-after-free or double-free
of the entire task stack; in other words, two tasks can end up running
on the same stack, resulting in various kinds of memory corruption.
(This does not just affect "recursively oopsing" tasks; it is enough to
oops once during task exit, for example in a file_operations::release
handler)
Fixes: 7f80a2fd7db9 ("exit: Stop poorly open coding do_task_dead in make_task_dead")
Cc: stable@kernel.org
Signed-off-by: Jann Horn <jannh@google.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
diff --git a/kernel/exit.c b/kernel/exit.c
index aa08b46..6a1081a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -959,6 +959,7 @@ void __noreturn make_task_dead(int signr)
futex_exit_recursive(tsk);
tsk->exit_state = EXIT_DEAD;
refcount_inc(&tsk->rcu_users);
+ preempt_disable();
do_task_dead();
}

View File

@ -0,0 +1,35 @@
From 159f2efabc89d3f931d38f2d35876535d4abf0a3 Mon Sep 17 00:00:00 2001
From: Jason Gunthorpe <jgg@nvidia.com>
Date: Tue, 28 Apr 2026 13:17:38 -0300
Subject: [PATCH] RDMA/mana: Remove user triggerable WARN_ON() in
mana_ib_create_qp_rss()
Sashiko points out that the user can specify WQs sharing the same CQ as a
part of the uAPI and this will trigger the WARN_ON() then go on to corrupt
the kernel.
Just reject it outright and fail the QP creation.
Cc: stable@vger.kernel.org
Fixes: c15d7802a424 ("RDMA/mana_ib: Add CQ interrupt support for RAW QP")
Link: https://sashiko.dev/#/patchset/0-v2-1c49eeb88c48%2B91-rdma_udata_rep_jgg%40nvidia.com?part=1
Link: https://patch.msgid.link/r/5-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com
Reviewed-by: Long Li <longli@microsoft.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c
index 1becc87..e3c3c7e 100644
--- a/drivers/infiniband/hw/mana/cq.c
+++ b/drivers/infiniband/hw/mana/cq.c
@@ -140,8 +140,9 @@ int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq)
if (cq->queue.id >= gc->max_num_cqs)
return -EINVAL;
- /* Create CQ table entry */
- WARN_ON(gc->cq_table[cq->queue.id]);
+ /* Create CQ table entry, sharing a CQ between WQs is not supported */
+ if (gc->cq_table[cq->queue.id])
+ return -EINVAL;
if (cq->queue.kmem)
gdma_cq = cq->queue.kmem;
else

View File

@ -0,0 +1,94 @@
From 5293a8882c549fab4a878bc76b0b6c951f980a61 Mon Sep 17 00:00:00 2001
From: Chaitanya Kulkarni <kch@nvidia.com>
Date: Wed, 8 Apr 2026 00:51:31 -0700
Subject: [PATCH] nvmet-tcp: fix race between ICReq handling and queue teardown
nvmet_tcp_handle_icreq() updates queue->state after sending an
Initialization Connection Response (ICResp), but it does so without
serializing against target-side queue teardown.
If an NVMe/TCP host sends an Initialization Connection Request
(ICReq) and immediately closes the connection, target-side teardown
may start in softirq context before io_work drains the already
buffered ICReq. In that case, nvmet_tcp_schedule_release_queue()
sets queue->state to NVMET_TCP_Q_DISCONNECTING and drops the queue
reference under state_lock.
If io_work later processes that ICReq, nvmet_tcp_handle_icreq() can
still overwrite the state back to NVMET_TCP_Q_LIVE. That defeats the
DISCONNECTING-state guard in nvmet_tcp_schedule_release_queue() and
allows a later socket state change to re-enter teardown and issue a
second kref_put() on an already released queue.
The ICResp send failure path has the same problem. If teardown has
already moved the queue to DISCONNECTING, a send error can still
overwrite the state with NVMET_TCP_Q_FAILED, again reopening the
window for a second teardown path to drop the queue reference.
Fix this by serializing both post-send state transitions with
state_lock and bailing out if teardown has already started.
Use -ESHUTDOWN as an internal sentinel for that bail-out path rather
than propagating it as a transport error like -ECONNRESET. Keep
nvmet_tcp_socket_error() setting rcv_state to NVMET_TCP_RECV_ERR before
honoring that sentinel so receive-side parsing stays quiesced until the
existing release path completes.
Fixes: c46a6465bac2 ("nvmet-tcp: add NVMe over TCP target driver")
Cc: stable@vger.kernel.org
Reported-by: Shivam Kumar <skumar47@syr.edu>
Tested-by: Shivam Kumar <kumar.shivam43666@gmail.com>
Signed-off-by: Chaitanya Kulkarni <kch@nvidia.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index f899bf6..515df00 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -390,6 +390,19 @@ static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue)
static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status)
{
+ /*
+ * Keep rcv_state at RECV_ERR even for the internal -ESHUTDOWN path.
+ * nvmet_tcp_handle_icreq() can return -ESHUTDOWN after the ICReq has
+ * already been consumed and queue teardown has started.
+ *
+ * If nvmet_tcp_data_ready() or nvmet_tcp_write_space() queues
+ * nvmet_tcp_io_work() again before nvmet_tcp_release_queue_work()
+ * cancels it, the queue must not keep that old receive state.
+ * Otherwise the next nvmet_tcp_io_work() run can reach
+ * nvmet_tcp_done_recv_pdu() and try to handle the same ICReq again.
+ *
+ * That is why queue->rcv_state needs to be updated before we return.
+ */
queue->rcv_state = NVMET_TCP_RECV_ERR;
if (status == -EPIPE || status == -ECONNRESET)
kernel_sock_shutdown(queue->sock, SHUT_RDWR);
@@ -893,10 +906,25 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)
iov.iov_base = icresp;
iov.iov_len = sizeof(*icresp);
ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len);
- if (ret < 0)
+ if (ret < 0) {
+ spin_lock_bh(&queue->state_lock);
+ if (queue->state == NVMET_TCP_Q_DISCONNECTING) {
+ spin_unlock_bh(&queue->state_lock);
+ return -ESHUTDOWN;
+ }
+ queue->state = NVMET_TCP_Q_FAILED;
+ spin_unlock_bh(&queue->state_lock);
return ret; /* queue removal will cleanup */
+ }
+ spin_lock_bh(&queue->state_lock);
+ if (queue->state == NVMET_TCP_Q_DISCONNECTING) {
+ spin_unlock_bh(&queue->state_lock);
+ /* Tell nvmet_tcp_socket_error() teardown is in progress. */
+ return -ESHUTDOWN;
+ }
queue->state = NVMET_TCP_Q_LIVE;
+ spin_unlock_bh(&queue->state_lock);
nvmet_prepare_receive_pdu(queue);
return 0;
}

View File

@ -0,0 +1,39 @@
From c0b7da13a04bd70ef6070bfb9ea85f582294560a Mon Sep 17 00:00:00 2001
From: Vladimir Riabchun <ferr.lambarginio@gmail.com>
Date: Tue, 10 Feb 2026 11:08:22 +0100
Subject: [PATCH] scsi: qla2xxx: Completely fix fcport double free
In qla24xx_els_dcmd_iocb() sp->free is set to qla2x00_els_dcmd_sp_free().
When an error happens, this function is called by qla2x00_sp_release(),
when kref_put() releases the first and the last reference.
qla2x00_els_dcmd_sp_free() frees fcport by calling qla2x00_free_fcport().
Doing it one more time after kref_put() is a bad idea.
Fixes: 82f522ae0d97 ("scsi: qla2xxx: Fix double free of fcport")
Fixes: 4895009c4bb7 ("scsi: qla2xxx: Prevent command send on chip reset")
Signed-off-by: Vladimir Riabchun <ferr.lambarginio@gmail.com>
Signed-off-by: Farhat Abbas <fabbas@cloudlinux.com>
Link: https://patch.msgid.link/aYsDln9NFQQsPDgg@vova-pc
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 0b41e8a..faec66b 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2751,7 +2751,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
if (!elsio->u.els_logo.els_logo_pyld) {
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
- qla2x00_free_fcport(fcport);
return QLA_FUNCTION_FAILED;
}
@@ -2776,7 +2775,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
if (rval != QLA_SUCCESS) {
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
- qla2x00_free_fcport(fcport);
return QLA_FUNCTION_FAILED;
}

View File

@ -0,0 +1,106 @@
From 8bf586044031efd9d9883a8b63a4eb28b111fa8f Mon Sep 17 00:00:00 2001
From: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
Date: Thu, 28 May 2026 19:40:07 +0000
Subject: [PATCH] rbd: eliminate a race in lock_dwork draining on unmap
JIRA: https://redhat.atlassian.net/browse/RHEL-180190
Backported from tree(s): linux
commit 9fc75b71fdd38465c76c6f6a884cdd4ae3c72d90
Author: Ilya Dryomov <idryomov@gmail.com>
Date: Tue May 19 23:07:26 2026 +0200
rbd: eliminate a race in lock_dwork draining on unmap
Given how rbd_lock_add_request() and rbd_img_exclusive_lock() are
written, lock_dwork may be (re)queued more than it's actually needed:
for example in case a new I/O request comes in while we are in the
middle of rbd_acquire_lock() on behalf of another I/O request. This is
expected and with rbd_release_lock() preemptively canceling lock_dwork
is benign under normal operation.
A more problematic example is maybe_kick_acquire():
if (have_requests || delayed_work_pending(&rbd_dev->lock_dwork)) {
dout("%s rbd_dev %p kicking lock_dwork\n", __func__, rbd_dev);
mod_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
}
It's not unrealistic for lock_dwork to get canceled right after
delayed_work_pending() returns true and for mod_delayed_work() to
requeue it right there anyway. This is a classic TOCTOU race.
When it comes to unmapping the image, there is an implicit assumption
of no self-initiated exclusive lock activity past the point of return
from rbd_dev_image_unlock() which unlocks the lock if it happens to be
held. This unlock is assumed to be final and lock_dwork (as well as
all other exclusive lock tasks, really) isn't expected to get queued
again. However, lock_dwork is canceled only in cancel_tasks_sync()
(i.e. later in the unmap sequence) and on top of that the cancellation
can get in effect nullified by maybe_kick_acquire(). This may result
in rbd_acquire_lock() executing after rbd_dev_device_release() and
rbd_dev_image_release() run and free and/or reset a bunch of things.
One of the possible failure modes then is a violated
rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
in rbd_dev_header_info() which is called via rbd_dev_refresh() from
rbd_post_acquire_action().
Redo exclusive lock task draining to provide saner semantics and try
to meet the assumptions around rbd_dev_image_unlock().
Cc: stable@vger.kernel.org
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index c82ec46..bfa3bae 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -4547,24 +4547,12 @@ static int rbd_register_watch(struct rbd_device *rbd_dev)
return ret;
}
-static void cancel_tasks_sync(struct rbd_device *rbd_dev)
-{
- dout("%s rbd_dev %p\n", __func__, rbd_dev);
-
- cancel_work_sync(&rbd_dev->acquired_lock_work);
- cancel_work_sync(&rbd_dev->released_lock_work);
- cancel_delayed_work_sync(&rbd_dev->lock_dwork);
- cancel_work_sync(&rbd_dev->unlock_work);
-}
-
/*
* header_rwsem must not be held to avoid a deadlock with
* rbd_dev_refresh() when flushing notifies.
*/
static void rbd_unregister_watch(struct rbd_device *rbd_dev)
{
- cancel_tasks_sync(rbd_dev);
-
mutex_lock(&rbd_dev->watch_mutex);
if (rbd_dev->watch_state == RBD_WATCH_STATE_REGISTERED)
__rbd_unregister_watch(rbd_dev);
@@ -6541,10 +6529,18 @@ static int rbd_add_parse_args(const char *buf,
static void rbd_dev_image_unlock(struct rbd_device *rbd_dev)
{
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
+
+ disable_delayed_work_sync(&rbd_dev->lock_dwork);
+ disable_work_sync(&rbd_dev->unlock_work);
+
down_write(&rbd_dev->lock_rwsem);
if (__rbd_is_lock_owner(rbd_dev))
__rbd_release_lock(rbd_dev);
up_write(&rbd_dev->lock_rwsem);
+
+ flush_work(&rbd_dev->acquired_lock_work);
+ flush_work(&rbd_dev->released_lock_work);
}
/*

View File

@ -0,0 +1,224 @@
From 899ee91156e57784090c5565e4f31bd7dbffbc5a Mon Sep 17 00:00:00 2001
From: Rajat Gupta <rajat.gupta@oss.qualcomm.com>
Date: Sun, 31 May 2026 08:32:21 -0400
Subject: [PATCH] net/sched: fix pedit partial COW leading to page cache
corruption
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
tcf_pedit_act() computes the COW range for skb_ensure_writable()
once before the key loop using tcfp_off_max_hint, but the hint does
not account for the runtime header offset added by typed keys. This
can leave part of the write region un-COW'd.
Fix by moving skb_ensure_writable() inside the per-key loop where
the actual write offset is known, and add overflow checking on the
offset arithmetic. For negative offsets (e.g. Ethernet header edits
at ingress), use skb_cow() to COW the headroom instead. Guard
offset_valid() against INT_MIN, where negation is undefined.
Fixes: 8b796475fd78 ("net/sched: act_pedit: really ensure the skb is writable")
Reported-by: Yiming Qian <yimingqian591@gmail.com>
Reported-by: Keenan Dong <keenanat2000@gmail.com>
Reported-by: Han Guidong <2045gemini@gmail.com>
Reported-by: Zhang Cen <rollkingzzc@gmail.com>
Reviewed-by: Han Guidong <2045gemini@gmail.com>
Tested-by: Han Guidong <2045gemini@gmail.com>
Reviewed-by: Davide Caratti <dcaratti@redhat.com>
Tested-by: Davide Caratti <dcaratti@redhat.com>
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Toke Høiland-Jørgensen <toke@redhat.com>
Reviewed-by: Victor Nogueira <victor@mojatatu.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Rajat Gupta <rajat.gupta@oss.qualcomm.com>
Link: https://patch.msgid.link/20260531123221.48732-1-jhs@mojatatu.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h
index 83fe399..a26d4cd 100644
--- a/include/net/tc_act/tc_pedit.h
+++ b/include/net/tc_act/tc_pedit.h
@@ -14,7 +14,6 @@ struct tcf_pedit_key_ex {
struct tcf_pedit_parms {
struct tc_pedit_key *tcfp_keys;
struct tcf_pedit_key_ex *tcfp_keys_ex;
- u32 tcfp_off_max_hint;
unsigned char tcfp_nkeys;
unsigned char tcfp_flags;
struct rcu_head rcu;
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index fc0a35a..495cc56 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -16,6 +16,7 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/slab.h>
+#include <linux/overflow.h>
#include <net/ipv6.h>
#include <net/netlink.h>
#include <net/pkt_sched.h>
@@ -24,6 +25,7 @@
#include <uapi/linux/tc_act/tc_pedit.h>
#include <net/pkt_cls.h>
#include <net/tc_wrapper.h>
+#include <asm/unaligned.h>
static struct tc_action_ops act_pedit_ops;
@@ -242,7 +244,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
goto out_free_ex;
}
- nparms->tcfp_off_max_hint = 0;
nparms->tcfp_flags = parm->flags;
nparms->tcfp_nkeys = parm->nkeys;
@@ -268,14 +269,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
BITS_PER_TYPE(int) - 1,
nparms->tcfp_keys[i].shift);
- /* The AT option can read a single byte, we can bound the actual
- * value with uchar max.
- */
- cur += (0xff & offmask) >> nparms->tcfp_keys[i].shift;
-
- /* Each key touches 4 bytes starting from the computed offset */
- nparms->tcfp_off_max_hint =
- max(nparms->tcfp_off_max_hint, cur + 4);
}
p = to_pedit(*a);
@@ -318,15 +311,12 @@ static void tcf_pedit_cleanup(struct tc_action *a)
call_rcu(&parms->rcu, tcf_pedit_cleanup_rcu);
}
-static bool offset_valid(struct sk_buff *skb, int offset)
+static bool offset_valid(struct sk_buff *skb, int offset, int len)
{
- if (offset > 0 && offset > skb->len)
- return false;
-
- if (offset < 0 && -offset > skb_headroom(skb))
+ if (offset < -(int)skb_headroom(skb))
return false;
- return true;
+ return offset <= (int)skb->len - len;
}
static int pedit_l4_skb_offset(struct sk_buff *skb, int *hoffset, const int header_type)
@@ -393,18 +383,10 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
struct tcf_pedit_key_ex *tkey_ex;
struct tcf_pedit_parms *parms;
struct tc_pedit_key *tkey;
- u32 max_offset;
int i;
parms = rcu_dereference_bh(p->parms);
- max_offset = (skb_transport_header_was_set(skb) ?
- skb_transport_offset(skb) :
- skb_network_offset(skb)) +
- parms->tcfp_off_max_hint;
- if (skb_ensure_writable(skb, min(skb->len, max_offset)))
- goto done;
-
tcf_lastuse_update(&p->tcf_tm);
tcf_action_update_bstats(&p->common, skb);
@@ -412,10 +394,11 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
tkey_ex = parms->tcfp_keys_ex;
for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) {
+ int write_offset, write_len;
int offset = tkey->off;
int hoffset = 0;
- u32 *ptr, hdata;
- u32 val;
+ u32 cur_val, val;
+ u32 *ptr;
int rc;
if (tkey_ex) {
@@ -433,13 +416,15 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
if (tkey->offmask) {
u8 *d, _d;
+ int at_offset;
- if (!offset_valid(skb, hoffset + tkey->at)) {
+ if (check_add_overflow(hoffset, (int)tkey->at, &at_offset) ||
+ !offset_valid(skb, at_offset, sizeof(_d))) {
pr_info_ratelimited("tc action pedit 'at' offset %d out of bounds\n",
hoffset + tkey->at);
goto bad;
}
- d = skb_header_pointer(skb, hoffset + tkey->at,
+ d = skb_header_pointer(skb, at_offset,
sizeof(_d), &_d);
if (!d)
goto bad;
@@ -451,31 +436,51 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
}
}
- if (!offset_valid(skb, hoffset + offset)) {
- pr_info_ratelimited("tc action pedit offset %d out of bounds\n", hoffset + offset);
+ if (check_add_overflow(hoffset, offset, &write_offset)) {
+ pr_info_ratelimited("tc action pedit offset overflow\n");
goto bad;
}
- ptr = skb_header_pointer(skb, hoffset + offset,
- sizeof(hdata), &hdata);
- if (!ptr)
+ if (!offset_valid(skb, write_offset, sizeof(*ptr))) {
+ pr_info_ratelimited("tc action pedit offset %d out of bounds\n",
+ write_offset);
goto bad;
+ }
+
+ if (write_offset < 0) {
+ if (skb_cow(skb, -write_offset))
+ goto bad;
+ if (write_offset + (int)sizeof(*ptr) > 0) {
+ if (skb_ensure_writable(skb,
+ min_t(int, skb->len,
+ write_offset + (int)sizeof(*ptr))))
+ goto bad;
+ }
+ } else {
+ if (check_add_overflow(write_offset, (int)sizeof(*ptr),
+ &write_len))
+ goto bad;
+ if (skb_ensure_writable(skb, min_t(int, skb->len,
+ write_len)))
+ goto bad;
+ }
+
+ ptr = (u32 *)(skb->data + write_offset);
+ cur_val = get_unaligned(ptr);
/* just do it, baby */
switch (cmd) {
case TCA_PEDIT_KEY_EX_CMD_SET:
val = tkey->val;
break;
case TCA_PEDIT_KEY_EX_CMD_ADD:
- val = (*ptr + tkey->val) & ~tkey->mask;
+ val = (cur_val + tkey->val) & ~tkey->mask;
break;
default:
pr_info_ratelimited("tc action pedit bad command (%d)\n", cmd);
goto bad;
}
- *ptr = ((*ptr & tkey->mask) ^ val);
- if (ptr == &hdata)
- skb_store_bits(skb, hoffset + offset, ptr, 4);
+ put_unaligned((cur_val & tkey->mask) ^ val, ptr);
}
goto done;

View File

@ -176,13 +176,13 @@ Summary: The Linux kernel
# define buildid .local
%define specversion 5.14.0
%define patchversion 5.14
%define pkgrelease 687.15.1
%define pkgrelease 687.17.1
%define kversion 5
%define tarfile_release 5.14.0-687.5.1.el9_8
# This is needed to do merge window version magic
%define patchlevel 14
# This allows pkg_release to have configurable %%{?dist} tag
%define specrelease 687.15.1%{?buildid}%{?dist}
%define specrelease 687.17.1%{?buildid}%{?dist}
# This defines the kabi tarball version
%define kabiversion 5.14.0-687.5.1.el9_8
@ -1162,6 +1162,33 @@ Patch1281: 1281-ipv6-rpl-headroom.patch
Patch1282: 1282-rdma-mlx4-srq.patch
Patch1283: 1283-dpll-series-RHEL.patch
Patch1284: 1284-ice-rss-queues-RHEL.patch
Patch1285: 1285-xen-privcmd-fix-double-free-via-vma-splitting.patch
Patch1286: 1286-bluetooth-hci-sync-fix-stack-buffer-overflow-in-hci-le-big-c.patch
Patch1287: 1287-can-isotp-fix-tx-buf-use-after-free-in-isotp-sendmsg.patch
Patch1288: 1288-dpll-add-pin-operational-state.patch
Patch1289: 1289-dpll-zl3073x-implement-pin-operational-state-reporting.patch
Patch1290: 1290-dpll-add-fractional-frequency-offset-to-pin-parent-device.patch
Patch1291: 1291-dpll-zl3073x-report-ffo-as-dpll-vs-input-reference-offset.patch
Patch1292: 1292-mptcp-fix-slab-use-after-free-in-inet-lookup-established.patch
Patch1293: 1293-ice-fix-null-pointer-dereference-in-ice-vsi-set-napi-queues.patch
Patch1294: 1294-bluetooth-hci-event-fix-potential-uaf-in-ssp-passkey-handler.patch
Patch1295: 1295-wifi-mac80211-use-safe-list-iteration-in-radar-detect-work.patch
Patch1296: 1296-wifi-mac80211-drop-stray-static-from-fast-rx-rx-result.patch
Patch1297: 1297-rdma-mana-validate-rx-hash-key-len.patch
Patch1298: 1298-wifi-mac80211-remove-station-if-connection-prep-fails.patch
Patch1299: 1299-bnxt-en-fix-rss-context-delete-logic.patch
Patch1300: 1300-gfs2-add-metapath-dibh-helper.patch
Patch1301: 1301-gfs2-fix-use-after-free-in-iomap-inline-data-write-path.patch
Patch1302: 1302-s390-ap-expose-ap-bindings-complete-count-counter-via-sysfs.patch
Patch1303: 1303-ibmveth-disable-gso-for-packets-with-small-mss.patch
Patch1304: 1304-s390-mm-add-missing-secure-storage-access-fixups-for-donated.patch
Patch1305: 1305-alsa-usb-audio-add-sanity-check-for-oob-writes-at-silencing.patch
Patch1306: 1306-exit-prevent-preemption-of-oopsing-task-dead-task.patch
Patch1307: 1307-rdma-mana-remove-user-triggerable-warn-on-in-mana-ib-create-.patch
Patch1308: 1308-nvmet-tcp-fix-race-between-icreq-handling-and-queue-teardown.patch
Patch1309: 1309-scsi-qla2xxx-completely-fix-fcport-double-free.patch
Patch1310: 1310-rbd-eliminate-a-race-in-lock-dwork-draining-on-unmap.patch
Patch1311: 1311-net-sched-fix-pedit-partial-cow-leading-to-page-cache-corrup.patch
# END OF PATCH DEFINITIONS
%description
@ -2091,6 +2118,33 @@ ApplyPatch 1281-ipv6-rpl-headroom.patch
ApplyPatch 1282-rdma-mlx4-srq.patch
ApplyPatch 1283-dpll-series-RHEL.patch
ApplyPatch 1284-ice-rss-queues-RHEL.patch
ApplyPatch 1285-xen-privcmd-fix-double-free-via-vma-splitting.patch
ApplyPatch 1286-bluetooth-hci-sync-fix-stack-buffer-overflow-in-hci-le-big-c.patch
ApplyPatch 1287-can-isotp-fix-tx-buf-use-after-free-in-isotp-sendmsg.patch
ApplyPatch 1288-dpll-add-pin-operational-state.patch
ApplyPatch 1289-dpll-zl3073x-implement-pin-operational-state-reporting.patch
ApplyPatch 1290-dpll-add-fractional-frequency-offset-to-pin-parent-device.patch
ApplyPatch 1291-dpll-zl3073x-report-ffo-as-dpll-vs-input-reference-offset.patch
ApplyPatch 1292-mptcp-fix-slab-use-after-free-in-inet-lookup-established.patch
ApplyPatch 1293-ice-fix-null-pointer-dereference-in-ice-vsi-set-napi-queues.patch
ApplyPatch 1294-bluetooth-hci-event-fix-potential-uaf-in-ssp-passkey-handler.patch
ApplyPatch 1295-wifi-mac80211-use-safe-list-iteration-in-radar-detect-work.patch
ApplyPatch 1296-wifi-mac80211-drop-stray-static-from-fast-rx-rx-result.patch
ApplyPatch 1297-rdma-mana-validate-rx-hash-key-len.patch
ApplyPatch 1298-wifi-mac80211-remove-station-if-connection-prep-fails.patch
ApplyPatch 1299-bnxt-en-fix-rss-context-delete-logic.patch
ApplyPatch 1300-gfs2-add-metapath-dibh-helper.patch
ApplyPatch 1301-gfs2-fix-use-after-free-in-iomap-inline-data-write-path.patch
ApplyPatch 1302-s390-ap-expose-ap-bindings-complete-count-counter-via-sysfs.patch
ApplyPatch 1303-ibmveth-disable-gso-for-packets-with-small-mss.patch
ApplyPatch 1304-s390-mm-add-missing-secure-storage-access-fixups-for-donated.patch
ApplyPatch 1305-alsa-usb-audio-add-sanity-check-for-oob-writes-at-silencing.patch
ApplyPatch 1306-exit-prevent-preemption-of-oopsing-task-dead-task.patch
ApplyPatch 1307-rdma-mana-remove-user-triggerable-warn-on-in-mana-ib-create-.patch
ApplyPatch 1308-nvmet-tcp-fix-race-between-icreq-handling-and-queue-teardown.patch
ApplyPatch 1309-scsi-qla2xxx-completely-fix-fcport-double-free.patch
ApplyPatch 1310-rbd-eliminate-a-race-in-lock-dwork-draining-on-unmap.patch
ApplyPatch 1311-net-sched-fix-pedit-partial-cow-leading-to-page-cache-corrup.patch
# END OF PATCH APPLICATIONS
# Any further pre-build tree manipulations happen here.
@ -4165,6 +4219,42 @@ fi
#
#
%changelog
* Mon Jun 22 2026 Andrew Lukoshko <alukoshko@almalinux.org> - 5.14.0-687.17.1
- Recreate RHEL 5.14.0-687.17.1 from CentOS Stream 9 and upstream stable backports (1285-1311)
- RHEL changelog for 687.16.1..687.17.1 follows:
* Thu Jun 18 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-687.17.1.el9_8]
- net/sched: fix pedit partial COW leading to page cache corruption (Ivan Vecera) [RHEL-177392] {CVE-2026-46331}
- gitlab-ci: use rhel9.8 builder image (Michael Krausch-Hofmann)
- rbd: eliminate a race in lock_dwork draining on unmap (CKI Backport Bot) [RHEL-183130]
- scsi: qla2xxx: Completely fix fcport double free (Ewan D. Milne) [RHEL-179754] {CVE-2026-43414}
- nvmet-tcp: fix race between ICReq handling and queue teardown (Chris Leech) [RHEL-180102] {CVE-2026-46135}
- RDMA/mana: Remove user triggerable WARN_ON() in mana_ib_create_qp_rss() (CKI Backport Bot) [RHEL-180158] {CVE-2026-46117}
- exit: prevent preemption of oopsing TASK_DEAD task (CKI Backport Bot) [RHEL-180016] {CVE-2026-46173}
- ALSA: usb-audio: Add sanity check for OOB writes at silencing (CKI Backport Bot) [RHEL-173941] {CVE-2026-43279}
* Tue Jun 16 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-687.16.1.el9_8]
- s390/mm: Add missing secure storage access fixups for donated memory (Jan Polensky) [RHEL-183317]
- ibmveth: Disable GSO for packets with small MSS (Mamatha Inamdar) [RHEL-178308]
- s390/ap: Expose ap_bindings_complete_count counter via sysfs (Jan Polensky) [RHEL-166048]
- gfs2: Fix use-after-free in iomap inline data write path (Andrew Price) [RHEL-179589] {CVE-2026-45984}
- gfs2: Add metapath_dibh helper (Andrew Price) [RHEL-179589] {CVE-2026-45984}
- bnxt_en: Fix RSS context delete logic (CKI Backport Bot) [RHEL-180308] {CVE-2026-43260}
- wifi: mac80211: remove station if connection prep fails (CKI Backport Bot) [RHEL-180121] {CVE-2026-46125}
- RDMA/mana: Validate rx_hash_key_len (CKI Backport Bot) [RHEL-180085] {CVE-2026-46145}
- wifi: mac80211: drop stray 'static' from fast-RX rx_result (CKI Backport Bot) [RHEL-180057] {CVE-2026-46152}
- wifi: mac80211: use safe list iteration in radar detect work (CKI Backport Bot) [RHEL-180025] {CVE-2026-46166}
- Bluetooth: hci_event: fix potential UAF in SSP passkey handlers (CKI Backport Bot) [RHEL-179359] {CVE-2026-46056}
- ice: Fix NULL pointer dereference in ice_vsi_set_napi_queues (CKI Backport Bot) [RHEL-175699]
- mptcp: fix slab-use-after-free in __inet_lookup_established (Davide Caratti) [RHEL-171506] {CVE-2026-31669}
- dpll: zl3073x: report FFO as DPLL vs input reference offset (Ivan Vecera) [RHEL-175823]
- dpll: add fractional frequency offset to pin-parent-device (Ivan Vecera) [RHEL-175823]
- dpll: zl3073x: implement pin operational state reporting (Ivan Vecera) [RHEL-175820]
- dpll: add pin operational state (Ivan Vecera) [RHEL-175820]
- can: isotp: fix tx.buf use-after-free in isotp_sendmsg() (CKI Backport Bot) [RHEL-175525] {CVE-2026-31474}
- Bluetooth: hci_sync: fix stack buffer overflow in hci_le_big_create_sync (CKI Backport Bot) [RHEL-172858] {CVE-2026-31772}
- xen/privcmd: fix double free via VMA splitting (CKI Backport Bot) [RHEL-172488] {CVE-2026-31787}
* Wed Jun 11 2026 Andrew Lukoshko <alukoshko@almalinux.org> - 5.14.0-687.15.1
- Recreate RHEL 5.14.0-687.15.1 from CentOS Stream 9 and upstream stable backports (1270-1284)
- redhat: Remove the mlx5 symbols from kabi: applied via updated Module.kabi_{aarch64,s390x,x86_64} (RHEL-181822)