7.1.8-rc1 review
Subsystems (3)
Greg Kroah-Hartman
maintainerPATCH 122/438 net: ethernet: mtk_eth_soc: pass eth to mtk_handle_irq_rx in poll_controller
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
[ Upstream commit e095f249e2209674f6366f6db0383a2b96e19239 ]
mtk_handle_irq_rx expects a struct mtk_eth * (matching the request_irq cookie), but mtk_poll_controller incorrectly passed the net_device *. Calling ndo_poll_controller with CONFIG_NET_POLL_CONTROLLER enabled would then crash.
--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +1 -1
@@ -3467,7 +3467,7 @@ static void mtk_poll_controller(struct net_device *dev)mtk_tx_irq_disable (eth,MTK_TX_DONE_INT );mtk_rx_irq_disable (eth, eth->soc->rx.irq_done_mask); -mtk_handle_irq_rx (eth->irq[MTK_FE_IRQ_RX ], dev); +mtk_handle_irq_rx (eth->irq[MTK_FE_IRQ_RX ], eth);mtk_tx_irq_enable (eth,MTK_TX_DONE_INT );mtk_rx_irq_enable (eth, eth->soc->rx.irq_done_mask); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 123/438 hwmon: (pmbus) Fix return value from pmbus_update_byte_data()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit a19038a200f18d9e74ac30081797917d0886e16b ]
pmbus_update_byte_data() is supposed to return a negative error code or 0. However, if no change is made to the register, it actually returns the register value. This can result in problems if the calling code explicitly expects to see an error code or 0.
Fix it to return 0 on success or the error code as expected.
--- drivers/hwmon/pmbus/pmbus_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/pmbus/pmbus_core.c +1 -1
@@ -513,7 +513,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,if (tmp != rv) rv =_pmbus_write_byte_data (client, page, reg, tmp); -return rv; +return rv <0 ? rv :0 ; }EXPORT_SYMBOL_NS_GPL (pmbus_update_byte_data,"PMBUS" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 124/438 idpf: bound interrupt-vector register fill to the allocated array
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 9f7007ee9858c99aa43101bc8352c672fee85644 ]
idpf_get_reg_intr_vecs() fills the caller-allocated reg_vals[] array from the VIRTCHNL2_OP_ALLOC_VECTORS reply in adapter->req_vec_chunks, bounding its inner loop only by the per-chunk num_vectors. The array is sized
separately: idpf_intr_reg_init() allocates kzalloc_objs(struct idpf_vec_regs, total_vecs) from caps.num_allocated_vectors and only checks the returned count after the fill. The sum of per-chunk num_vectors is never reconciled against total_vecs, so a reply with a small num_allocated_vectors but chunks summing higher writes past the end of reg_vals[].
Impact: a control plane (a PF or hypervisor device model) that returns a VIRTCHNL2_OP_ALLOC_VECTORS reply whose per-chunk num_vectors sum exceeds num_allocated_vectors writes struct idpf_vec_regs entries past the end of the reg_vals kmalloc allocation (KASAN slab-out-of-bounds write).
Bound the fill loop to the array capacity passed in by the callers, mirroring the sibling idpf_vport_get_q_reg(). The existing num_regs < num_vecs check then rejects an undersized reply without the out-of-bounds write happening first.
--- drivers/net/ethernet/intel/idpf/idpf_dev.c | 2 +- drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 2 +- drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 5 +++-- drivers/net/ethernet/intel/idpf/idpf_virtchnl.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-)
drivers/net/ethernet/intel/idpf/idpf_dev.c +1 -1
@@ -87,7 +87,7 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,if (!reg_vals)return -ENOMEM ; - num_regs =idpf_get_reg_intr_vecs (adapter, reg_vals); + num_regs =idpf_get_reg_intr_vecs (adapter, reg_vals, total_vecs);if (num_regs < num_vecs) { err = -EINVAL ; goto free_reg_vals;
drivers/net/ethernet/intel/idpf/idpf_vf_dev.c +1 -1
@@ -86,7 +86,7 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,if (!reg_vals)return -ENOMEM ; - num_regs =idpf_get_reg_intr_vecs (adapter, reg_vals); + num_regs =idpf_get_reg_intr_vecs (adapter, reg_vals, total_vecs);if (num_regs < num_vecs) { err = -EINVAL ; goto free_reg_vals;
drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +3 -2
@@ -1318,11 +1318,12 @@ idpf_vport_init_queue_reg_chunks(struct idpf_vport_config *vport_config,* idpf_get_reg_intr_vecs - Get vector queue register offset * @adapter: adapter structure to get the vector chunks * @reg_vals: Register offsets to store in +* @num_vecs: number of entries the @reg_vals array can hold * * Return: number of registers that got populated */ int idpf_get_reg_intr_vecs (struct idpf_adapter *adapter, -struct idpf_vec_regs *reg_vals) +struct idpf_vec_regs *reg_vals,int num_vecs) {struct virtchnl2_vector_chunks *chunks;struct idpf_vec_regs reg_val;
@@ -1346,7 +1347,7 @@ int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter, dynctl_reg_spacing =le32_to_cpu (chunk->dynctl_reg_spacing); itrn_reg_spacing =le32_to_cpu (chunk->itrn_reg_spacing); -for (i =0 ; i < num_vec; i++) { +for (i =0 ; i < num_vec && num_regs < num_vecs; i++) { reg_vals[num_regs].dyn_ctl_reg = reg_val.dyn_ctl_reg; reg_vals[num_regs].itrn_reg = reg_val.itrn_reg; reg_vals[num_regs].itrn_index_spacing =
drivers/net/ethernet/intel/idpf/idpf_virtchnl.h +1 -1
@@ -104,7 +104,7 @@ int idpf_vc_core_init(struct idpf_adapter *adapter);void idpf_vc_core_deinit (struct idpf_adapter *adapter);int idpf_get_reg_intr_vecs (struct idpf_adapter *adapter, -struct idpf_vec_regs *reg_vals); +struct idpf_vec_regs *reg_vals,int num_vecs);int idpf_queue_reg_init (struct idpf_vport *vport,struct idpf_q_vec_rsrc *rsrc,struct idpf_queue_id_reg_info *chunks);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 125/438 idpf: adjust TxQ ring count minimum
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Hay <[email protected]>
[ Upstream commit bef152db47debcd14cbacefc5767f6f026c4bc89 ]
Set the TxQ ring count minimum to 128 descriptors. Any lower than this, and the queue will stall and trigger Tx timeouts in flow based scheduling mode. This is because next_to_clean might never be updated.
In flow based scheduling mode, next_to_clean is only updated after a descriptor completion is processed, i.e. after the RE bit is set in the last descriptor of a Tx packet. This will never happen with a ring size of 64 and an IDPF_TX_SPLITQ_RE_MIN_GAP of 64. No matter what the value of last_re is initialized/set to, the calculated gap will be at most 63 and never trigger the RE bit.
Even a ring size of 96 does not solve this. Because of how infrequent next_to_clean is updated and how small the ring is, IDPF_DESC_UNUSED will be much smaller on average. This increases the chance the queue will be stopped because a multi-descriptor packet, e.g. a large LSO packet, does not see enough resources on the ring. In this case, the queue will trigger the stop logic. The queue permanently stalls because there is no chance for a descriptor completion to update next_to_clean since it is dependent on a packet being sent.
--- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 5 +---- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-)
drivers/net/ethernet/intel/idpf/idpf_txrx.c +1 -4
@@ -3097,10 +3097,7 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, tx_params.dtype =IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE ; tx_params.eop_cmd =IDPF_TXD_FLEX_FLOW_CMD_EOP ; -/* Set the RE bit to periodically "clean" the descriptor ring. -* MIN_GAP is set to MIN_RING size to ensure it will be set at -* least once each time around the ring. -*/ +/* Set the RE bit periodically to "clean" the descriptor ring */ if (idpf_tx_splitq_need_re (tx_q)) { tx_params.eop_cmd |=IDPF_TXD_FLEX_FLOW_CMD_RE ; tx_q->txq_grp->num_completions_pending++;
drivers/net/ethernet/intel/idpf/idpf_txrx.h +1 -1
@@ -21,7 +21,7 @@/* Mailbox Queue */ #define IDPF_MAX_MBXQ 1 -#define IDPF_MIN_TXQ_DESC 64 +#define IDPF_MIN_TXQ_DESC 128#define IDPF_MIN_RXQ_DESC 64#define IDPF_MIN_TXQ_COMPLQ_DESC 256#define IDPF_MAX_QIDS 256
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 126/438 idpf: Fix mailbox IRQ name leak on request failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 9bff30482c10f70d9e56c0633a6616e07140e217 ]
idpf_mb_intr_req_irq() allocates the mailbox IRQ name before calling request_irq(). On success, the name is released later through kfree(free_irq()), but request_irq() failure returns without freeing it.
Free the allocated name on the request_irq() failure path.
--- drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/idpf/idpf_lib.c +1 -1
@@ -139,7 +139,7 @@ static int idpf_mb_intr_req_irq(struct idpf_adapter *adapter)if (err) {dev_err (&adapter->pdev->dev,"IRQ request for mailbox failed, error: %d\n" , err); - +kfree (name);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 127/438 ice: suppress DPLL errors during reset recovery
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Przemyslaw Korba <[email protected]>
[ Upstream commit b00be7c6b4bd7da3d510753b27ff6cb7ec647d07 ]
During reset recovery, the admin queue returns EBUSY which is expected behavior. However, the DPLL subsystem was logging these as errors and incrementing the error counter, potentially leading to unnecessary warnings and even disabling the DPLL periodic worker if the threshold was reached.
Suppress error logging and error counter increments when the admin queue returns EBUSY, as this is expected during reset recovery and not a real failure condition.
test case:
- ethtool --reset eth3 irq-shared dma-shared filter-shared offload-shared mac-shared phy-shared ram-shared
- observe if dmesg EBUSY errors are gone
--- drivers/net/ethernet/intel/ice/ice_dpll.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
drivers/net/ethernet/intel/ice/ice_dpll.c +12 -7
@@ -784,7 +784,7 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, ret,libie_aq_str (pf->hw.adminq.sq_last_status), pin_type_name[pin_type], pin->idx); - else + else if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY) dev_err_ratelimited(ice_pf_to_dev(pf),"err:%d %s failed to update %s pin:%u\n" , ret,
@@ -2821,7 +2821,8 @@ static int ice_dpll_pps_update_phase_offsets(struct ice_pf *pf, *phase_offset_pins_updated =0 ; ret =ice_aq_get_cgu_input_pin_measure (&pf->hw,DPLL_TYPE_PPS , meas,ARRAY_SIZE (meas)); -if (ret && pf->hw.adminq.sq_last_status ==LIBIE_AQ_RC_EAGAIN ) { +if (ret && (pf->hw.adminq.sq_last_status ==LIBIE_AQ_RC_EAGAIN || + pf->hw.adminq.sq_last_status ==LIBIE_AQ_RC_EBUSY )) {return 0 ; }else if (ret) { dev_err(ice_pf_to_dev(pf),
@@ -2883,10 +2884,12 @@ ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) d->dpll_idx, d->prev_input_idx, d->input_idx, d->dpll_state, d->prev_dpll_state, d->mode);if (ret) { -dev_err (ice_pf_to_dev (pf), -"update dpll=%d state failed, ret=%d %s\n" , - d->dpll_idx, ret, -libie_aq_str (pf->hw.adminq.sq_last_status)); +/* EBUSY is expected during reset recovery, don't log error */ +if (pf->hw.adminq.sq_last_status !=LIBIE_AQ_RC_EBUSY ) +dev_err (ice_pf_to_dev (pf), +"update dpll=%d state failed, ret=%d %s\n" , + d->dpll_idx, ret, +libie_aq_str (pf->hw.adminq.sq_last_status));return ret; }if (init) {
@@ -2955,7 +2958,9 @@ static void ice_dpll_periodic_work(struct kthread_work *work) d->periodic_counter % dp->phase_offset_monitor_period == 0) ret =ice_dpll_pps_update_phase_offsets (pf, &phase_offset_ntf);if (ret) { - d->cgu_state_acq_err_num++; +/* EBUSY is expected during reset recovery */ +if (pf->hw.adminq.sq_last_status !=LIBIE_AQ_RC_EBUSY ) + d->cgu_state_acq_err_num++;/* stop rescheduling this worker */ if (d->cgu_state_acq_err_num >ICE_CGU_STATE_ACQ_ERR_THRESHOLD ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 128/438 Bluetooth: ISO: clear iso_data always when detaching conn from hcon
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit d57e506f6a1e3929611340fae87c1e4823f4d85c ]
When setting conn->hcon = NULL, also conn->hcon->iso_data = NULL is necessary, otherwise later iso_conn_free() will UAF.
Fix clearing of iso_data in iso_sock_disconn()
Fixes KASAN: slab-use-after-free in iso_conn_hold_unless_zero on iso_sock_release() followed by hci_abort_conn_sync().
--- net/bluetooth/iso.c | 1 + 1 file changed, 1 insertion(+)
net/bluetooth/iso.c +1 -0
@@ -836,6 +836,7 @@ static void iso_sock_disconn(struct sock *sk) sk->sk_state =BT_DISCONN ;iso_conn_lock (iso_pi (sk)->conn);hci_conn_drop (iso_pi (sk)->conn->hcon); +iso_pi (sk)->conn->hcon->iso_data =NULL ;iso_pi (sk)->conn->hcon =NULL ;iso_conn_unlock (iso_pi (sk)->conn); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 129/438 Bluetooth: L2CAP: fix UAF in l2cap_le_connect_rsp
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiale Yao <[email protected]>
[ Upstream commit c4740e7f23ff9a8210198d8b4703259e21b9f69d ]
l2cap_le_connect_rsp() obtains a channel via __l2cap_get_chan_by_ident() but neither holds a reference nor uses l2cap_chan_hold_unless_zero() before locking and operating on it. A concurrent l2cap_chan_del() triggered by a remote disconnect can free the channel between the lookup and l2cap_chan_lock(), causing a use-after-free.
The BR/EDR counterpart l2cap_connect_rsp() and the sibling handler l2cap_le_command_rej() already use l2cap_chan_hold_unless_zero() to safely hold a reference, but l2cap_le_connect_rsp() was left unprotected.
Fix by adding l2cap_chan_hold_unless_zero() after the ident lookup and l2cap_chan_put() on the exit path, consistent with other L2CAP response handlers.
--- net/bluetooth/l2cap_core.c | 5 +++++ 1 file changed, 5 insertions(+)
net/bluetooth/l2cap_core.c +5 -0
@@ -4823,6 +4823,10 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,if (!chan)return -EBADSLT ; + chan =l2cap_chan_hold_unless_zero (chan); +if (!chan) +return -EBADSLT ; + err =0 ;l2cap_chan_lock (chan);
@@ -4868,6 +4872,7 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn, }l2cap_chan_unlock (chan); +l2cap_chan_put (chan);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 130/438 Bluetooth: ISO: fix CONNECTED -> CLOSED transition on shutdown/release
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 0786469ee242952008628ed0e2d386098e2065ab ]
Commit d57e506f6a1e ("Bluetooth: ISO: clear iso_data always when detaching conn from hcon") merged a version of the UAF fix that breaks releasing connected
ISO sockets. Since hci_conn::iso_data is set to NULL, iso_chan_del() won't be called when the hci_conn disconnects, and the ISO socket does not emit POLLHUP correctly.
Fix by retaining full hci_conn <-> iso_conn association while in BT_DISCONNECT state, so that local disconnect via shutdown() follows similar ISO socket code path as remote disconnect. Use a separate flag to track whether hci_conn_drop() is needed, instead of setting iso_conn::hcon = NULL
In iso_sock_ready(), disallow disconnecting socket going BT_CONNECTED, in case hcon connects while its drop is pending.
--- net/bluetooth/iso.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
net/bluetooth/iso.c +20 -6
@@ -23,8 +23,14 @@ static struct bt_sock_list iso_sk_list = { };/* ---- ISO connections ---- */ +enum { +ISO_CONN_DROPPED , + __ISO_CONN_NUM_FLAGS +}; +struct iso_conn {struct hci_conn *hcon; + DECLARE_BITMAP(flags, __ISO_CONN_NUM_FLAGS);/* @lock: spinlock protecting changes to iso_conn fields */ spinlock_t lock;
@@ -106,7 +112,8 @@ static void iso_conn_free(struct kref *ref)if (conn->hcon) { conn->hcon->iso_data =NULL ; -hci_conn_drop (conn->hcon); +if (!test_and_set_bit (ISO_CONN_DROPPED , conn->flags)) +hci_conn_drop (conn->hcon); }/* Ensure no more work items will run since hci_conn has been dropped */
@@ -305,6 +312,7 @@ static int __iso_chan_add(struct iso_conn *conn, struct sock *sk,iso_pi (sk)->conn = conn; conn->sk = sk; +clear_bit (ISO_CONN_DROPPED , conn->flags);if (parent)bt_accept_enqueue (parent, sk, true);
@@ -834,11 +842,8 @@ static void iso_sock_disconn(struct sock *sk) } sk->sk_state =BT_DISCONN ; -iso_conn_lock (iso_pi (sk)->conn); -hci_conn_drop (iso_pi (sk)->conn->hcon); -iso_pi (sk)->conn->hcon->iso_data =NULL ; -iso_pi (sk)->conn->hcon =NULL ; -iso_conn_unlock (iso_pi (sk)->conn); +if (!test_and_set_bit (ISO_CONN_DROPPED ,iso_pi (sk)->conn->flags)) +hci_conn_drop (iso_pi (sk)->conn->hcon); }static void __iso_sock_close (struct sock *sk)
@@ -2041,9 +2046,18 @@ static void iso_sock_ready(struct sock *sk)return ;lock_sock (sk); + +switch (sk->sk_state) { +case BT_DISCONN : +case BT_CLOSED : +release_sock (sk); +return ; + } +iso_sock_clear_timer (sk); sk->sk_state =BT_CONNECTED ; sk->sk_state_change (sk); +release_sock (sk); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 131/438 Bluetooth: ISO: lock sk in iso_sock_getname
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 89cf154d7c18e6e94a3da83051f3cf2bac317ae2 ]
Accessing iso_pi(sk)->conn requires lock_sock, which is not held here.
Fix by adding the lock/release.
--- net/bluetooth/iso.c | 4 ++++ 1 file changed, 4 insertions(+)
net/bluetooth/iso.c +4 -0
@@ -1471,6 +1471,8 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr,BT_DBG ("sock %p, sk %p" , sock, sk); +lock_sock (sk); + addr->sa_family =AF_BLUETOOTH ;if (peer) {
@@ -1492,6 +1494,8 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr, sa->iso_bdaddr_type =iso_pi (sk)->src_type; } +release_sock (sk); +return len; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 132/438 Bluetooth: ISO: lock sk in iso_connect_ind
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 4311fd6f429065a8ba208660360a895627a00cf3 ]
Accessing iso_pi(sk)->conn requires lock_sock, which is not taken in the "ev3" part of iso_connect_ind. It may also be NULL if socket has transitioned away from the LISTEN/CONNECT states before locking.
Fix by adding lock/release. Recheck hcon is valid after lock acquire where needed.
--- net/bluetooth/iso.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
net/bluetooth/iso.c +11 -8
@@ -2368,7 +2368,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)lock_sock (sk); - hcon =iso_pi (sk)->conn->hcon; + hcon =iso_pi (sk)->conn ?iso_pi (sk)->conn->hcon :NULL ;iso_pi (sk)->qos.bcast.encryption = ev2->encryption;if (ev2->num_bis <iso_pi (sk)->bc_num_bis)
@@ -2408,9 +2408,11 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)if (!sk) goto done; - hcon =iso_pi (sk)->conn->hcon; +lock_sock (sk); + + hcon =iso_pi (sk)->conn ?iso_pi (sk)->conn->hcon :NULL ;if (!hcon) - goto done; + goto release3;if (ev3->data_status ==LE_PA_DATA_TRUNCATED ) {/* The controller was unable to retrieve PA data. */
@@ -2418,12 +2420,12 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) HCI_MAX_PER_AD_TOT_LEN); hcon->le_per_adv_data_len =0 ; hcon->le_per_adv_data_offset =0 ; - goto done; + goto release3; }if (hcon->le_per_adv_data_offset + ev3->length >HCI_MAX_PER_AD_TOT_LEN ) - goto done; + goto release3;memcpy (hcon->le_per_adv_data + hcon->le_per_adv_data_offset, ev3->data, ev3->length);
@@ -2442,18 +2444,19 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) &base_len);if (!base || base_len >BASE_MAX_LENGTH ) - goto done; + goto release3; -lock_sock (sk);memcpy (iso_pi (sk)->base, base, base_len);iso_pi (sk)->base_len = base_len; -release_sock (sk); }else {/* This is a PA data fragment. Keep pa_data_len set to 0 * until all data has been reassembled. */ hcon->le_per_adv_data_len =0 ; } + +release3: +release_sock (sk); }else { sk =iso_get_sock (hdev, &hdev->bdaddr,BDADDR_ANY ,BT_LISTEN , iso_match_dst,BDADDR_ANY );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 133/438 Bluetooth: ISO: fix timeout vs sync_timeout typo in check_bcast_qos
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit e9cb51813d79fc9aae4a2098aab3ab6ebd7fb6c8 ]
In iso.c check_bcast_qos(), missing bcast.timeout is not set to its default value, and appears typoed as bcast.sync_timeout.
Fix the typo.
--- net/bluetooth/iso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/iso.c +1 -1
@@ -1795,7 +1795,7 @@ static bool check_bcast_qos(struct bt_iso_qos *qos)return false;if (!qos->bcast.timeout) - qos->bcast.sync_timeout =BT_ISO_SYNC_TIMEOUT ; + qos->bcast.timeout =BT_ISO_SYNC_TIMEOUT ;if (qos->bcast.timeout <0x000a || qos->bcast.timeout >0x4000 )return false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 134/438 Bluetooth: ISO: validate sockaddr_iso first in iso_sock_rebind_bis()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 4e20192d46a685d73e590a60a4a2419a0a8afcbf ]
iso_sock_rebind_bis() updates socket iso_pi(sk)->bc_num_bis before validating the BIS values, so it's possible to end up with bc_num_bis inconsistent.
Assign to iso_pi(sk)->bc_num_bis only after validation.
--- net/bluetooth/iso.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/bluetooth/iso.c +3 -3
@@ -1038,15 +1038,15 @@ static int iso_sock_rebind_bis(struct sock *sk, struct sockaddr_iso *sa, goto done; } -iso_pi (sk)->bc_num_bis = sa->iso_bc->bc_num_bis; - -for (int i =0 ; i <iso_pi (sk)->bc_num_bis; i++) +for (int i =0 ; i < sa->iso_bc->bc_num_bis; i++)if (sa->iso_bc->bc_bis[i] <0x01 || sa->iso_bc->bc_bis[i] >0x1f ) { err = -EINVAL ; goto done; } +iso_pi (sk)->bc_num_bis = sa->iso_bc->bc_num_bis; +memcpy (iso_pi (sk)->bc_bis, sa->iso_bc->bc_bis,iso_pi (sk)->bc_num_bis);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 135/438 Bluetooth: ISO: hold sk properly in iso_conn_ready
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 0d255e63fcf3f13a570d7ac11678fa1164ac015c ]
sk deref in iso_conn_ready must be done either under conn->lock, or holding a refcount, to avoid concurrent close. conn->sk is currently accessed without either:
[Task 1] [Task 2]
iso_sock_release
iso_conn_ready
sk = conn->sk
lock_sock(sk)
conn->sk = NULL
lock_sock(sk)
release_sock(sk)
iso_sock_kill(sk)
UAF on sk deref
Fix possible UAF by holding sk refcount in iso_conn_ready(). Also recheck after lock_sock that the socket is still valid. Adjust locking so conn->sk is cleared only under lock_sock.
--- net/bluetooth/iso.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-)
net/bluetooth/iso.c +23 -11
@@ -804,11 +804,13 @@ static void iso_sock_kill(struct sock *sk)BT_DBG ("sk %p state %d" , sk, sk->sk_state);/* Sock is dead, so set conn->sk to NULL to avoid possible UAF */ +lock_sock (sk);if (iso_pi (sk)->conn) {iso_conn_lock (iso_pi (sk)->conn);iso_pi (sk)->conn->sk =NULL ;iso_conn_unlock (iso_pi (sk)->conn); } +release_sock (sk);/* Kill poor orphan */ bt_sock_unlink (&iso_sk_list, sk);
@@ -2046,23 +2048,17 @@ static void iso_sock_ready(struct sock *sk) {BT_DBG ("sk %p" , sk); -if (!sk) -return ; - -lock_sock (sk); +lockdep_assert (lockdep_sock_is_held (sk));switch (sk->sk_state) {case BT_DISCONN :case BT_CLOSED : -release_sock (sk);return ; }iso_sock_clear_timer (sk); sk->sk_state =BT_CONNECTED ; sk->sk_state_change (sk); - -release_sock (sk); }static bool iso_match_big (struct sock *sk,void *data)
@@ -2092,7 +2088,7 @@ static bool iso_match_dst(struct sock *sk, void *data)static void iso_conn_ready (struct iso_conn *conn) {struct sock *parent =NULL ; -struct sock *sk = conn->sk; +struct sock *sk;struct hci_ev_le_big_sync_established *ev =NULL ;struct hci_ev_le_pa_sync_established *ev2 =NULL ;struct hci_ev_le_per_adv_report *ev3 =NULL ;
@@ -2101,7 +2097,22 @@ static void iso_conn_ready(struct iso_conn *conn)BT_DBG ("conn %p" , conn); +iso_conn_lock (conn); + sk =iso_sock_hold (conn); +iso_conn_unlock (conn); +if (sk) { +lock_sock (sk); + +/* conn->sk may have become NULL if racing with sk close, but +* due to held hdev->lock, it can't become different sk. +*/ +if (!conn->sk) { +release_sock (sk); +sock_put (sk); +return ; + } +/* Attempt to update source address in case of BIS Sender if * the advertisement is using a random address. */
@@ -2114,14 +2125,15 @@ static void iso_conn_ready(struct iso_conn *conn) adv =hci_find_adv_instance (bis->hdev, bis->iso_qos.bcast.bis);if (adv &&bacmp (&adv->random_addr,BDADDR_ANY )) { -lock_sock (sk);iso_pi (sk)->src_type =BDADDR_LE_RANDOM ;bacpy (&iso_pi (sk)->src, &adv->random_addr); -release_sock (sk); } } -iso_sock_ready (conn->sk); +iso_sock_ready (sk); + +release_sock (sk); +sock_put (sk); }else { hcon = conn->hcon;if (!hcon)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 136/438 Bluetooth: ISO: fix leaking sk after socket release
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit ce57442a379212fe3fda59c9437ee8217eceb5b1 ]
iso_sock_kill() tests !sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket || sock_flag(sk, SOCK_DEAD) for early return, but this is always true since sock_orphan(sk) sets SOCK_DEAD, so the sk reference released by socket always leaks, iso_sock_destruct is never called.
The socket reference also leaks when __iso_sock_close() does not set SOCK_ZAPPED, since iso_conn_del() does not call iso_sock_kill() after zapping.
Fix by replacing SOCK_DEAD by BT_SK_KILLED flag that is not used for something else, and lock_sock to ensure iso_sock_kill() puts sk only after socket release only once. Release and iso_conn_del may run concurrently. Call iso_sock_kill() from iso_conn_del() to clean sk up after zapping.
Remove call to iso_sock_kill() from iso_sock_close(), as it's generally no-op there.
--- net/bluetooth/iso.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
net/bluetooth/iso.c +18 -4
@@ -61,6 +61,7 @@ static void iso_sock_kill(struct sock *sk);enum {BT_SK_BIG_SYNC ,BT_SK_PA_SYNC , +BT_SK_KILLED , };struct iso_pinfo {
@@ -294,6 +295,7 @@ static void iso_conn_del(struct hci_conn *hcon, int err)iso_sock_clear_timer (sk);iso_chan_del (sk, err);release_sock (sk); +iso_sock_kill (sk);sock_put (sk); }
@@ -797,24 +799,29 @@ static void iso_sock_cleanup_listen(struct sock *parent)*/ static void iso_sock_kill (struct sock *sk) { +lock_sock (sk); +if (!sock_flag (sk,SOCK_ZAPPED ) || sk->sk_socket || -sock_flag (sk,SOCK_DEAD )) +test_bit (BT_SK_KILLED , &iso_pi (sk)->flags)) { +release_sock (sk);return ; + }BT_DBG ("sk %p state %d" , sk, sk->sk_state);/* Sock is dead, so set conn->sk to NULL to avoid possible UAF */ -lock_sock (sk);if (iso_pi (sk)->conn) {iso_conn_lock (iso_pi (sk)->conn);iso_pi (sk)->conn->sk =NULL ;iso_conn_unlock (iso_pi (sk)->conn); } -release_sock (sk);/* Kill poor orphan */ bt_sock_unlink (&iso_sk_list, sk);sock_set_flag (sk,SOCK_DEAD ); +set_bit (BT_SK_KILLED , &iso_pi (sk)->flags); + +release_sock (sk);sock_put (sk); }
@@ -891,7 +898,6 @@ static void iso_sock_close(struct sock *sk)iso_sock_clear_timer (sk);__iso_sock_close (sk);release_sock (sk); -iso_sock_kill (sk); }static void iso_sock_init (struct sock *sk,struct sock *parent)
@@ -2039,8 +2045,16 @@ static int iso_sock_release(struct socket *sock)release_sock (sk); } +/* Make sure sk is valid even if iso_conn_del() is concurrent */ +sock_hold (sk); + +lock_sock (sk);sock_orphan (sk); +release_sock (sk); +iso_sock_kill (sk); + +sock_put (sk);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 137/438 Bluetooth: ISO: avoid deadlocks in iso_sock_timeout
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 200fa1629c57a3ca2b03d3ca63fd3a9bfd910c43 ]
iso_sock_timeout() takes lock_sock, so sync disabling the timer while holding that lock may deadlock.
iso_sock_timeout() may also run concurrently with iso_conn_del(), which leads to UAF
[Task 1] [Task hdev->workqueue]
iso_sock_timeout iso_conn_del
iso_conn_hold_unless_zero iso_chan_del
`------------> iso_conn_put
caller frees hcon
iso_conn_put
iso_conn_free
conn->hcon->iso_data = NULL; /* UAF */Fix the deadlock by removing the disable from the lock_sock sections. Move the timer from iso_conn to iso_pinfo to decouple it from iso_conn which may need to be freed in lock_sock section. Convert some of the clear_timer to disable_timer.
--- net/bluetooth/iso.c | 60 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 31 deletions(-)
net/bluetooth/iso.c +29 -31
@@ -36,8 +36,6 @@ struct iso_conn {spinlock_t lock;struct sock *sk; -struct delayed_work timeout_work; -struct sk_buff *rx_skb;__u32 rx_len;__u16 tx_sn;
@@ -80,6 +78,7 @@ struct iso_pinfo {__u8 base_len;__u8 base[BASE_MAX_LENGTH ];struct iso_conn *conn; +struct delayed_work timeout_work; };static struct bt_iso_qos default_qos;
@@ -117,9 +116,6 @@ static void iso_conn_free(struct kref *ref)hci_conn_drop (conn->hcon); } -/* Ensure no more work items will run since hci_conn has been dropped */ -disable_delayed_work_sync (&conn->timeout_work); -kfree_skb (conn->rx_skb);kfree (conn);
@@ -160,48 +156,45 @@ static struct sock *iso_sock_hold(struct iso_conn *conn)static void iso_sock_timeout (struct work_struct *work) { - struct iso_conn *conn = container_of(work, struct iso_conn, - timeout_work.work); -struct sock *sk; - - conn =iso_conn_hold_unless_zero (conn); -if (!conn) -return ; - -iso_conn_lock (conn); - sk =iso_sock_hold (conn); -iso_conn_unlock (conn); -iso_conn_put (conn); - -if (!sk) -return ; + struct iso_pinfo *pi = container_of(work, struct iso_pinfo, + timeout_work.work); +struct sock *sk = &pi->bt.sk;BT_DBG ("sock %p state %d" , sk, sk->sk_state);lock_sock (sk); - sk->sk_err =ETIMEDOUT ; - sk->sk_state_change (sk); +if (!sock_flag (sk,SOCK_ZAPPED )) { + sk->sk_err =ETIMEDOUT ; + sk->sk_state_change (sk); + }release_sock (sk); -sock_put (sk); }static void iso_sock_set_timer (struct sock *sk,long timeout) { +lockdep_assert (lockdep_sock_is_held (sk)); + +cancel_delayed_work (&iso_pi (sk)->timeout_work); +if (!iso_pi (sk)->conn)return ;BT_DBG ("sock %p state %d timeout %ld" , sk, sk->sk_state, timeout); -cancel_delayed_work (&iso_pi (sk)->conn->timeout_work); -schedule_delayed_work (&iso_pi (sk)->conn->timeout_work, timeout); +schedule_delayed_work (&iso_pi (sk)->timeout_work, timeout); }static void iso_sock_clear_timer (struct sock *sk) { -if (!iso_pi (sk)->conn) -return ; +BT_DBG ("sock %p state %d" , sk, sk->sk_state); +cancel_delayed_work (&iso_pi (sk)->timeout_work); +} + +static void iso_sock_disable_timer (struct sock *sk) +{ +lockdep_assert (!lockdep_sock_is_held (sk));BT_DBG ("sock %p state %d" , sk, sk->sk_state); -cancel_delayed_work (&iso_pi (sk)->conn->timeout_work); +disable_delayed_work_sync (&iso_pi (sk)->timeout_work); }/* ---- ISO connections ---- */
@@ -226,7 +219,6 @@ static struct iso_conn *iso_conn_add(struct hci_conn *hcon)kref_init (&conn->ref);spin_lock_init (&conn->lock); -INIT_DELAYED_WORK (&conn->timeout_work, iso_sock_timeout); hcon->iso_data = conn; conn->hcon = hcon;
@@ -291,8 +283,9 @@ static void iso_conn_del(struct hci_conn *hcon, int err)return ; } +iso_sock_disable_timer (sk); +lock_sock (sk); -iso_sock_clear_timer (sk);iso_chan_del (sk, err);release_sock (sk);iso_sock_kill (sk);
@@ -799,6 +792,8 @@ static void iso_sock_cleanup_listen(struct sock *parent)*/ static void iso_sock_kill (struct sock *sk) { +iso_sock_disable_timer (sk); +lock_sock (sk); if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket ||
@@ -894,8 +889,9 @@ static void __iso_sock_close(struct sock *sk)/* Must be called on unlocked socket. */ static void iso_sock_close (struct sock *sk) { +iso_sock_disable_timer (sk); +lock_sock (sk); -iso_sock_clear_timer (sk);__iso_sock_close (sk);release_sock (sk); }
@@ -964,6 +960,8 @@ static struct sock *iso_sock_alloc(struct net *net, struct socket *sock,iso_pi (sk)->qos = default_qos;iso_pi (sk)->sync_handle =-1 ; +INIT_DELAYED_WORK (&iso_pi (sk)->timeout_work, iso_sock_timeout); +bt_sock_link (&iso_sk_list, sk);return sk; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 138/438 Bluetooth: ISO: ensure no dangling hcon references in iso_conn
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit aa9f7cb2bd3a2be998ceb739fc9a2f986eba43eb ]
After iso_conn_del(), ISO sockets should not dereference the hcon any more. Currently, clearing iso_conn::hcon relies on iso_conn_del() releasing the last reference to the iso_conn.
Simplify this by explicitly clearing conn->hcon in iso_conn_del(), to avoid more complex reasoning on races about who holds the last reference.
Stable-dep-of: fdfde532ab1c ("Bluetooth: ISO: fix refcounting of iso_conn")
--- net/bluetooth/iso.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-)
net/bluetooth/iso.c +21 -3
@@ -262,6 +262,7 @@ static void iso_chan_del(struct sock *sk, int err) }static void iso_conn_del (struct hci_conn *hcon,int err) + __must_hold(&hcon->hdev->lock) {struct iso_conn *conn = hcon->iso_data;struct sock *sk;
@@ -276,11 +277,10 @@ static void iso_conn_del(struct hci_conn *hcon, int err)iso_conn_lock (conn); sk =iso_sock_hold (conn);iso_conn_unlock (conn); -iso_conn_put (conn);if (!sk) {iso_conn_put (conn); -return ; + goto done; }iso_sock_disable_timer (sk);
@@ -290,6 +290,15 @@ static void iso_conn_del(struct hci_conn *hcon, int err)release_sock (sk);iso_sock_kill (sk);sock_put (sk); + +done: +/* No sk access to conn->hcon any more (lock_sock + hdev->lock) */ +iso_conn_lock (conn); + conn->hcon =NULL ; + hcon->iso_data =NULL ; +iso_conn_unlock (conn); + +iso_conn_put (conn); } static int __iso_chan_add(struct iso_conn *conn, struct sock *sk,
@@ -305,6 +314,11 @@ static int __iso_chan_add(struct iso_conn *conn, struct sock *sk,return -EBUSY ; } +if (!conn->hcon) { +BT_ERR ("conn->hcon missing" ); +return -EIO ; + } +iso_pi (sk)->conn = conn; conn->sk = sk;clear_bit (ISO_CONN_DROPPED , conn->flags);
@@ -2499,6 +2513,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) }static void iso_connect_cfm (struct hci_conn *hcon,__u8 status) + __must_hold(&hcon->hdev->lock) {if (hcon->type !=CIS_LINK && hcon->type !=BIS_LINK && hcon->type !=PA_LINK ) {
@@ -2510,8 +2525,10 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)struct hci_link *link, *t;list_for_each_entry_safe (link, t, &hcon->link_list, - list) + list) { +lockdep_assert_held (&link->conn->hdev->lock);iso_conn_del (link->conn,bt_to_errno (status)); + }return ; }
@@ -2541,6 +2558,7 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status) }static void iso_disconn_cfm (struct hci_conn *hcon,__u8 reason) + __must_hold(&hcon->hdev->lock) {if (hcon->type !=CIS_LINK && hcon->type !=BIS_LINK && hcon->type !=PA_LINK )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 139/438 Bluetooth: ISO: fix refcounting of iso_conn
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit fdfde532ab1caa165fcd8985001157ac8b4db365 ]
iso_conn_del() and iso_chan_del() have a race that results to double-put of iso_conn:
[Task hdev->workqueue] [Task 2]
iso_conn_del iso_chan_del
iso_conn_hold_unless_zero iso_conn_lock
iso_conn_lock conn->sk = NULL
iso_conn_unlock
sk = iso_sock_hold(conn) <---------´
if (!sk) iso_conn_put iso_conn_put
iso_conn_put /* UAF */The extra put for !sk in iso_conn_del() is currently required since failing iso_chan_add() may leave iso_conn not associated with any sk.
Fix by having iso_pi(sk)->conn own refcount when non-NULL, so iso_conn_del does not need to put it. Adjust the iso_conn_add() refcounting so that conn is put if it does not get associated with an sk.
--- net/bluetooth/iso.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
net/bluetooth/iso.c +17 -12
@@ -107,9 +107,6 @@ static void iso_conn_free(struct kref *ref)BT_DBG ("conn %p" , conn); -if (conn->sk) -iso_pi (conn->sk)->conn =NULL ; -if (conn->hcon) { conn->hcon->iso_data =NULL ;if (!test_and_set_bit (ISO_CONN_DROPPED , conn->flags))
@@ -144,6 +141,14 @@ static struct iso_conn *iso_conn_hold_unless_zero(struct iso_conn *conn)return conn; } +static struct iso_conn *iso_conn_hold (struct iso_conn *conn) +{ +BT_DBG ("conn %p refcnt %u" , conn,kref_read (&conn->ref)); + +kref_get (&conn->ref); +return conn; +} +static struct sock *iso_sock_hold (struct iso_conn *conn) {if (!conn || !bt_sock_linked (&iso_sk_list, conn->sk))
@@ -209,7 +214,6 @@ static struct iso_conn *iso_conn_add(struct hci_conn *hcon) conn->hcon = hcon;iso_conn_unlock (conn); } -iso_conn_put (conn);return conn; }
@@ -278,10 +282,8 @@ static void iso_conn_del(struct hci_conn *hcon, int err) sk =iso_sock_hold (conn);iso_conn_unlock (conn); -if (!sk) { -iso_conn_put (conn); +if (!sk) goto done; - }iso_sock_disable_timer (sk);
@@ -319,7 +321,7 @@ static int __iso_chan_add(struct iso_conn *conn, struct sock *sk,return -EIO ; } -iso_pi (sk)->conn = conn; +iso_pi (sk)->conn =iso_conn_hold (conn); conn->sk = sk;clear_bit (ISO_CONN_DROPPED , conn->flags);
@@ -426,6 +428,7 @@ static int iso_connect_bis(struct sock *sk) } err =iso_chan_add (conn, sk,NULL ); +iso_conn_put (conn);if (err) goto unlock;
@@ -528,6 +531,7 @@ static int iso_connect_cis(struct sock *sk) } err =iso_chan_add (conn, sk,NULL ); +iso_conn_put (conn);if (err) goto unlock;
@@ -1309,10 +1313,9 @@ static int iso_listen_bis(struct sock *sk) } err =iso_chan_add (conn, sk,NULL ); -if (err) { -hci_conn_drop (hcon); +iso_conn_put (conn); +if (err) goto unlock; - } unlock:release_sock (sk);
@@ -2550,8 +2553,10 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)struct iso_conn *conn; conn =iso_conn_add (hcon); -if (conn) +if (conn) {iso_conn_ready (conn); +iso_conn_put (conn); + } }else {iso_conn_del (hcon,bt_to_errno (status)); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 140/438 Bluetooth: ISO: fix race of kfree vs kref_get_unless_zero
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit af24e338bf5dafb80f42baa9a0b9e9b57b1c5d9c ]
hci_conn::iso_data is accessed and modified without lock or RCU. This leads to a race
[Task hdev->workqueue] [Task 2]
iso_recv iso_conn_put(conn)
conn = LOAD hcon->iso_data iso_conn_free(conn)
iso_conn_hold_unless_zero(conn) hcon->iso_data = NULL
kfree(conn)
kref_get_unless_zero(&conn->ref) /* UAF */and also to races in iso_conn_add() vs. iso_conn_free().
Fix by adding spinlock hci_conn::proto_lock and using it to guard hci_conn::iso_data.
--- include/net/bluetooth/hci_core.h | 4 +- net/bluetooth/hci_conn.c | 2 + net/bluetooth/iso.c | 64 ++++++++++++++++++++++++++------ 3 files changed, 58 insertions(+), 12 deletions(-)
include/net/bluetooth/hci_core.h +3 -1
@@ -770,9 +770,11 @@ struct hci_conn {struct dentry *debugfs;struct hci_dev *hdev; + +spinlock_t proto_lock;/* lock guarding protocol data */ void *l2cap_data;void *sco_data; -void *iso_data; + void *iso_data __guarded_by(&proto_lock);struct list_head link_list;struct hci_conn *parent;
net/bluetooth/hci_conn.c +2 -0
@@ -1126,6 +1126,8 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,INIT_DELAYED_WORK (&conn->idle_work, hci_conn_idle);INIT_DELAYED_WORK (&conn->le_conn_timeout, le_conn_timeout); +spin_lock_init (&conn->proto_lock); +atomic_set (&conn->refcnt,0 );hci_dev_hold (hdev);
net/bluetooth/iso.c +53 -11
150 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 141/438 Bluetooth: btintel: Validate length before parsing diagnostics TLV
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit b640ff9af3c809ff5ea2077fbba17df1594ec1e4 ]
btintel_diagnostics() accesses tlv->val[0] without first validating that the diagnostics VSE is long enough to contain that field, so may cause reading data beyond the received frame.
Fix by validating the length before access.
--- drivers/bluetooth/btintel.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/bluetooth/btintel.c +3 -0
@@ -3771,6 +3771,9 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) {struct intel_tlv *tlv = (void *)&skb->data[5 ]; +if (skb->len <5 +sizeof (*tlv) +sizeof (tlv->val[0 ])) + goto recv_frame; +/* The first event is always an event type TLV */ if (tlv->type !=INTEL_TLV_TYPE_ID ) goto recv_frame;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 142/438 Bluetooth: hci_conn: hold conn reference in abort_conn_sync()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 5761d003daa987ac81463f570713ce9c9dd204e5 ]
There is theoretical UAF if the conn is freed while the hci_sync task is running.
Hold refcount to avoid that.
--- net/bluetooth/hci_conn.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
net/bluetooth/hci_conn.c +11 -1
@@ -3168,6 +3168,13 @@ static int abort_conn_sync(struct hci_dev *hdev, void *data)return hci_abort_conn_sync (hdev, conn, conn->abort_reason); } +static void abort_conn_destroy (struct hci_dev *hdev,void *data,int err) +{ +struct hci_conn *conn = data; + +hci_conn_put (conn); +} +int hci_abort_conn (struct hci_conn *conn,u8 reason) {struct hci_dev *hdev = conn->hdev;
@@ -3193,7 +3200,10 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)* as a result to MGMT_OP_DISCONNECT/MGMT_OP_UNPAIR which does * already queue its callback on cmd_sync_work. */ - err =hci_cmd_sync_run_once (hdev, abort_conn_sync, conn,NULL ); + err =hci_cmd_sync_run_once (hdev, abort_conn_sync,hci_conn_get (conn), + abort_conn_destroy); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 143/438 Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 2f5d635ad5906b0235bc0c870e8beba3116e1e98 ]
There is theoretical UAF if the conn is freed while the hci_sync task is running.
Hold refcount to avoid that.
--- net/bluetooth/hci_sync.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-)
net/bluetooth/hci_sync.c +24 -8
@@ -7067,12 +7067,23 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)return err; } +static void hci_acl_create_conn_sync_complete (struct hci_dev *hdev,void *data, +int err) +{ +struct hci_conn *conn = data; + +hci_conn_put (conn); +} +int hci_connect_acl_sync (struct hci_dev *hdev,struct hci_conn *conn) {int err; - err =hci_cmd_sync_queue_once (hdev, hci_acl_create_conn_sync, conn, -NULL ); + err =hci_cmd_sync_queue_once (hdev, hci_acl_create_conn_sync, +hci_conn_get (conn), + hci_acl_create_conn_sync_complete); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
@@ -7083,36 +7094,41 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)bt_dev_dbg (hdev,"err %d" , err);if (err == -ECANCELED ) -return ; + goto done;hci_dev_lock (hdev);if (!hci_conn_valid (hdev, conn)) - goto done; + goto unlock;if (!err) {hci_connect_le_scan_cleanup (conn,0x00 ); - goto done; + goto unlock; }/* Check if connection is still pending */ if (conn !=hci_lookup_le_connect (hdev)) - goto done; + goto unlock;/* Flush to make sure we send create conn cancel command if needed */ flush_delayed_work (&conn->le_conn_timeout);hci_conn_failed (conn,bt_status (err)); -done: +unlock:hci_dev_unlock (hdev); +done: +hci_conn_put (conn); }int hci_connect_le_sync (struct hci_dev *hdev,struct hci_conn *conn) {int err; - err =hci_cmd_sync_queue_once (hdev, hci_le_create_conn_sync, conn, + err =hci_cmd_sync_queue_once (hdev, hci_le_create_conn_sync, +hci_conn_get (conn), create_le_conn_complete); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 144/438 Bluetooth: hci_sync: hold conn in hci_connect_big_sync() callback
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 56e78b670356caab0b607e8aad4cf819a1909d07 ]
There is theoretical UAF if the conn is freed while the hci_sync task is running.
Hold refcount to avoid that. Handle NULL hcon, return 0 + do nothing to match the previous behavior.
--- net/bluetooth/hci_sync.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
net/bluetooth/hci_sync.c +12 -4
@@ -7437,10 +7437,12 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)bt_dev_dbg (hdev,"err %d" , err);if (err == -ECANCELED ) -return ; + goto done; -if (hci_conn_valid (hdev, conn)) -clear_bit (HCI_CONN_CREATE_BIG_SYNC , &conn->flags); +clear_bit (HCI_CONN_CREATE_BIG_SYNC , &conn->flags); + +done: +hci_conn_put (conn); }static int hci_le_big_create_sync (struct hci_dev *hdev,void *data)
@@ -7492,8 +7494,14 @@ int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn) {int err; - err =hci_cmd_sync_queue_once (hdev, hci_le_big_create_sync, conn, +if (!conn) +return 0 ; + + err =hci_cmd_sync_queue_once (hdev, hci_le_big_create_sync, +hci_conn_get (conn), create_big_complete); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 145/438 Bluetooth: hci_sync: hold conn in hci_connect_pa_sync() callback
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 44fc74069d8988f2825246f9401218e29de2c0ab ]
There is theoretical UAF if the conn is freed while the hci_sync task is running.
Hold refcount to avoid that.
--- net/bluetooth/hci_sync.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
net/bluetooth/hci_sync.c +7 -2
@@ -7251,7 +7251,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)bt_dev_dbg (hdev,"err %d" , err);if (err == -ECANCELED ) -return ; + goto done;hci_dev_lock (hdev);
@@ -7275,6 +7275,8 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err) unlock:hci_dev_unlock (hdev); +done: +hci_conn_put (conn); } static int hci_le_past_params_sync(struct hci_dev *hdev, struct hci_conn *conn,
@@ -7425,8 +7427,11 @@ int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn) {int err; - err =hci_cmd_sync_queue_once (hdev, hci_le_pa_create_sync, conn, + err =hci_cmd_sync_queue_once (hdev, hci_le_pa_create_sync, +hci_conn_get (conn), create_pa_complete); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 146/438 Bluetooth: hci_sync: hold conn in hci_past_sync() callback
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit abf9753edf3f88282c44a605f3945d8d4f8dd86c ]
Avoids giving freed pointers to hci_conn_valid(), which kmalloc may have reused.
Hold refcount to avoid that.
--- net/bluetooth/hci_sync.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
net/bluetooth/hci_sync.c +8 -3
@@ -7521,6 +7521,8 @@ static void past_complete(struct hci_dev *hdev, void *data, int err)bt_dev_dbg (hdev,"err %d" , err); +hci_conn_put (past->conn); +hci_conn_put (past->le);kfree (past); }
@@ -7585,8 +7587,8 @@ int hci_past_sync(struct hci_conn *conn, struct hci_conn *le)if (!data)return -ENOMEM ; - data->conn = conn; - data->le = le; + data->conn =hci_conn_get (conn); + data->le =hci_conn_get (le);if (conn->role ==HCI_ROLE_MASTER ) err = hci_cmd_sync_queue_once(conn->hdev,
@@ -7596,8 +7598,11 @@ int hci_past_sync(struct hci_conn *conn, struct hci_conn *le) err =hci_cmd_sync_queue_once (conn->hdev, hci_le_past_sync, data, past_complete); -if (err) +if (err) { +hci_conn_put (data->conn); +hci_conn_put (data->le);kfree (data); + }return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 147/438 Bluetooth: hci_sync: fix hci_conn_del() use in hci_le_create_conn_sync
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 2c1e4e00613dfd105f978be2276e5e265801ec9f ]
hci_conn_del() caller must hold hdev->lock, check the conn was not concurrently deleted, and usually inform socket the conn is going to be deleted.
Use hci_abort_conn_sync() instead of calling hci_conn_del() without locks etc.
--- net/bluetooth/hci_sync.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/bluetooth/hci_sync.c +3 -1
@@ -6672,7 +6672,9 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)if (hci_dev_test_flag (hdev,HCI_LE_SCAN ) && hdev->le_scan_type ==LE_SCAN_ACTIVE && !hci_dev_test_flag (hdev,HCI_LE_SIMULTANEOUS_ROLES )) { -hci_conn_del (conn); + conn->state =BT_OPEN ; +hci_abort_conn_sync (hdev, conn, +HCI_ERROR_REJ_LIMITED_RESOURCES );hci_conn_put (conn);return -EBUSY ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 148/438 Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit c0a9dcd2be398eee505d4b254ec3a845aa8ab189 ]
hci_conn_get() without already held reference is data race against concurrent deletion.
In previous patches, the refcount has been changed to be taken before starting the hci_sync task, so remove these extra get() + put() as they are not needed.
--- net/bluetooth/hci_sync.c | 13 ------------- 1 file changed, 13 deletions(-)
net/bluetooth/hci_sync.c +0 -13
@@ -6656,11 +6656,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)bt_dev_dbg (hdev,"conn %p" , conn); -/* Hold a reference so conn stays valid for the HCI_CONN_CREATE -* clear_bit() at done. -*/ -hci_conn_get (conn); -clear_bit (HCI_CONN_SCANNING , &conn->flags); conn->state =BT_CONNECT ;
@@ -6675,7 +6670,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) conn->state =BT_OPEN ;hci_abort_conn_sync (hdev, conn,HCI_ERROR_REJ_LIMITED_RESOURCES ); -hci_conn_put (conn);return -EBUSY ; }
@@ -6773,7 +6767,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)/* Re-enable advertising after the connection attempt is finished. */ hci_resume_advertising_sync (hdev); -hci_conn_put (conn);return err; }
@@ -7048,11 +7041,6 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)else cp.role_switch =0x00 ; -/* Hold a reference so conn stays valid for the HCI_CONN_CREATE -* clear_bit() below. -*/ -hci_conn_get (conn); -/* Mark create connection in flight so hci_cancel_connect_sync() can * cancel it while blocking on the connection complete event. */
@@ -7064,7 +7052,6 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) conn->conn_timeout, NULL);clear_bit (HCI_CONN_CREATE , &conn->flags); -hci_conn_put (conn);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 149/438 x86/boot: Add volatile, clobbers and zero-length test in memcmp()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mauricio Faria de Oliveira <[email protected]>
[ Upstream commit a8c171c107c0b61a5e7e10cedab0fb72aeaf640d ]
Add the volatile qualifier and clobbers parameter to prevent bugs with instruction reordering and optimization.
Also add TEST for the zero-length case to set ZF, as, if the count register is zero, the REPE prefix does not run the CMPSB instruction, leaving the ZF flag undetermined.
[ bp: Add a comment about the len==0 case. ]
--- arch/x86/boot/string.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
arch/x86/boot/string.c +9 -2
@@ -32,8 +32,15 @@int memcmp (const void *s1,const void *s2,size_t len) {bool diff; - asm("repe cmpsb" - :"=@ccnz" (diff),"+D" (s1),"+S" (s2),"+c" (len)); + +/* +* Make sure ZF is properly set in the len==0 case because in it, +* RCX==0 and the REPE; CMPSB won't get executed. +*/ + asmvolatile ("test %3, %3\n\t" +"repe cmpsb" + :"=@ccnz" (diff),"+D" (s1),"+S" (s2),"+c" (len) + : :"cc" ,"memory" );return diff; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 150/438 net: phylink: put link_gpio if phylink_create fails
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Marangi <[email protected]>
[ Upstream commit 0fe1e3e8f3380d7862296a73b528d164e96c76b8 ]
In phylink_create() if phylink_register_sfp() returns an error, link_gpio obtained by phylink_parse_fixedlink() is never released. While this is a very unlikely scenario, it's worth to fix/handle this.
This was present from the very first implementation of phylink but got relevant only with the introduction of ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network devices and sfp cages") where additional function were added after phylink_parse_fixedlink() making the release of link_gpio needed if such additional function errored out.
While at it, restructure the exit condition of phylink_create() with the goto pattern to reduce code duplication on handling error conditions.
--- drivers/net/phy/phylink.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
drivers/net/phy/phylink.c +15 -14
@@ -1875,8 +1875,8 @@ struct phylink *phylink_create(struct phylink_config *config, }else if (config->type ==PHYLINK_DEV ) { pl->dev = config->dev; }else { -kfree (pl); -return ERR_PTR (-EINVAL ); + ret = -EINVAL ; + goto free_pl; } pl->mac_supports_eee_ops =phylink_mac_implements_lpi (mac_ops);
@@ -1909,28 +1909,29 @@ struct phylink *phylink_create(struct phylink_config *config,phylink_validate (pl, pl->supported, &pl->link_config); ret =phylink_parse_mode (pl, fwnode); -if (ret <0 ) { -kfree (pl); -return ERR_PTR (ret); - } +if (ret <0 ) + goto free_pl;if (pl->cfg_link_an_mode ==MLO_AN_FIXED ) { ret =phylink_parse_fixedlink (pl, fwnode); -if (ret <0 ) { -kfree (pl); -return ERR_PTR (ret); - } +if (ret <0 ) + goto release_link_gpio; } pl->req_link_an_mode = pl->cfg_link_an_mode; ret =phylink_register_sfp (pl, fwnode); -if (ret <0 ) { -kfree (pl); -return ERR_PTR (ret); - } +if (ret <0 ) + goto release_link_gpio;return pl; + +release_link_gpio: +if (pl->link_gpio) +gpiod_put (pl->link_gpio); +free_pl: +kfree (pl); +return ERR_PTR (ret); }EXPORT_SYMBOL_GPL (phylink_create);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 151/438 scsi: target: iblock: Fix wrong PR ops NULL check for PREEMPT/RELEASE
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: TanZheng <[email protected]>
[ Upstream commit 9c33222bd387312874fbe36ca8002e5c945b9653 ]
In the iblock_execute_pr_out() function, PRO_PREEMPT, PRO_PREEMPT_AND_ABORT, and PRO_RELEASE all perform callback capability checks through ops->pr_clear. The error check allows unimplemented hooks to pass through the gate, resulting dereferencing a NULL function pointer.
Check whether the hooks that need to be called are supported.
--- drivers/target/target_core_iblock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/target/target_core_iblock.c +3 -3
@@ -906,7 +906,7 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key,break ;case PRO_PREEMPT :case PRO_PREEMPT_AND_ABORT : -if (!ops->pr_clear) { +if (!ops->pr_preempt) {pr_err ("block_device does not support pr_preempt.\n" );return TCM_UNSUPPORTED_SCSI_OPCODE ; }
@@ -916,8 +916,8 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key, sa == PRO_PREEMPT_AND_ABORT);break ;case PRO_RELEASE : -if (!ops->pr_clear) { -pr_err ("block_device does not support pr_pclear.\n" ); +if (!ops->pr_release) { +pr_err ("block_device does not support pr_release.\n" );return TCM_UNSUPPORTED_SCSI_OPCODE ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 152/438 scsi: ufs: core: Cancel RTC work in active-active suspend
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit f71b4a30983b846b4075bf544e835121e70e6a43 ]
UFS RTC support schedules ufs_rtc_update_work to periodically update the device RTC. The work can issue query commands and access the UFS host controller.
A previous change moved the RTC work cancellation before the PRE_CHANGE vendor suspend callback to close a race in the common suspend path. However, the active-active path jumps directly to vops_suspend after flushing exception handling work and therefore bypasses the cancellation.
If the RTC work runs while the vendor suspend callback is gating or otherwise changing hardware state, it can access the controller during suspend and trigger an SError.
Cancel the RTC work before entering the vendor suspend callback in the active-active path. Since this path now cancels the work, move the RTC work scheduling outside the device and link state restoration block in the resume path. This restarts RTC updates after an active-active suspend and resume cycle.
--- drivers/ufs/core/ufshcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/ufs/core/ufshcd.c +4 -2
@@ -10238,6 +10238,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) req_link_state == UIC_LINK_ACTIVE_STATE) {ufshcd_disable_auto_bkops (hba);flush_work (&hba->eeh_work); +cancel_delayed_work_sync (&hba->ufs_rtc_update_work); goto vops_suspend; }
@@ -10447,10 +10448,11 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto set_old_link_state;ufshcd_set_timestamp_attr (hba); -schedule_delayed_work (&hba->ufs_rtc_update_work, -msecs_to_jiffies (UFS_RTC_UPDATE_INTERVAL_MS )); } +schedule_delayed_work (&hba->ufs_rtc_update_work, +msecs_to_jiffies (UFS_RTC_UPDATE_INTERVAL_MS )); +if (ufshcd_keep_autobkops_enabled_except_suspend (hba))ufshcd_enable_auto_bkops (hba);else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 153/438 scsi: ufs: core: Revert "Delegate the interrupt service routine to a threaded IRQ handler"
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bart Van Assche <[email protected]>
[ Upstream commit 8a309036f557d3ff4efb2beea5132ba91172d934 ]
There have been multiple reports of performance regressions caused by commit 3c7ac40d7322 ("scsi: ufs: core: Delegate the interrupt service routine to a threaded IRQ handler"). Hence this revert.
This patch reverts most of the following commits:
* 3c7ac40d7322 ("scsi: ufs: core: Delegate the interrupt service routine to a threaded IRQ handler")
* 6475cfb81fc4 ("scsi: ufs: core: Avoid IRQ thread wakeup during active UIC command")
This patch preserves the following commits:
* 034d319c8899 ("scsi: ufs: core: Fix interrupt handling for MCQ Mode")
* eabcac808ca3 ("scsi: ufs: core: Fix IRQ lock inversion for the SCSI host lock")
--- drivers/ufs/core/ufshcd.c | 39 +++------------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-)
drivers/ufs/core/ufshcd.c +3 -36
@@ -7309,7 +7309,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) }/** -* ufshcd_threaded_intr - Threaded interrupt service routine +* ufshcd_intr - Main interrupt service routine * @irq: irq number * @__hba: pointer to adapter instance *
@@ -7317,7 +7317,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)* IRQ_HANDLED - If interrupt is valid * IRQ_NONE - If invalid interrupt */ -static irqreturn_t ufshcd_threaded_intr (int irq,void *__hba) +static irqreturn_t ufshcd_intr (int irq,void *__hba) {u32 last_intr_status, intr_status, enabled_intr_status =0 ;irqreturn_t retval =IRQ_NONE ;
@@ -7356,38 +7356,6 @@ static irqreturn_t ufshcd_threaded_intr(int irq, void *__hba)return retval; } -/** -* ufshcd_intr - Main interrupt service routine -* @irq: irq number -* @__hba: pointer to adapter instance -* -* Return: -* IRQ_HANDLED - If interrupt is valid -* IRQ_WAKE_THREAD - If handling is moved to threaded handled -* IRQ_NONE - If invalid interrupt -*/ -static irqreturn_t ufshcd_intr (int irq,void *__hba) -{ -struct ufs_hba *hba = __hba; -u32 intr_status, enabled_intr_status; - -/* -* Handle interrupt in thread if MCQ or ESI is disabled, -* and no active UIC command. -*/ -if ((!hba->mcq_enabled || !hba->mcq_esi_enabled) && - !hba->active_uic_cmd) -return IRQ_WAKE_THREAD ; - - intr_status =ufshcd_readl (hba,REG_INTERRUPT_STATUS ); - enabled_intr_status = intr_status &ufshcd_readl (hba,REG_INTERRUPT_ENABLE ); - -ufshcd_writel (hba, intr_status,REG_INTERRUPT_STATUS ); - -/* Directly handle interrupts since MCQ ESI handlers does the hard job */ -return ufshcd_sl_intr (hba, enabled_intr_status); -} -static int ufshcd_clear_tm_cmd (struct ufs_hba *hba,int tag) {int err =0 ;
@@ -11204,8 +11172,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)ufshcd_readl (hba,REG_INTERRUPT_ENABLE );/* IRQ registration */ - err =devm_request_threaded_irq (dev, irq, ufshcd_intr, ufshcd_threaded_intr, -IRQF_ONESHOT |IRQF_SHARED ,UFSHCD , hba); + err =devm_request_irq (dev, irq, ufshcd_intr,IRQF_SHARED ,UFSHCD , hba);if (err) {dev_err (hba->dev,"request irq failed\n" ); goto out_disable;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 154/438 scsi: zfcp: Fix memory leak during adapter release by destroying gid_pn_req
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Block <[email protected]>
[ Upstream commit b601fa590e667bd9643feed8c869b6b3e418480d ]
When releasing an adapter we don't free the mempool 'gid_pn_req' that is allocated during the enqueue. This leaks memory:
unreferenced object 0xd8d29297de700 (size 256):
comm "(udev-worker)", pid 2105, jiffies 4294945794
hex dump (first 32 bytes):
00 00 00 00 de ad 4e ad ff ff ff ff 00 00 00 00 ......N.........
ff ff ff ff ff ff ff ff 00 0d c4 5f 67 9d 99 e0 ..........._g...
backtrace (crc 4a5b5da2):
[<000dc45f64da418c>] kmemleak_alloc+0x6c/0xa0
[<000dc45f62b430aa>] __kmalloc_cache_node_noprof+0x36a/0x4d0
[<000dc45f629a535a>] mempool_create_node_noprof+0xaa/0x150
[<000dc45ee2c065e6>] zfcp_allocate_low_mem_buffers+0x96/0x370 [zfcp]
[<000dc45ee2c070f8>] zfcp_adapter_enqueue+0x598/0xd40 [zfcp]
[<000dc45ee2c08eb0>] zfcp_ccw_set_online+0x160/0x210 [zfcp]
[<000dc45f643d4762>] ccw_device_set_online+0x232/0xd80
[<000dc45f643d53d4>] online_store_recog_and_online+0x124/0x390
[<000dc45f643d8238>] online_store+0x298/0x5b0
[<000dc45f62eb0a04>] kernfs_fop_write_iter+0x2c4/0x480
[<000dc45f62c81150>] new_sync_write+0x370/0x4b0
[<000dc45f62c87abe>] vfs_write+0x43e/0x5b0
[<000dc45f62c87ff4>] ksys_write+0x114/0x1f0
[<000dc45f621c4a16>] do_syscall+0x2f6/0x430
[<000dc45f64d9d5d8>] __do_syscall+0xc8/0x1c0
[<000dc45f64dc2224>] system_call+0x74/0xa0Fix this by destroying the mempool during the adapter's release.
--- drivers/s390/scsi/zfcp_aux.c | 1 + 1 file changed, 1 insertion(+)
drivers/s390/scsi/zfcp_aux.c +1 -0
@@ -253,6 +253,7 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)static void zfcp_free_low_mem_buffers (struct zfcp_adapter *adapter) {mempool_destroy (adapter->pool.erp_req); +mempool_destroy (adapter->pool.gid_pn_req);mempool_destroy (adapter->pool.scsi_req);mempool_destroy (adapter->pool.scsi_abort);mempool_destroy (adapter->pool.qtcb_pool);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 155/438 scsi: target: Clear cmd_cnt when initial counter enrollment fails
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit a8ddfd2425bbbafadae8700d63ed8a61a4109878 ]
When target_get_sess_cmd() fails during session shutdown because percpu_ref_tryget_live() returns false, the command keeps the se_cmd->cmd_cnt pointer that __target_init_cmd() assigned earlier without owning a reference. Final release through target_release_cmd_kref() then issues an unmatched percpu_ref_put().
Commit 8e288be8606a ("scsi: target: Pass in cmd counter to use during cmd setup") moved the cmd_cnt assignment ahead of the reference acquisition. Clear se_cmd->cmd_cnt whenever the initial target_get_sess_cmd() fails in target_init_cmd() and target_submit_tmr(), so release performs exactly one matching put per acquired reference.
--- drivers/target/target_core_transport.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/target/target_core_transport.c +10 -2
@@ -1734,6 +1734,7 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, u32 data_length, int task_attr, int data_dir, int flags) { struct se_portal_group *se_tpg; +int ret; se_tpg = se_sess->se_tpg;BUG_ON (!se_tpg);
@@ -1763,7 +1764,11 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,* necessary for fabrics using TARGET_SCF_ACK_KREF that expect a second * kref_put() to happen during fabric packet acknowledgement. */ -return target_get_sess_cmd (se_cmd, flags &TARGET_SCF_ACK_KREF ); + ret =target_get_sess_cmd (se_cmd, flags &TARGET_SCF_ACK_KREF ); +if (ret) + se_cmd->cmd_cnt =NULL ; + +return ret; }EXPORT_SYMBOL_GPL (target_init_cmd);
@@ -2039,8 +2044,10 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,* allocation failure. */ ret =core_tmr_alloc_req (se_cmd, fabric_tmr_ptr, tm_type, gfp); -if (ret <0 ) +if (ret <0 ) { + se_cmd->cmd_cnt =NULL ;return -ENOMEM ; + }if (tm_type ==TMR_ABORT_TASK ) se_cmd->se_tmr_req->ref_task_tag = tag;
@@ -2048,6 +2055,7 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,/* See target_submit_cmd for commentary */ ret =target_get_sess_cmd (se_cmd, flags &TARGET_SCF_ACK_KREF );if (ret) { + se_cmd->cmd_cnt =NULL ;core_tmr_release_req (se_cmd->se_tmr_req);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 156/438 octeontx2: cn20k: Coordinate default rules with NIX LF lifecycle
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratheesh Kannoth <[email protected]>
[ Upstream commit aac055dbc0fadf64c9d6fbcfc066b8ba33216dc4 ]
Add NIX_LF_DONT_FREE_DFT_IDXS so the PF can send NIX LF free during hw reinit or teardown without the AF freeing CN20K default NPC rule indexes while the driver still owns that state (otx2_init_hw_resources and otx2_free_hw_resources).
On CN20K, allocate default NPC rules from NIX LF alloc before nix_interface_init, roll back with npc_cn20k_dft_rules_free on failure, and free from NIX LF free when the new flag is not set. Tighten rvu_mbox_handler_nix_lf_alloc error handling: use a single rc, propagate qmem_alloc and other errors, and set -ENOMEM only when kcalloc fails (remove the blanket -ENOMEM at the free_mem path).
Stable-dep-of: 3bd438a58e91 ("octeontx2-af: Block VFs from clobbering special CGX PKIND state")
--- .../net/ethernet/marvell/octeontx2/af/mbox.h | 1 + .../ethernet/marvell/octeontx2/af/rvu_nix.c | 77 +++++++++++++------ .../ethernet/marvell/octeontx2/af/rvu_npc.c | 20 +++-- .../ethernet/marvell/octeontx2/nic/otx2_pf.c | 6 +- 4 files changed, 69 insertions(+), 35 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/mbox.h +1 -0
@@ -1008,6 +1008,7 @@ struct nix_lf_free_req {struct mbox_msghdr hdr;#define NIX_LF_DISABLE_FLOWS BIT_ULL(0)#define NIX_LF_DONT_FREE_TX_VTAG BIT_ULL(1) +#define NIX_LF_DONT_FREE_DFT_IDXS BIT_ULL(2)u64 flags; };
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +52 -25
165 lines not on this page · raw message
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +14 -6
@@ -1285,11 +1285,18 @@ void npc_enadis_default_mce_entry(struct rvu *rvu, u16 pcifunc,struct nix_mce_list *mce_list;int index, blkaddr, mce_idx;struct rvu_pfvf *pfvf; +u16 ptr[4 ];/* multicast pkt replication is not enabled for AF's VFs & SDP links */ if (is_lbk_vf (rvu, pcifunc) ||is_sdp_pfvf (rvu, pcifunc))return ; +/* In cn20k, only CGX mapped devices have default MCAST entry */ +if (is_cn20k (rvu->pdev) && +npc_cn20k_dft_rules_idx_get (rvu, pcifunc, &ptr[0 ], &ptr[1 ], + &ptr[2 ], &ptr[3 ])) +return ; + blkaddr =rvu_get_blkaddr (rvu,BLKTYPE_NPC ,0 );if (blkaddr <0 )return ;
@@ -1329,9 +1336,12 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,struct rvu_pfvf *pfvf =rvu_get_pfvf (rvu, pcifunc);struct npc_mcam *mcam = &rvu->hw->mcam;int index, blkaddr; +u16 ptr[4 ];/* only CGX or LBK interfaces have default entries */ -if (is_cn20k (rvu->pdev) && !npc_is_cgx_or_lbk (rvu, pcifunc)) +if (is_cn20k (rvu->pdev) && +npc_cn20k_dft_rules_idx_get (rvu, pcifunc, &ptr[0 ], &ptr[1 ], + &ptr[2 ], &ptr[3 ]))return ; blkaddr =rvu_get_blkaddr (rvu,BLKTYPE_NPC ,0 );
@@ -4075,12 +4085,10 @@ void rvu_npc_clear_ucast_entry(struct rvu *rvu, int pcifunc, int nixlf) ucast_idx =npc_get_nixlf_mcam_index (mcam, pcifunc, nixlf,NIXLF_UCAST_ENTRY ); -if (ucast_idx <0 ) { -dev_err (rvu->dev, -"%s: Error to get ucast entry for pcifunc=%#x\n" , - __func__, pcifunc); + +/* In cn20k, default rules are freed before detach rsrc */ +if (ucast_idx <0 )return ; - }npc_enable_mcam_entry (rvu, mcam, blkaddr, ucast_idx, false);
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +2 -4
@@ -1053,7 +1053,6 @@ irqreturn_t otx2_pfaf_mbox_intr_handler(int irq, void *pf_irq)/* Clear the IRQ */ otx2_write64 (pf,RVU_PF_INT ,BIT_ULL (0 )); - mbox_data =otx2_read64 (pf,RVU_PF_PFAF_MBOX0 );if (mbox_data &MBOX_UP_MSG ) {
@@ -1727,7 +1726,7 @@ int otx2_init_hw_resources(struct otx2_nic *pf)mutex_lock (&mbox->lock); free_req =otx2_mbox_alloc_msg_nix_lf_free (mbox);if (free_req) { - free_req->flags =NIX_LF_DISABLE_FLOWS ; + free_req->flags =NIX_LF_DISABLE_FLOWS |NIX_LF_DONT_FREE_DFT_IDXS ;if (otx2_sync_mbox_msg (mbox))dev_err (pf->dev,"%s failed to free nixlf\n" , __func__); }
@@ -1801,7 +1800,7 @@ void otx2_free_hw_resources(struct otx2_nic *pf)/* Reset NIX LF */ free_req =otx2_mbox_alloc_msg_nix_lf_free (mbox);if (free_req) { - free_req->flags =NIX_LF_DISABLE_FLOWS ; + free_req->flags =NIX_LF_DISABLE_FLOWS |NIX_LF_DONT_FREE_DFT_IDXS ;if (!(pf->flags &OTX2_FLAG_PF_SHUTDOWN )) free_req->flags |=NIX_LF_DONT_FREE_TX_VTAG ;if (otx2_sync_mbox_msg (mbox))
@@ -1924,7 +1923,6 @@ int otx2_alloc_queue_mem(struct otx2_nic *pf)struct otx2_qset *qset = &pf->qset;struct otx2_cq_poll *cq_poll; -/* RQ and SQs are mapped to different CQs, * so find out max CQ IRQs (i.e CINTs) needed. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 157/438 octeontx2-af: Block VFs from clobbering special CGX PKIND state
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hariprasad Kelam <[email protected]>
[ Upstream commit 3bd438a58e910db5dc369aa25dfed1fc95f1b596 ]
PF and VF NIX LFs that share a CGX LMAC reuse the same hardware PKIND programming. When HiGig2 or EDSA parsing is enabled, a VF NIX LF alloc must not reset the LMAC RX PKIND or default TX parse config over the PF setup.
Add cgx_get_pkind() and rvu_cgx_is_pkind_config_permitted() so VFs skip cgx_set_pkind(), rvu_npc_set_pkind(), and NIX_AF_LFX_TX_PARSE_CFG updates when the LMAC is using NPC_RX_HIGIG_PKIND or NPC_RX_EDSA_PKIND.
--- .../net/ethernet/marvell/octeontx2/af/cgx.c | 12 +++ .../net/ethernet/marvell/octeontx2/af/cgx.h | 1 + .../net/ethernet/marvell/octeontx2/af/rvu.h | 2 + .../ethernet/marvell/octeontx2/af/rvu_cgx.c | 79 +++++++++++++++++++ .../ethernet/marvell/octeontx2/af/rvu_nix.c | 22 +++++- .../ethernet/marvell/octeontx2/af/rvu_npc.c | 29 ++++--- 6 files changed, 131 insertions(+), 14 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/cgx.c +12 -0
@@ -518,6 +518,18 @@ int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind)return 0 ; } +int cgx_get_pkind (void *cgxd,u8 lmac_id,int *pkind) +{ +struct cgx *cgx = cgxd; + +if (!is_lmac_valid (cgx, lmac_id)) +return -ENODEV ; + + *pkind =cgx_read (cgx, lmac_id, cgx->mac_ops->rxid_map_offset); + *pkind = *pkind &0x3F ; +return 0 ; +} +static u8 cgx_get_lmac_type (void *cgxd,int lmac_id) {struct cgx *cgx = cgxd;
drivers/net/ethernet/marvell/octeontx2/af/cgx.h +1 -0
@@ -141,6 +141,7 @@ int cgx_get_cgxid(void *cgxd);int cgx_get_lmac_cnt (void *cgxd);void *cgx_get_pdata (int cgx_id);int cgx_set_pkind (void *cgxd,u8 lmac_id,int pkind); +int cgx_get_pkind (void *cgxd,u8 lmac_id,int *pkind);int cgx_lmac_evh_register (struct cgx_event_cb *cb,void *cgxd,int lmac_id);int cgx_lmac_evh_unregister (void *cgxd,int lmac_id);int cgx_get_tx_stats (void *cgxd,int lmac_id,int idx,u64 *tx_stat);
drivers/net/ethernet/marvell/octeontx2/af/rvu.h +2 -0
@@ -1113,6 +1113,8 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, u8 *intf, u8 *ena);int npc_config_cntr_default_entries (struct rvu *rvu,bool enable);bool is_cgx_config_permitted (struct rvu *rvu,u16 pcifunc); +bool rvu_cgx_check_permission_and_set_pkind (struct rvu *rvu,u16 pcifunc,int pkind); +bool rvu_cgx_is_pkind_config_permitted (struct rvu *rvu,u16 pcifunc);bool is_mac_feature_supported (struct rvu *rvu,int pf,int feature);u32 rvu_cgx_get_fifolen (struct rvu *rvu);void *rvu_first_cgx_pdata (struct rvu *rvu);
drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +79 -0
82 lines not on this page · raw message
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +18 -4
@@ -363,8 +363,8 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf, pfvf->tx_chan_cnt =1 ; rsp->tx_link = cgx_id * hw->lmac_per_cgx + lmac_id; -cgx_set_pkind (rvu_cgx_pdata (cgx_id, rvu), lmac_id, pkind); -rvu_npc_set_pkind (rvu, pkind, pfvf); +if (rvu_cgx_check_permission_and_set_pkind (rvu, pcifunc, pkind)) +rvu_npc_set_pkind (rvu, pkind, pfvf);break ;case NIX_INTF_TYPE_LBK : vf = (pcifunc &RVU_PFVF_FUNC_MASK ) -1 ;
@@ -1505,13 +1505,15 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,struct nix_lf_alloc_req *req, struct nix_lf_alloc_rsp *rsp) { - int nixlf, qints, hwctx_size, intf, rc = 0; + int nixlf, qints, hwctx_size, intf, rc = 0, pf;u16 bcast, mcast, promisc, ucast;struct rvu_hwinfo *hw = rvu->hw;u16 pcifunc = req->hdr.pcifunc; +u8 cgx_id =0 , lmac_id =0 ;bool rules_created = false;struct rvu_block *block;struct rvu_pfvf *pfvf; +struct cgx *cgxd;u64 cfg, ctx_cfg;int blkaddr;
@@ -1685,8 +1687,20 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,rvu_write64 (rvu, blkaddr,NIX_AF_LFX_RX_CFG (nixlf), req->rx_cfg);/* Configure pkind for TX parse config */ + + pf =rvu_get_pf (rvu->pdev, pcifunc); cfg =NPC_TX_DEF_PKIND ; -rvu_write64 (rvu, blkaddr,NIX_AF_LFX_TX_PARSE_CFG (nixlf), cfg); + +if (is_pf_cgxmapped (rvu, pf) &&is_vf (pcifunc)) { +rvu_get_cgx_lmac_id (rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + cgxd =rvu_cgx_pdata (cgx_id, rvu); +mutex_lock (&cgxd->lock); +if (rvu_cgx_is_pkind_config_permitted (rvu, pcifunc)) +rvu_write64 (rvu, blkaddr,NIX_AF_LFX_TX_PARSE_CFG (nixlf), cfg); +mutex_unlock (&cgxd->lock); + }else { +rvu_write64 (rvu, blkaddr,NIX_AF_LFX_TX_PARSE_CFG (nixlf), cfg); + }if (is_rep_dev (rvu, pcifunc)) { pfvf->tx_chan_base =RVU_SWITCH_LBK_CHAN ;
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +19 -10
@@ -19,6 +19,7 @@#include "cn20k/npc.h" #include "rvu_npc.h" #include "cn20k/reg.h" +#include "lmac_common.h" #define RSVD_MCAM_ENTRIES_PER_PF 3/* Broadcast, Promisc and AllMulticast */ #define RSVD_MCAM_ENTRIES_PER_NIXLF 1/* Ucast for LFs */
@@ -3912,10 +3913,11 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir, {struct rvu_pfvf *pfvf =rvu_get_pfvf (rvu, pcifunc); -int blkaddr, nixlf, rc, intf_mode;int pf =rvu_get_pf (rvu->pdev, pcifunc); +int blkaddr, nixlf, rc, intf_mode; +u8 cgx_id =0 , lmac_id =0 ;u64 rxpkind, txpkind; -u8 cgx_id, lmac_id; +struct cgx *cgxd;/* use default pkind to disable edsa/higig */ rxpkind =rvu_npc_get_pkind (rvu, pf);
@@ -3939,12 +3941,8 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,/* rx pkind set req valid only for cgx mapped PFs */ if (!is_cgx_config_permitted (rvu, pcifunc))return 0 ; -rvu_get_cgx_lmac_id (rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); - - rc =cgx_set_pkind (rvu_cgx_pdata (cgx_id, rvu), lmac_id, - rxpkind); -if (rc) -return rc; +if (!rvu_cgx_check_permission_and_set_pkind (rvu, pcifunc, rxpkind)) +return -EINVAL ; }if (dir &PKIND_TX ) {
@@ -3953,8 +3951,19 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,if (rc)return rc; -rvu_write64 (rvu, blkaddr,NIX_AF_LFX_TX_PARSE_CFG (nixlf), - txpkind); +if (is_pf_cgxmapped (rvu, pf) &&is_vf (pcifunc)) { +rvu_get_cgx_lmac_id (rvu->pf2cgxlmac_map[pf], &cgx_id, + &lmac_id); + cgxd =rvu_cgx_pdata (cgx_id, rvu); +mutex_lock (&cgxd->lock); +if (rvu_cgx_is_pkind_config_permitted (rvu, pcifunc)) +rvu_write64 (rvu, blkaddr,NIX_AF_LFX_TX_PARSE_CFG (nixlf), + txpkind); +mutex_unlock (&cgxd->lock); + }else { +rvu_write64 (rvu, blkaddr,NIX_AF_LFX_TX_PARSE_CFG (nixlf), + txpkind); + } } pfvf->intf_mode = intf_mode;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 158/438 scsi: mpi3mr: Fix potential deadlock in mpi3mr_fault_uevent_emit
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chandrakanth Patil <[email protected]>
[ Upstream commit ccff8c92571500fcfed21281e33daaf645bf692f ]
mpi3mr_fault_uevent_emit() runs from the fault watchdog and reset paths where host I/O may already be blocked. GFP_KERNEL allocations here, both the local kzalloc_obj() and the ones inside kobject_uevent_env() itself, can trigger reclaim that waits on that blocked I/O and deadlock.
Use memalloc_noio_save()/restore() to cover the whole call instead of just the local allocation.
--- drivers/scsi/mpi3mr/mpi3mr_fw.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/scsi/mpi3mr/mpi3mr_fw.c +7 -2
@@ -9,6 +9,7 @@#include "mpi3mr.h" #include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/sched/mm.h> static int mpi3mr_issue_reset (struct mpi3mr_ioc *mrioc,u16 reset_type,u16 reset_reason);
@@ -1287,11 +1288,14 @@ static void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_ioc *mrioc)static void mpi3mr_fault_uevent_emit (struct mpi3mr_ioc *mrioc) {struct kobj_uevent_env *env; +unsigned int noio_flag;int ret; + noio_flag =memalloc_noio_save (); + env =kzalloc_obj (*env);if (!env) -return ; + goto out_restore; ret =add_uevent_var (env,"DRIVER=%s" , mrioc->driver_name);if (ret)
@@ -1326,7 +1330,8 @@ static void mpi3mr_fault_uevent_emit(struct mpi3mr_ioc *mrioc) out_free:kfree (env); - +out_restore: +memalloc_noio_restore (noio_flag); }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 159/438 scsi: ufs: core: Initialize hba->rpmbs list in ufshcd
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ao Sun <[email protected]>
[ Upstream commit 0279fd451a9971c0d5b959fc59f3e11b55e1694e ]
Initialize the hba->rpmbs list in ufshcd_alloc_host() to prevent NULL pointer dereference in the device teardown path if ufs_rpmb_probe() fails.
--- drivers/ufs/core/ufs-rpmb.c | 2 -- drivers/ufs/core/ufshcd.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-)
drivers/ufs/core/ufs-rpmb.c +0 -2
@@ -152,8 +152,6 @@ int ufs_rpmb_probe(struct ufs_hba *hba)return -EINVAL ; } -INIT_LIST_HEAD (&hba->rpmbs); -struct rpmb_descr descr = { .type =RPMB_TYPE_UFS , .route_frames = ufs_rpmb_route_frames,
drivers/ufs/core/ufshcd.c +1 -0
@@ -10924,6 +10924,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle) hba->nop_out_timeout =NOP_OUT_TIMEOUT ;ufshcd_set_sg_entry_size (hba,sizeof (struct ufshcd_sg_entry ));INIT_LIST_HEAD (&hba->clk_list_head); +INIT_LIST_HEAD (&hba->rpmbs);spin_lock_init (&hba->outstanding_lock); *hba_handle = hba;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 160/438 net: sxgbe: free TX rings on RX allocation failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
[ Upstream commit c870f7e2890b9f78ac84515a9809cc5c183c975e ]
When RX descriptor ring allocation fails, init_dma_desc_rings() only frees the partially allocated RX rings and returns. The TX rings that were allocated earlier in the same function are leaked.
Rearrange error labels to clean up TX rings upon RX failures.
--- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +4 -5
@@ -597,14 +597,13 @@ static int init_dma_desc_rings(struct net_device *netd)return 0 ; -txalloc_err: -while (queue_num--) -free_tx_ring (priv->device, priv->txq[queue_num], tx_rsize); -return ret; - rxalloc_err:while (queue_num--)free_rx_ring (priv->device, priv->rxq[queue_num], rx_rsize); + queue_num =SXGBE_TX_QUEUES ; +txalloc_err: +while (queue_num--) +free_tx_ring (priv->device, priv->txq[queue_num], tx_rsize);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 161/438 net: sxgbe: check descriptor ring allocation failures
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
[ Upstream commit 51b093a7ba27476e1f639455f005e8d2e75390e4 ]
sxgbe_open() ignores the return value of init_dma_desc_rings() and continues to program DMA with invalid ring addresses when allocation fails. Check the return value and disconnect the PHY on failure.
--- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +4 -1
@@ -1078,7 +1078,9 @@ static int sxgbe_open(struct net_device *dev) priv->dma_buf_sz =SXGBE_ALIGN (DMA_BUFFER_SIZE ); priv->tx_tc =TC_DEFAULT ; priv->rx_tc =TC_DEFAULT ; -init_dma_desc_rings (dev); + ret =init_dma_desc_rings (dev); +if (ret) + goto init_phy_error;/* DMA initialization and SW reset */ ret =sxgbe_init_dma_engine (priv);
@@ -1187,6 +1189,7 @@ static int sxgbe_open(struct net_device *dev) init_error:free_dma_desc_resources (priv); +init_phy_error:if (dev->phydev)phy_disconnect (dev->phydev); phy_error:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 162/438 can: isotp: check register_netdevice_notifier() error in module init
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Minhong He <[email protected]>
[ Upstream commit ef09a13c5afac41a3c4b5f22b8572820d9e7518c ]
Register the netdevice notifier before can_proto_register() and check the return value. If protocol registration fails, unregister the notifier before returning the error.
Align isotp_module_init() with the reordering already done for raw.c (commit c28b3bffe49e ("can: raw: process optimization in raw_init()")) and bcm.c (commit edd1a7e42f1d ("can: bcm: registration process optimization in bcm_module_init()")).
--- net/can/isotp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
net/can/isotp.c +9 -4
@@ -1907,13 +1907,18 @@ static __init int isotp_module_init(void)pr_info ("can: isotp protocol (max_pdu_size %d)\n" , max_pdu_size); + err =register_netdevice_notifier (&canisotp_notifier); +if (err) +return err; + err =can_proto_register (&isotp_can_proto); -if (err <0 ) +if (err <0 ) {pr_err ("can: registration of isotp protocol failed %pe\n" ,ERR_PTR (err)); -else -register_netdevice_notifier (&canisotp_notifier); +unregister_netdevice_notifier (&canisotp_notifier); +return err; + } -return err; +return 0 ; } static __exit void isotp_module_exit(void)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 163/438 drm/i915/dp: Ignore the sinks DSC max FRL rate without a PCON DSC encoder
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Kaplan <[email protected]>
[ Upstream commit 8891e39e89042e285fd82fdde325d1311ec750a1 ]
intel_dp_hdmi_sink_max_frl() limits the sink's max FRL rate by its DSC max FRL rate whenever the sink supports DSC 1.2. However, the DSC max FRL rate (HF-VSDB DSC_Max_FRL_Rate) only applies to compressed video transport, which requires a DSC 1.2 encoder in the PCON (configured via intel_dp_pcon_dsc_configure()). Without such an encoder the HDMI link always carries uncompressed video, for which the regular Max_FRL_Rate is the correct limit.
Applying the DSC limit unconditionally trains the FRL link at a lower rate than both the PCON and the sink support.
E.g. an LG OLED G4 (Max_FRL_Rate 48 Gbps, DSC_Max_FRL_Rate 24 Gbps) behind a Synaptics VMM7100 PCON (PCON max FRL bw 48 Gbps, no DSC encoder):
Sink max rate from EDID = 24 Gbps
FRL trained with : 24 Gbps
while Windows/macOS train the same hardware at 40/48 Gbps. The too low FRL rate needlessly constrains the formats available to the sink.
Only apply the sink's DSC max FRL rate if the PCON has a DSC 1.2 encoder, matching the gate in intel_dp_pcon_dsc_configure(). PCONs with a DSC encoder keep the current conservative behavior, since the link is trained once and compressed transport may be used for any subsequent mode.
With this the setup above trains at 48 Gbps.
Tested on PTL (xe) with the above PCON/sink combo.
--- drivers/gpu/drm/i915/display/intel_dp.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/display/intel_dp.c +8 -1
@@ -4109,7 +4109,14 @@ static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp) rate_per_lane = info->hdmi.max_frl_rate_per_lane; max_frl_rate = max_lanes * rate_per_lane; -if (info->hdmi.dsc_cap.v_1p2) { +/* +* The sink's DSC max FRL rate only applies to compressed video +* transport, which requires a DSC 1.2 encoder in the PCON. Without +* one the HDMI link always carries uncompressed video, for which +* the regular max FRL rate is the limit. +*/ +if (drm_dp_pcon_enc_is_dsc_1_2 (intel_dp->pcon_dsc_dpcd) && + info->hdmi.dsc_cap.v_1p2) { max_dsc_lanes = info->hdmi.dsc_cap.max_lanes; dsc_rate_per_lane = info->hdmi.dsc_cap.max_frl_rate_per_lane;if (max_dsc_lanes && dsc_rate_per_lane)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 164/438 drm/xe/pt: check no-DMA huge-pte cases before DMA segment test
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Himal Prasad Ghimiray <[email protected]>
[ Upstream commit d94f82d57e7a86def6946f22b34eb53f96628f8a ]
On a non-range clear, curs.size is never set, so the segment test (next - va_curs_start > curs->size) returns false for every level > 0 before the clear_pt short-circuit is reached. The clear then descends to level 0 instead of forming a huge zero-leaf, wasting page tables and risking -ENOMEM on unbind.
Move the null-VMA, purged-BO and clear_pt short-circuits above the curs->size test. The bind path always sets curs.size, so it is unaffected.
v2
- Also set curs.size on the clear path so the cursor stays meaningful during the walk. clear_pt is only reached with range == NULL, so assert that invariant. (Matthew Brost)
--- drivers/gpu/drm/xe/xe_pt.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/gpu/drm/xe/xe_pt.c +8 -5
@@ -442,10 +442,6 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level,if (!xe_pt_covers (addr, next, level, &xe_walk->base))return false; -/* Does the DMA segment cover the whole pte? */ -if (next - xe_walk->va_curs_start > xe_walk->curs->size) -return false; -/* null VMA's and purged BO's do not have dma addresses */ if (xe_vma_is_null (xe_walk->vma) || (bo &&xe_bo_is_purged (bo)))return true;
@@ -454,6 +450,10 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level,if (xe_walk->clear_pt)return true; +/* Does the DMA segment cover the whole pte? */ +if (next - xe_walk->va_curs_start > xe_walk->curs->size) +return false; +/* Is the DMA address huge PTE size aligned? */ size = next - addr; dma = addr - xe_walk->va_curs_start +xe_res_dma (xe_walk->curs);
@@ -774,8 +774,11 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma, } xe_walk.needs_64K = (vm->flags &XE_VM_FLAG_64K ); -if (clear_pt) +if (clear_pt) { +xe_assert (xe, !range); + curs.size =xe_vma_size (vma); goto walk_pt; + }if (vma->gpuva.flags &XE_VMA_ATOMIC_PTE_BIT ) { xe_walk.default_vram_pte =xe_atomic_for_vram (vm, vma) ?XE_USM_PPGTT_PTE_AE :0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 165/438 fprobe: Fix module reference count leak on error in register_fprobe()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit 8cf2f40ceb85047ad8a84dffae3bebc9fed18216 ]
In register_fprobe(), get_ips_from_filter() resolves target function addresses and increments module reference counts via try_module_get() for symbols in kernel modules. If get_ips_from_filter() fails on the second pass and returns an error, register_fprobe() returned directly without releasing module references acquired up to that point.
Fix this by ensuring the cleanup loop executing module_put() runs even when get_ips_from_filter() returns a negative error.
--- kernel/trace/fprobe.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
kernel/trace/fprobe.c +2 -4
@@ -961,10 +961,8 @@ int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilterreturn -ENOMEM ; ret =get_ips_from_filter (filter, notfilter, addrs, mods, num); -if (ret <0 ) -return ret; - - ret =register_fprobe_ips (fp, addrs, ret); +if (ret >=0 ) + ret =register_fprobe_ips (fp, addrs, ret);for (int i =0 ; i < num; i++) {if (mods[i])
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 166/438 tracing/mmiotrace: Reset dropped_count in mmio_reset_data()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit c786d2bdf1f3964deee192ad942dee2a741c1e2c ]
mmio_reset_data() is called during tracer initialization, reset, and start. While it resets overrun_detected and prev_overruns, it neglects to reset dropped_count. Consequently, dropped event counts from prior tracing sessions persist in dropped_count and corrupt overrun reports in subsequent runs.
Fix this by explicitly calling atomic_set(&dropped_count, 0) in mmio_reset_data().
--- kernel/trace/trace_mmiotrace.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/trace_mmiotrace.c +1 -0
@@ -29,6 +29,7 @@ static void mmio_reset_data(struct trace_array *tr) { overrun_detected = false; prev_overruns =0 ; +atomic_set (&dropped_count,0 );tracing_reset_online_cpus (&tr->array_buffer); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 167/438 tracing/mmiotrace: Add NULL check for mmio_trace_array in logging functions
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit 12b80cdbc54cf615b4717a4e8180063408091ea2 ]
mmio_trace_rw() and mmio_trace_mapping() retrieve mmio_trace_array into tr and pass it to __trace_mmiotrace_rw() and __trace_mmiotrace_map(). If these functions are invoked while mmio_trace_array is NULL (e.g. before initialization or after disabled), accessing tr->array_buffer.buffer will result in a NULL pointer dereference crash.
Fix this by adding an explicit NULL check for tr at the beginning of __trace_mmiotrace_rw() and __trace_mmiotrace_map().
--- kernel/trace/trace_mmiotrace.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
kernel/trace/trace_mmiotrace.c +10 -2
@@ -294,11 +294,15 @@ device_initcall(init_mmio_trace);static void __trace_mmiotrace_rw (struct trace_array *tr,struct mmiotrace_rw *rw) { -struct trace_buffer *buffer = tr->array_buffer.buffer; +struct trace_buffer *buffer;struct ring_buffer_event *event;struct trace_mmiotrace_rw *entry;unsigned int trace_ctx; +if (!tr) +return ; + + buffer = tr->array_buffer.buffer; trace_ctx =tracing_gen_ctx_flags (0 ); event =trace_buffer_lock_reserve (buffer,TRACE_MMIO_RW ,sizeof (*entry), trace_ctx);
@@ -321,11 +325,15 @@ void mmio_trace_rw(struct mmiotrace_rw *rw)static void __trace_mmiotrace_map (struct trace_array *tr,struct mmiotrace_map *map) { -struct trace_buffer *buffer = tr->array_buffer.buffer; +struct trace_buffer *buffer;struct ring_buffer_event *event;struct trace_mmiotrace_map *entry;unsigned int trace_ctx; +if (!tr) +return ; + + buffer = tr->array_buffer.buffer; trace_ctx =tracing_gen_ctx_flags (0 ); event =trace_buffer_lock_reserve (buffer,TRACE_MMIO_MAP ,sizeof (*entry), trace_ctx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 168/438 riscv: drop __init from vec_check_unaligned_access_speed_all_cpus
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anirudh Srinivasan <[email protected]>
[ Upstream commit f51fed61eea0daba2f95f1a6074085e4cd513c7b ]
This function runs within a kthread and need not necessarily finish before system finishes boot and free_initmem() unmaps the .init.text section. This function makes calls to SBI for probing unaligned access speed, and if this is slow for some reason (say some debug prints were added to SBI), the kthread can still be running at this point and result in an instruction page fault when trying to fetch from the freed region.
[ 25.642087] Unable to handle kernel paging request at virtual address ffffffff80a04ef8 [ 25.646694] Current vec_check_unali pgtable: 4K pagesize, 48-bit VAs, pgdp=0x00004000316e9000 [ 25.653170] [ffffffff80a04ef8] pgd=000010004be7e401, p4d=000010004be7e401, pud=000010004be7e001, pmd=000010000c3000e3 [ 25.661244] Oops [#1] [ 25.662997] Modules linked in: [ 25.665357] CPU: 3 UID: 0 PID: 42 Comm: vec_check_unali Not tainted 7.0.0-tt-blackhole-asrinivasan-00007-g30ff73f18211 #570 PREEMPTLAZY [ 25.674669] Hardware name: Tenstorrent Blackhole (DT) [ 25.678545] epc : vec_check_unaligned_access_speed_all_cpus+0x18/0x2c [ 25.683458] ra : vec_check_unaligned_access_speed_all_cpus+0x18/0x2c [ 25.688372] epc : ffffffff80a04ef8 ra : ffffffff80a04ef8 sp : ffff8f8000203e20 [ 25.693874] gp : ffffffff814dc168 tp : ffffaf8001ad9900 t0 : 0000000000000000 [ 25.699401] t1 : fffffffffffffff0 t2 : ffffaf8001ad9a10 s0 : ffff8f8000203e30 [ 25.704912] s1 : ffffaf80018dc780 a0 : 0000000000000000 a1 : 0000000000000002 [ 25.710407] a2 : 00000000000001f0 a3 : 0000000000000018 a4 : 0000000000000000 [ 25.715917] a5 : 0000000000000000 a6 : ffffaf8001c03d98 a7 : ffffaf8001c03e30 [ 25.721419] s2 : ffff8f8000023c98 s3 : ffffaf8001aa1240 s4 : ffffffff80a04ee0 [ 25.726937] s5 : 0000000000000000 s6 : 0000000000000000 s7 : 0000000000000000 [ 25.732450] s8 : 0000000000000000 s9 : 0000000000000000 s10: 0000000000000000 [ 25.737944] s11: 0000000000000000 t3 : 0000000000000002 t4 : 0000000000000402 [ 25.743481] t5 : 0000000000000040 t6 : 0000000000000004 ssp : 0000000000000000 [ 25.749024] status: 0000000200000120 badaddr: ffffffff80a04ef8 cause: 000000000000000c [ 25.755060] [<ffffffff80a04ef8>] vec_check_unaligned_access_speed_all_cpus+0x18/0x2c [ 25.760964] [<ffffffff80047a10>] kthread+0xd8/0xfc [ 25.764660] [<ffffffff80010c48>] ret_from_fork_kernel+0x18/0x1c4 [ 25.769220] [<ffffffff80895fe6>] ret_from_fork_kernel_asm+0x16/0x18 [ 25.774018] Code: cccc cccc cccc cccc cccc cccc cccc cccc cccc cccc (cccc) cccc
Drop __init from its signature so that this doesn't happen.
--- arch/riscv/kernel/unaligned_access_speed.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/riscv/kernel/unaligned_access_speed.c +2 -2
@@ -314,7 +314,7 @@ static void check_vector_unaligned_access(struct work_struct *work __always_unus }/* Measure unaligned access speed on all CPUs present at boot in parallel. */ -static int __init vec_check_unaligned_access_speed_all_cpus (void *unused__always_unused ) +static int vec_check_unaligned_access_speed_all_cpus (void *unused__always_unused ) {schedule_on_each_cpu (check_vector_unaligned_access);riscv_hwprobe_complete_async_probe ();
@@ -322,7 +322,7 @@ static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __alway return 0; }#else /* CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS */ -static int __init vec_check_unaligned_access_speed_all_cpus (void *unused__always_unused ) +static int vec_check_unaligned_access_speed_all_cpus (void *unused__always_unused ) {return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 169/438 accel/qaic: use sizeof(*trans_hdr) for transaction length check
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Bilal <[email protected]>
[ Upstream commit d6c075f797a672a6e3bd2fd44aee713801698ec2 ]
In encode_message() the per-transaction lower-bound check compares trans_hdr->len against sizeof(trans_hdr), i.e. the size of the pointer, instead of sizeof(*trans_hdr), the size of struct qaic_manage_trans_hdr.
Every other length check in this file (encode_message() at the loop guard, decode_message(), etc.) correctly uses sizeof(*trans_hdr), so this is an inconsistency. On 64-bit builds the pointer and the struct are both 8 bytes, so the check is correct by coincidence and there is no behavioural change. On 32-bit builds the pointer is 4 bytes, which weakens the minimum-length check below the 8-byte header size.
Use sizeof(*trans_hdr) so the check validates against the actual transaction header size on all builds.
--- drivers/accel/qaic/qaic_control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/accel/qaic/qaic_control.c +1 -1
@@ -786,7 +786,7 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,break ; } trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len); -if (trans_hdr->len <sizeof (trans_hdr) || +if (trans_hdr->len <sizeof (*trans_hdr) ||size_add (user_len, trans_hdr->len) > user_msg->len) { ret = -EINVAL ;break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 170/438 riscv: mm: Fix out-of-bounds page-table walk during memory hot-remove
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit a0188cc133696627857d16054e43f9ebc7efc821 ]
remove_pud_mapping() and remove_p4d_mapping() obtain a child table base with pud_offset(p4dp, 0) and p4d_offset(pgd, 0), then add the index for addr.
RISC-V folds page-table levels at runtime. When a level is folded, its offset helper returns the parent entry itself, but the index can still be nonzero. Adding it walks past the parent table. Sv48 folds P4D, while Sv39 folds both P4D and PUD, so memory hot-remove can descend into unrelated memory and pass an invalid page to __free_pages(). This can trigger:
kernel BUG at include/linux/mm.h:1810!
VM_BUG_ON_PAGE(page_ref_count(page) == 0)
arch_remove_memory+0x1e/0x5c try_remove_memory+0x15e/0x200 remove_memory+0x24/0x3c
Only add the index when the corresponding page-table level is enabled, matching p4d_offset() and pud_offset().
--- arch/riscv/mm/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/riscv/mm/init.c +2 -2
@@ -1629,7 +1629,7 @@ static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, unfor (; addr < end; addr = next) { next =pud_addr_end (addr, end); - pudp = pud_base +pud_index (addr); + pudp = pgtable_l4_enabled ? pud_base +pud_index (addr) : pud_base; pud =pudp_get (pudp);if (!pud_present (pud))continue ;
@@ -1660,7 +1660,7 @@ static void __meminit remove_p4d_mapping(p4d_t *p4d_base, unsigned long addr, unfor (; addr < end; addr = next) { next =p4d_addr_end (addr, end); - p4dp = p4d_base +p4d_index (addr); + p4dp = pgtable_l5_enabled ? p4d_base +p4d_index (addr) : p4d_base; p4d =p4dp_get (p4dp);if (!p4d_present (p4d))continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 171/438 ring-buffer: Fix reader page read offset for remote buffers
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Donnefort <[email protected]>
[ Upstream commit 78cd56c2a9d2e8da763cea3b06b636266ca66911 ]
A page swapped in by __rb_get_reader_page_from_remote() retains its stale read offset, causing subsequent reads to skip events or read past valid data. Fix it.
--- kernel/trace/ring_buffer.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/ring_buffer.c +1 -0
@@ -5624,6 +5624,7 @@ __rb_get_reader_page_from_remote(struct ring_buffer_per_cpu *cpu_buffer) cpu_buffer->head_page = new_head; cpu_buffer->reader_page = new_reader; + cpu_buffer->reader_page->read =0 ; cpu_buffer->pages = &new_head->list; cpu_buffer->read_stamp = new_reader->page->time_stamp; cpu_buffer->lost_events = cpu_buffer->meta_page->reader.lost_events;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 172/438 ipv6: release fib6_null_entry on subtree failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
[ Upstream commit 93cad1f6bd1e27c75c4a5ab000c2a2fc01181ccf ]
When adding a source-specific route creates a new subtree, fib6_add() installs fib6_null_entry as the temporary leaf of the new subtree root and takes a fib6_info reference for that holder.
If adding the first source leaf fails, the code frees the just allocated subtree root but leaves that hold behind. fib6_null_entry is a per-netns sentinel and is freed directly at netns teardown, so this does not keep the object alive. However, it leaves its visible refcount permanently elevated and can eventually saturate the refcount on repeated failures.
Drop the null-entry reference before freeing the unlinked subtree root.
--- net/ipv6/ip6_fib.c | 1 + 1 file changed, 1 insertion(+)
net/ipv6/ip6_fib.c +1 -0
@@ -1495,6 +1495,7 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,root, and then (in failure) stale node in main tree. */ +fib6_info_release (info->nl_net->ipv6.fib6_null_entry);node_free_immediate (info->nl_net, sfn); err =PTR_ERR (sn); goto failure;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 173/438 riscv: vdso: Only try to install vDSO when present
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Weißschuh <[email protected]>
[ Upstream commit c052927905710de1ab7364bf1925efbd12517ea3 ]
vdso.so.dbg is only built with CONFIG_MMU.
--- arch/riscv/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/riscv/Makefile +1 -1
@@ -168,7 +168,7 @@ vdso_prepare: prepare0 endif endif -vdso-install-y += arch/riscv/kernel/vdso/vdso.so.dbg +vdso-install-$(CONFIG_MMU) += arch/riscv/kernel/vdso/vdso.so.dbg vdso-install-$(CONFIG_RISCV_USER_CFI) += arch/riscv/kernel/vdso_cfi/vdso-cfi.so.dbg vdso-install-$(CONFIG_COMPAT) += arch/riscv/kernel/compat_vdso/compat_vdso.so.dbg
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 174/438 net: dsa: mt7530: check bus->read() errors in the MDIO regmap backend
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Golle <[email protected]>
[ Upstream commit b4ce102b2cd88424c5860fbbb20b9eb343a93bf4 ]
bus->read() returns a negative errno on failure, but mt7530_regmap_read() assigns it to a u16, truncating e.g. -ETIMEDOUT into 0xff92, and returns success. The garbage word is then consumed as register data, and read-modify-write cycles write it back to the switch. Check both reads and propagate their errors.
The same defect existed in mt7530_mii_read() since the driver was introduced and moved into the regmap backend unchanged.
--- drivers/net/dsa/mt7530-mdio.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/net/dsa/mt7530-mdio.c +9 -2
@@ -55,8 +55,15 @@ mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)if (ret <0 )return ret; - lo = bus->read (bus, priv->mdiodev->addr, r); - hi = bus->read (bus, priv->mdiodev->addr,0x10 ); + ret = bus->read (bus, priv->mdiodev->addr, r); +if (ret <0 ) +return ret; + lo = ret; + + ret = bus->read (bus, priv->mdiodev->addr,0x10 ); +if (ret <0 ) +return ret; + hi = ret; *val = (hi <<16 ) | (lo &0xffff );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 175/438 net: dsa: mt7530: error out on failed reads in ATC/VTCR command polling
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Golle <[email protected]>
[ Upstream commit ed9adac35b8fac635f40e28461505e2e5b6c8fcc ]
mt7530_fdb_cmd() and mt7530_vlan_cmd() poll the command register through a helper which returns 0 when the underlying read fails. A failed bus transaction thus clears ATC_BUSY/VTCR_BUSY and is treated as successful command completion, and the subsequent ATC_INVALID and VTCR_INVALID checks are defeated the same way.
Poll using regmap_read_poll_timeout(), which stops on read errors and propagates them, and check the completion status read as well. Take the MDIO bus lock across the sequence as the switch regmap is set up with locking disabled.
--- drivers/net/dsa/mt7530.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-)
drivers/net/dsa/mt7530.c +18 -10
@@ -248,15 +248,20 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp) {u32 val;int ret; -struct mt7530_dummy_poll p;/* Set the command operating upon the MAC address entries */ val =ATC_BUSY |ATC_MAT (0 ) | cmd;mt7530_write (priv,MT7530_ATC , val); -INIT_MT7530_DUMMY_POLL (&p, priv,MT7530_ATC ); - ret =readx_poll_timeout (_mt7530_read, &p, val, - !(val &ATC_BUSY ),20 ,20000 ); +mt7530_mutex_lock (priv); + + ret =regmap_read_poll_timeout (priv->regmap,MT7530_ATC , val, + !(val &ATC_BUSY ),20 ,20000 ); +if (!ret) + ret =regmap_read (priv->regmap,MT7530_ATC , &val); + +mt7530_mutex_unlock (priv); +if (ret <0 ) {dev_err (priv->dev,"reset timeout\n" );return ret;
@@ -265,7 +270,6 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)/* Additional sanity for read command if the specified * entry is invalid */ - val =mt7530_read (priv,MT7530_ATC );if ((cmd ==MT7530_FDB_READ ) && (val &ATC_INVALID ))return -EINVAL ;
@@ -1626,22 +1630,26 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,static int mt7530_vlan_cmd (struct mt7530_priv *priv,enum mt7530_vlan_cmd cmd,u16 vid) { -struct mt7530_dummy_poll p;u32 val;int ret; val =VTCR_BUSY |VTCR_FUNC (cmd) | vid;mt7530_write (priv,MT7530_VTCR , val); -INIT_MT7530_DUMMY_POLL (&p, priv,MT7530_VTCR ); - ret =readx_poll_timeout (_mt7530_read, &p, val, - !(val &VTCR_BUSY ),20 ,20000 ); +mt7530_mutex_lock (priv); + + ret =regmap_read_poll_timeout (priv->regmap,MT7530_VTCR , val, + !(val &VTCR_BUSY ),20 ,20000 ); +if (!ret) + ret =regmap_read (priv->regmap,MT7530_VTCR , &val); + +mt7530_mutex_unlock (priv); +if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" );return ret; } - val =mt7530_read (priv,MT7530_VTCR );if (val &VTCR_INVALID ) {dev_err (priv->dev,"read VTCR invalid\n" );return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 176/438 net: dsa: mt7530: error out on failed reads in MT7531 PHY polling
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Golle <[email protected]>
[ Upstream commit 77a9ebe8818cf6dd1699bd6728cb5d66307801d7 ]
The MT7531 indirect PHY access functions poll MT7531_PHY_IAC through a helper which returns 0 when the underlying read fails, so a failed bus transaction clears MT7531_PHY_ACS_ST and the access carries on, returning garbage PHY register data to phylib.
Poll using regmap_read_poll_timeout(), which stops on read errors and propagates them. These functions hold the MDIO bus lock across the whole sequence, so the unlocked regmap accesses remain correct. Remove the now-unused _mt7530_unlocked_read().
--- drivers/net/dsa/mt7530.c | 58 ++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 38 deletions(-)
drivers/net/dsa/mt7530.c +20 -38
@@ -191,12 +191,6 @@ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)mt7530_mutex_unlock (priv); } -static u32 -_mt7530_unlocked_read (struct mt7530_dummy_poll *p) -{ -return mt7530_mii_read (p->priv, p->reg); -} -static u32 _mt7530_read (struct mt7530_dummy_poll *p) {
@@ -553,16 +547,13 @@ static int mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad, int regnum) { - struct mt7530_dummy_poll p; u32 reg, val;int ret; -INIT_MT7530_DUMMY_POLL (&p, priv,MT7531_PHY_IAC ); -mt7530_mutex_lock (priv); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -572,8 +563,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,MT7531_MDIO_DEV_ADDR (devad) | regnum;mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -583,8 +574,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,MT7531_MDIO_DEV_ADDR (devad);mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -601,16 +592,13 @@ static int mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad, int regnum, u16 data) { - struct mt7530_dummy_poll p; u32 val, reg;int ret; -INIT_MT7530_DUMMY_POLL (&p, priv,MT7531_PHY_IAC ); -mt7530_mutex_lock (priv); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -620,8 +608,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,MT7531_MDIO_DEV_ADDR (devad) | regnum;mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -631,8 +619,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,MT7531_MDIO_DEV_ADDR (devad) | data;mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -647,16 +635,13 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,static int mt7531_ind_c22_phy_read (struct mt7530_priv *priv,int port,int regnum) { -struct mt7530_dummy_poll p;int ret;u32 val; -INIT_MT7530_DUMMY_POLL (&p, priv,MT7531_PHY_IAC ); -mt7530_mutex_lock (priv); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -667,8 +652,8 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)mt7530_mii_write (priv,MT7531_PHY_IAC , val |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -685,16 +670,13 @@ static int mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum, u16 data) { - struct mt7530_dummy_poll p; int ret;u32 reg; -INIT_MT7530_DUMMY_POLL (&p, priv,MT7531_PHY_IAC ); -mt7530_mutex_lock (priv); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, reg, - !(reg &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , reg, + !(reg &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -705,8 +687,8 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, reg, - !(reg &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , reg, + !(reg &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 177/438 net: stmmac: Fix E2E delay mechanism
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nazim Amirul <[email protected]>
[ Upstream commit b041ed62aa6e3b2d7d36127e0e5d7bf2701f8231 ]
For E2E delay mechanism, "received DELAY_REQ without timestamp" error messages show up for dwmac v3.70+ and dwxgmac IPs.
This issue affects socfpga platforms, Agilex7 (dwmac 3.70) and Agilex5 (dwxgmac). According to the databook, to enable timestamping for all events, the SNAPTYPSEL bits in the MAC_Timestamp_Control register must be set to 2'b01, and the TSEVNTENA bit must be cleared to 0'b0.
Commit 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism") already addresses this problem for all dwmacs above version v4.10. However, same holds true for v3.70 and above, as well as for dwxgmac. Updates the check accordingly.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +2 -1
@@ -755,7 +755,8 @@ static int stmmac_hwtstamp_set(struct net_device *dev, config->rx_filter =HWTSTAMP_FILTER_PTP_V2_EVENT ; ptp_v2 =PTP_TCR_TSVER2ENA ; snap_type_sel =PTP_TCR_SNAPTYPSEL_1 ; -if (priv->synopsys_id <DWMAC_CORE_4_10 ) +if (priv->synopsys_id <DWMAC_CORE_3_70 && + priv->plat->core_type !=DWMAC_CORE_XGMAC ) ts_event_en =PTP_TCR_TSEVNTENA ; ptp_over_ipv4_udp =PTP_TCR_TSIPV4ENA ; ptp_over_ipv6_udp =PTP_TCR_TSIPV6ENA ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 178/438 net: mana: Create separate EQs for each vPort
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <[email protected]>
[ Upstream commit fa1a3b7bcd161028e038025c1a4a8963b2f56a95 ]
To prepare for assigning vPorts to dedicated MSI-X vectors, remove EQ sharing among the vPorts and create dedicated EQs for each vPort.
Move the EQ definition from struct mana_context to struct mana_port_context and update related support functions. Export mana_create_eq() and mana_destroy_eq() for use by the MANA RDMA driver.
RSS QPs now take a vport reference via pd->vport_use_count to ensure EQs outlive all QP consumers. The vport must already be configured by a raw QP before an RSS QP can be created. EQs are only destroyed when the last QP (raw or RSS) on the PD releases its reference.
Restrict each vport to a single RSS QP. The hardware only supports one steering configuration (indirection table / hash key) per vport, and mana_disable_vport_rx() on QP destroy disables RX globally for the vport. Previously, creating a second RSS QP would silently overwrite the first QP's steering config and destroy would blackhole all traffic. This is now explicitly rejected with -EBUSY. Existing applications (DPDK being the primary RDMA consumer) always create one RSS QP per vport, so no real-world flows are affected.
Reject cross-port PD sharing for both raw and RSS QPs. Since EQs and vport configuration are per-port, a PD is bound to the port used by its first raw QP. Subsequent QPs on the same PD must use the same port or the creation fails with -EINVAL. Previously this was silently
broken: with shared EQs it appeared to work, but with per-vPort EQs a cross-port PD would cause wrong-port EQ teardown and corruption. DPDK creates one PD per port so no existing flows are affected.
Serialize mana_set_channels() and the async per-port queue reset handler against RDMA vport configuration to prevent RDMA from claiming the vport during the detach/attach window. A channel_changing flag is set under apc->vport_mutex before detach and checked by mana_cfg_vport() when called from the RDMA path, blocking RDMA from grabbing the vport during the entire window. When the port is down and RDMA already holds the vport, the channel change is rejected with -EBUSY.
Stable-dep-of: e67cc80b50f5 ("net: mana: Return error code from mana_create_rxq()")
--- drivers/infiniband/hw/mana/main.c | 40 ++++-- drivers/infiniband/hw/mana/mana_ib.h | 14 ++ drivers/infiniband/hw/mana/qp.c | 68 ++++++++- drivers/net/ethernet/microsoft/mana/mana_en.c | 135 +++++++++++------- .../ethernet/microsoft/mana/mana_ethtool.c | 23 ++- include/net/mana/mana.h | 15 +- 6 files changed, 228 insertions(+), 67 deletions(-)
drivers/infiniband/hw/mana/main.c +32 -8
@@ -20,8 +20,10 @@ void mana_ib_uncfg_vport(struct mana_ib_dev *dev, struct mana_ib_pd *pd, pd->vport_use_count--;WARN_ON (pd->vport_use_count <0 ); -if (!pd->vport_use_count) +if (!pd->vport_use_count) { +mana_destroy_eq (mpc);mana_uncfg_vport (mpc); + }mutex_unlock (&pd->vport_mutex); }
@@ -40,13 +42,27 @@ int mana_ib_cfg_vport(struct mana_ib_dev *dev, u32 port, struct mana_ib_pd *pd, pd->vport_use_count++;if (pd->vport_use_count >1 ) { +/* Reject cross-port PD sharing. EQs and vport config +* are per-port, so the PD must stay bound to the port +* that was configured on the first raw QP creation. +*/ +if (pd->vport_port != port) { + pd->vport_use_count--; +mutex_unlock (&pd->vport_mutex); +ibdev_dbg (&dev->ib_dev, +"PD already bound to port %u\n" , + pd->vport_port); +return -EINVAL ; + }ibdev_dbg (&dev->ib_dev,"Skip as this PD is already configured vport\n" );mutex_unlock (&pd->vport_mutex);return 0 ; } - err =mana_cfg_vport (mpc, pd->pdn, doorbell_id); + pd->vport_port = port; + + err =mana_cfg_vport (mpc, pd->pdn, doorbell_id, true);if (err) { pd->vport_use_count--;mutex_unlock (&pd->vport_mutex);
@@ -55,15 +71,23 @@ int mana_ib_cfg_vport(struct mana_ib_dev *dev, u32 port, struct mana_ib_pd *pd,return err; } -mutex_unlock (&pd->vport_mutex); - pd->tx_shortform_allowed = mpc->tx_shortform_allowed; - pd->tx_vp_offset = mpc->tx_vp_offset; + err =mana_create_eq (mpc); +if (err) { +mana_uncfg_vport (mpc); + pd->vport_use_count--; + }else { + pd->tx_shortform_allowed = mpc->tx_shortform_allowed; + pd->tx_vp_offset = mpc->tx_vp_offset; + } + +mutex_unlock (&pd->vport_mutex); -ibdev_dbg (&dev->ib_dev,"vport handle %llx pdid %x doorbell_id %x\n" , - mpc->port_handle, pd->pdn, doorbell_id); +if (!err) +ibdev_dbg (&dev->ib_dev,"vport handle %llx pdid %x doorbell_id %x\n" , + mpc->port_handle, pd->pdn, doorbell_id); -return 0 ; +return err; }int mana_ib_alloc_pd (struct ib_pd *ibpd,struct ib_udata *udata)
drivers/infiniband/hw/mana/mana_ib.h +14 -0
@@ -102,6 +102,20 @@ struct mana_ib_pd {struct mutex vport_mutex;int vport_use_count; +/* Port bound to this PD for raw QP usage. Only valid when +* vport_use_count > 0. A PD can only be associated with a +* single physical port because per-port EQs and vport +* configuration are tied to the PD's refcount. +*/ +u32 vport_port; + +/* Only one RSS QP is allowed per vport because each RSS QP +* overwrites the vport steering config (indirection table / +* hash key) and mana_disable_vport_rx() on destroy would +* blackhole traffic for any other RSS QP on the same vport. +*/ +bool has_rss_qp; +bool tx_shortform_allowed;u32 tx_vp_offset; };
drivers/infiniband/hw/mana/qp.c +61 -7
147 lines not on this page · raw message
drivers/net/ethernet/microsoft/mana/mana_en.c +87 -48
318 lines not on this page · raw message
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +22 -1
@@ -454,6 +454,11 @@ static int mana_set_coalesce(struct net_device *ndev,return err; } +/* mana_set_channels - change the number of queues on a port +* +* Returns -EBUSY if RDMA holds the vport with EQs sized to the +* current num_queues. +*/ static int mana_set_channels (struct net_device *ndev,struct ethtool_channels *channels) {
@@ -462,10 +467,22 @@ static int mana_set_channels(struct net_device *ndev,unsigned int old_count = apc->num_queues;int err; +/* Set channel_changing to block RDMA from grabbing the vport +* during the detach/attach window. mana_cfg_vport() checks +* this flag under vport_mutex and returns -EBUSY if set. +*/ +mutex_lock (&apc->vport_mutex); +if (!apc->port_is_up && apc->vport_use_count) { +mutex_unlock (&apc->vport_mutex); +return -EBUSY ; + } + apc->channel_changing = true; +mutex_unlock (&apc->vport_mutex); + err =mana_pre_alloc_rxbufs (apc, ndev->mtu, new_count);if (err) {netdev_err (ndev,"Insufficient memory for new allocations" ); -return err; + goto clear_flag; } err =mana_detach (ndev, false);
@@ -483,6 +500,10 @@ static int mana_set_channels(struct net_device *ndev, out:mana_pre_dealloc_rxbufs (apc); +clear_flag: +mutex_lock (&apc->vport_mutex); + apc->channel_changing = false; +mutex_unlock (&apc->vport_mutex);return err; }
include/net/mana/mana.h +12 -3
@@ -488,8 +488,6 @@ struct mana_context {u8 bm_hostmode;struct mana_ethtool_hc_stats hc_stats; -struct mana_eq *eqs; -struct dentry *mana_eqs_debugfs;struct workqueue_struct *per_port_queue_reset_wq;/* Workqueue for querying hardware stats */ struct delayed_work gf_stats_work;
@@ -509,6 +507,9 @@ struct mana_port_context {u8 mac_addr[ETH_ALEN ]; +struct mana_eq *eqs; +struct dentry *mana_eqs_debugfs; +enum TRI_STATE rss_state;mana_handle_t default_rxobj;
@@ -555,6 +556,12 @@ struct mana_port_context {struct mutex vport_mutex;int vport_use_count; +/* Set by mana_set_channels() under vport_mutex to block RDMA +* from grabbing the vport during the detach/attach window. +* Checked by mana_cfg_vport() when called from the RDMA path. +*/ +bool channel_changing; +/* Net shaper handle*/ struct net_shaper_handle handle;
@@ -1040,8 +1047,10 @@ void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type, mana_handle_t wq_obj);int mana_cfg_vport (struct mana_port_context *apc,u32 protection_dom_id, -u32 doorbell_pg_id); +u32 doorbell_pg_id,bool check_channel_changing);void mana_uncfg_vport (struct mana_port_context *apc); +int mana_create_eq (struct mana_port_context *apc); +void mana_destroy_eq (struct mana_port_context *apc); struct net_device *mana_get_primary_netdev(struct mana_context *ac, u32 port_index,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 179/438 net: mana: Return error code from mana_create_rxq()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aditya Garg <[email protected]>
[ Upstream commit e67cc80b50f587cd1d8ffc8989dcec3291720bc3 ]
mana_create_rxq() returns a struct mana_rxq pointer and returns NULL on any failure. The caller, mana_add_rx_queues(), cannot tell what went wrong and hardcodes the error as -ENOMEM. As a result the actual failure reported by the lower layers (for example -EPROTO from a failed HW request) is masked and every RX queue creation failure looks like an out-of-memory error.
Return an ERR_PTR() encoded error code from mana_create_rxq() on failure instead of NULL. The caller now propagates the returned error code directly instead of substituting -ENOMEM.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +4 -4
@@ -2771,7 +2771,7 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc, rxq =kzalloc_flex (*rxq, rx_oobs, apc->rx_queue_size);if (!rxq) -return NULL ; +return ERR_PTR (-ENOMEM ); rxq->ndev = ndev; rxq->num_rx_buf = apc->rx_queue_size;
@@ -2872,7 +2872,7 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,mana_destroy_rxq (apc, rxq, false); -return NULL ; +return ERR_PTR (err); }static void mana_create_rxq_debugfs (struct mana_port_context *apc,int idx)
@@ -2906,8 +2906,8 @@ static int mana_add_rx_queues(struct mana_port_context *apc,for (i =0 ; i < apc->num_queues; i++) { rxq =mana_create_rxq (apc, i, &apc->eqs[i], ndev); -if (!rxq) { - err = -ENOMEM ; +if (IS_ERR (rxq)) { + err =PTR_ERR (rxq);netdev_err (ndev,"Failed to create rxq %d : %d\n" , i, err); goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 180/438 ptp: netc: fix potential interrupt storm caused by incorrect unbind order
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Fang <[email protected]>
[ Upstream commit 54ad7ea45d63146a8e3c57375f8a269d4cf7ecea ]
In netc_timer_remove(), hardware interrupts are disabled by clearing TMR_TEMASK before ptp_clock_unregister() is called. This may cause a race condition during driver unbind that could leave hardware interrupts active. For example, a concurrent PTP_CLK_REQ_EXTTS ioctl can re-enable TMR_TEMASK after it has been cleared, leaving a pending hardware interrupt when the driver unbinds.
Since the NETC Timer does not support PCIe FLR, hardware state is not reset during probe. When the driver is rebound and the IRQ is registered, the pending interrupt fires immediately. At that point priv->tmr_emask is still zero, so netc_timer_isr() does not clear the interrupt status and unconditionally returns IRQ_HANDLED, resulting in an uninterruptible infinite interrupt storm.
Fix this in several ways. First, request the IRQ with IRQF_NO_AUTOEN so it is not enabled when request_irq() runs, and clear TMR_TEMASK in netc_timer_init() before enabling it. The IRQ is only enabled at the end of probe once the timer has been reprogrammed and the PTP clock has been registered. This ensures a stale pending interrupt from a previous unbind or an unclean shutdown cannot be delivered before the driver is fully initialized.
Second, in netc_timer_remove() call disable_irq() before ptp_clock_unregister() and move the TMR_TEMASK/TMR_CTRL clearing after it. disable_irq() masks the line and waits for any in-flight netc_timer_isr() to finish, so no ISR can dereference priv->clock after ptp_clock_unregister() has freed it. Unregistering the PTP clock before clearing the mask also guarantees that no in-flight or concurrent ioctl can re-enable hardware interrupts.
Finally, return IRQ_NONE from netc_timer_isr() when the masked event status is zero, so the kernel's spurious interrupt detection can disable a stuck line instead of looping forever.
--- drivers/ptp/ptp_netc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/ptp/ptp_netc.c +12 -3
@@ -769,6 +769,7 @@ static void netc_timer_init(struct netc_timer *priv)TMR_CTRL_TE |TMR_CTRL_FS ;netc_timer_wr (priv,NETC_TMR_CTRL , tmr_ctrl);netc_timer_wr (priv,NETC_TMR_PRSC , priv->oclk_prsc); +netc_timer_wr (priv,NETC_TMR_TEMASK ,0 );/* Disable FIPER by default */ fiper_ctrl =netc_timer_rd (priv,NETC_TMR_FIPER_CTRL );
@@ -901,6 +902,11 @@ static irqreturn_t netc_timer_isr(int irq, void *data)/* Clear interrupts status */ netc_timer_wr (priv,NETC_TMR_TEVENT , tmr_event); +if (!tmr_event) { +spin_unlock (&priv->lock); +return IRQ_NONE ; + } +if (tmr_event &TMR_TEVENT_ALMEN (0 ))netc_timer_alarm_write (priv,NETC_TMR_DEFAULT_ALARM ,0 );
@@ -936,7 +942,8 @@ static int netc_timer_init_msix_irq(struct netc_timer *priv) } priv->irq =pci_irq_vector (pdev,0 ); - err =request_irq (priv->irq, netc_timer_isr,0 , priv->irq_name, priv); + err =request_irq (priv->irq, netc_timer_isr,IRQF_NO_AUTOEN , + priv->irq_name, priv);if (err) {dev_err (&pdev->dev,"request_irq() failed\n" );pci_free_irq_vectors (pdev);
@@ -951,7 +958,6 @@ static void netc_timer_free_msix_irq(struct netc_timer *priv) {struct pci_dev *pdev = priv->pdev; -disable_irq (priv->irq);free_irq (priv->irq, priv);pci_free_irq_vectors (pdev); }
@@ -1005,6 +1011,8 @@ static int netc_timer_probe(struct pci_dev *pdev, goto free_msix_irq; } +enable_irq (priv->irq); +return 0 ; free_msix_irq:
@@ -1019,9 +1027,10 @@ static void netc_timer_remove(struct pci_dev *pdev) {struct netc_timer *priv =pci_get_drvdata (pdev); +disable_irq (priv->irq); +ptp_clock_unregister (priv->clock);netc_timer_wr (priv,NETC_TMR_TEMASK ,0 );netc_timer_wr (priv,NETC_TMR_CTRL ,0 ); -ptp_clock_unregister (priv->clock);netc_timer_free_msix_irq (priv);netc_timer_pci_remove (pdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 181/438 net: libwx: fix FDIR ATR queue mismatch for software VLAN packets
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiawen Wu <[email protected]>
[ Upstream commit 732ed8f75ce583d115716f668dc80d730f3ad610 ]
When TX VLAN hardware offload is disabled, VLAN tags are embedded in the packet payload (software VLAN). Previously, the driver failed to set the WX_TX_FLAGS_SW_VLAN flag for these packets during transmission.
This missing flag caused the txgbe FDIR ATR logic to fall through to the default hash calculation path. This resulted in asymmetric hash values for Tx and Rx flows, preventing return packets from being steered to the same queue as the transmit packets.
Fix this by detecting software VLANs via eth_type_vlan(skb->protocol) and setting WX_TX_FLAGS_SW_VLAN. This ensures the ATR feature selects the correct hashing algorithm to maintain Tx/Rx queue symmetry.
--- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/wangxun/libwx/wx_lib.c +2 -0
@@ -1606,6 +1606,8 @@ static netdev_tx_t wx_xmit_frame_ring(struct sk_buff *skb,if (skb_vlan_tag_present (skb)) { tx_flags |=skb_vlan_tag_get (skb) <<WX_TX_FLAGS_VLAN_SHIFT ; tx_flags |=WX_TX_FLAGS_HW_VLAN ; + }else if (eth_type_vlan (skb->protocol)) { + tx_flags |=WX_TX_FLAGS_SW_VLAN ; } if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 182/438 octeontx2-pf: Set correct sequence for carrier off and tx queue stop
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suman Ghosh <[email protected]>
[ Upstream commit 16809472409d998afcda402e32b8229b389337c4 ]
During link down event, we were doing netif_tx_stop_all_queues() first and then netif_carrier_off(). This can cause a potential race since carrier is still on during down event. This patch reverse the calling order to fix the issue.
--- drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +1 -1
@@ -889,8 +889,8 @@ static void otx2_handle_link_event(struct otx2_nic *pf)netif_carrier_on (netdev);netif_tx_start_all_queues (netdev); }else { -netif_tx_stop_all_queues (netdev);netif_carrier_off (netdev); +netif_tx_stop_all_queues (netdev); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 183/438 sched/deadline: Use revised wakeup rule only for running dl_server
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gabriele Monaco <[email protected]>
[ Upstream commit 1842bf97af109f5ebf830175c9725bf81ebb78b1 ]
Commit 14a857056466 ("sched/deadline: Use revised wakeup rule for dl_server") applies the revised wakeup rule to any server, as a result servers that are not running (dl_defer_running == 0) and start with a deadline overflow get enqueued and can boost tasks as if they were running, invalidating the defer rule and the documented state model.
Apply the revised wakeup rule only for deferrable servers that are marked as running.
--- kernel/sched/deadline.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/sched/deadline.c +2 -1
@@ -1017,7 +1017,8 @@ static void update_dl_entity(struct sched_dl_entity *dl_se)if (dl_time_before (dl_se->deadline,rq_clock (rq)) ||dl_entity_overflow (dl_se,rq_clock (rq))) { -if (unlikely ((!dl_is_implicit (dl_se) || dl_se->dl_defer) && +if (unlikely ((!dl_is_implicit (dl_se) || + (dl_se->dl_defer && dl_se->dl_defer_running)) && !dl_time_before (dl_se->deadline,rq_clock (rq)) && !is_dl_boosted (dl_se))) {update_dl_revised_wakeup (dl_se, rq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 184/438 spi: spi-nxp-fspi: add per-SoC SDR/DTR clock rate limits for all supported SoCs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haibo Chen <[email protected]>
[ Upstream commit 9c19d60fea9f46ed0c3394653ef4941f1a459968 ]
The commit f43579ef3500 ("spi: spi-nxp-fspi: limit the clock rate for different sample clock source selection") introduced a global 166MHz cap for DTR mode (RXCLKSRC=3), based on the i.MX8MN datasheet timing specification (Section 3.9.9, page 65).
After reviewing the FlexSPI timing parameters in the datasheets for all supported SoCs, the following corrections and additions are needed:
1. SDR mode (RXCLKSRC=0) limits vary per SoC:
- i.MX8MN/MM/MP/95: 66MHz (IMX8MNCEC §3.9.9, IMX8MMCEC §3.9.10,
IMX8MPCEC, IMX95CEC Rev.8 §4.11.7)
- i.MX8QXP/QM/DXL/ULP: 60MHz (IMX8QXPCEC, IMX8QMCEC, IMX8DXLCEC,
IMX8ULPCEC §7.3.1 ND mode)- LX2160A: 100MHz (LX2160ACEC FlexSPI timing parameters)
2. DTR mode (RXCLKSRC=3) limits vary per SoC:
- i.MX8MN/MM/MP/ULP: 166MHz
- i.MX8QXP/QM/DXL: 200MHz (same FlexSPI IP across this family)
- i.MX95: 200MHz (IMX95CEC §4.11.7.3.2.3 Table 106)
- LX2160A: DTR disabled (FSPI_QUIRK_DISABLE_DTR)
Update related platform data with correct speed limation according to datasheet.
--- drivers/spi/spi-nxp-fspi.c | 83 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-)
drivers/spi/spi-nxp-fspi.c +80 -3
@@ -340,6 +340,18 @@ struct nxp_fspi_devtype_data {unsigned int quirks;unsigned int lut_num;bool little_endian; +/* +* The max clock rate (Hz) that FlexSPI can output to the device +* in SDR mode (RXCLKSRC=0). Defaults to 66MHz if zero. +* Some SoCs (e.g. LX2160A) support up to 100MHz in SDR mode. +*/ +unsigned long max_sdr_rate; +/* +* The max clock rate (Hz) that FlexSPI can output to the device +* in DTR mode (RXCLKSRC=3). Defaults to 166MHz if zero. +* Some SoCs (e.g. i.MX95, i.MX8QM, i.MX8DXL) support up to 200MHz. +*/ +unsigned long max_dtr_rate; };static struct nxp_fspi_devtype_data lx2160a_data = {
@@ -349,6 +361,10 @@ static struct nxp_fspi_devtype_data lx2160a_data = { .quirks = FSPI_QUIRK_DISABLE_DTR, .lut_num = 32, .little_endian = true, /* little-endian */ +/* +* LX2160ACEC: SDR RXCLKSRC=0 max 100MHz, DTR disabled via quirk. +*/ + .max_sdr_rate = 100000000, };static struct nxp_fspi_devtype_data imx8mm_data = {
@@ -358,6 +374,21 @@ static struct nxp_fspi_devtype_data imx8mm_data = { .quirks = 0, .lut_num = 32, .little_endian = true, /* little-endian */ + /* IMX8MMCEC §3.9.10: SDR RXCLKSRC=0 max 66MHz, DDR RXCLKSRC=3 max 166MHz */ + .max_sdr_rate = 66000000, + .max_dtr_rate = 166000000, +}; + +static struct nxp_fspi_devtype_data imx8mp_data = { + .rxfifo =SZ_512 ,/* (64 * 64 bits) */ + .txfifo =SZ_1K ,/* (128 * 64 bits) */ + .ahb_buf_size =SZ_2K ,/* (256 * 64 bits) */ + .quirks =0 , + .lut_num =32 , + .little_endian = true,/* little-endian */ +/* IMX8MPCEC: SDR RXCLKSRC=0 max 66MHz, DDR RXCLKSRC=3 max 166MHz */ + .max_sdr_rate =66000000 , + .max_dtr_rate =166000000 , };static struct nxp_fspi_devtype_data imx8qxp_data = {
@@ -367,6 +398,12 @@ static struct nxp_fspi_devtype_data imx8qxp_data = { .quirks = 0, .lut_num = 32, .little_endian = true, /* little-endian */ +/* +* IMX8QXPCEC: SDR RXCLKSRC=0 max 60MHz, DDR RXCLKSRC=3 max 200MHz. +* i.MX8QM and i.MX8DXL share the same FlexSPI IP and limits. +*/ + .max_sdr_rate = 60000000, + .max_dtr_rate = 200000000, };static struct nxp_fspi_devtype_data imx8dxl_data = {
@@ -376,6 +413,12 @@ static struct nxp_fspi_devtype_data imx8dxl_data = { .quirks = FSPI_QUIRK_USE_IP_ONLY, .lut_num = 32, .little_endian = true, /* little-endian */ +/* +* IMX8DXLCEC (i.MX 8XLite): SDR RXCLKSRC=0 max 60MHz, +* DDR RXCLKSRC=3 max 200MHz. +*/ + .max_sdr_rate = 60000000, + .max_dtr_rate = 200000000, };static struct nxp_fspi_devtype_data imx8ulp_data = {
@@ -385,6 +428,29 @@ static struct nxp_fspi_devtype_data imx8ulp_data = { .quirks = 0, .lut_num = 16, .little_endian = true, /* little-endian */ +/* +* IMX8ULPCEC §7.3.1, Normal Drive (ND, 1.0V) mode: +* SDR RXCLKSRC=0 max 60MHz, DDR RXCLKSRC=3 max 166MHz. +* Note: Overdrive (OD, 1.05V) allows up to 180MHz DTR +* but is not the default use case. +*/ + .max_sdr_rate = 60000000, + .max_dtr_rate = 166000000, +}; + +static struct nxp_fspi_devtype_data imx95_data = { + .rxfifo =SZ_512 ,/* (64 * 64 bits) */ + .txfifo =SZ_1K ,/* (128 * 64 bits) */ + .ahb_buf_size =SZ_2K ,/* (256 * 64 bits) */ + .quirks =0 , + .lut_num =32 , + .little_endian = true,/* little-endian */ +/* +* IMX95CEC Rev.8 §4.11.7: SDR RXCLKSRC=0 max 66MHz, +* DDR RXCLKSRC=3 max 200MHz (Nominal/Overdrive mode). +*/ + .max_sdr_rate =66000000 , + .max_dtr_rate =200000000 , };struct nxp_fspi {
@@ -691,10 +757,20 @@ static void nxp_fspi_select_rx_sample_clk_source(struct nxp_fspi *f, reg =fspi_readl (f, f->iobase +FSPI_MCR0 );if (op_is_dtr) { reg |=FSPI_MCR0_RXCLKSRC (3 ); - f->max_rate =166000000 ; +/* +* Use the SoC-specific DTR max rate if provided, otherwise +* fall back to 166MHz (limit from IMX8MN datasheet §3.9.9). +*/ + f->max_rate = f->devtype_data->max_dtr_rate ? + f->devtype_data->max_dtr_rate :166000000 ; }else {/*select mode 0 */ reg &= ~FSPI_MCR0_RXCLKSRC (3 ); - f->max_rate =66000000 ; +/* +* Use the SoC-specific SDR max rate if provided, otherwise +* fall back to 66MHz (limit from IMX8MN datasheet §3.9.9). +*/ + f->max_rate = f->devtype_data->max_sdr_rate ? + f->devtype_data->max_sdr_rate :66000000 ; }fspi_writel (f, reg, f->iobase +FSPI_MCR0 ); }
@@ -1444,10 +1520,11 @@ static const struct dev_pm_ops nxp_fspi_pm_ops = {static const struct of_device_id nxp_fspi_dt_ids[] = { { .compatible ="nxp,lx2160a-fspi" , .data = (void *)&lx2160a_data, }, { .compatible ="nxp,imx8mm-fspi" , .data = (void *)&imx8mm_data, }, - { .compatible ="nxp,imx8mp-fspi" , .data = (void *)&imx8mm_data, }, + { .compatible ="nxp,imx8mp-fspi" , .data = (void *)&imx8mp_data, }, { .compatible ="nxp,imx8qxp-fspi" , .data = (void *)&imx8qxp_data, }, { .compatible ="nxp,imx8dxl-fspi" , .data = (void *)&imx8dxl_data, }, { .compatible ="nxp,imx8ulp-fspi" , .data = (void *)&imx8ulp_data, }, + { .compatible ="nxp,imx95-fspi" , .data = (void *)&imx95_data, }, {/* sentinel */ } };MODULE_DEVICE_TABLE (of, nxp_fspi_dt_ids);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 185/438 qede: sync udp_tunnel ports outside qede_lock in the recovery path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Denis V. Lunev <[email protected]>
[ Upstream commit 451c9075d6c53f2438d110addbeeeea6fac18567 ]
A TX timeout on a qede NIC that has VXLAN/GENEVE tunnel ports configured wedges the rtnetlink control plane of the whole machine:
NETDEV WATCHDOG: ens6f1 (qede): transmit queue 2 timed out 10226 ms [qede_tx_timeout:586(ens6f1)]TX timeout on queue 2! [qede_recovery_handler:2665(ens6f0)]Starting a recovery process
The recovery path deadlocks on the driver's own mutex:
qede_sp_task
rtnl_lock()
mutex_lock(&edev->qede_lock) <- taken
qede_recovery_handler
qede_load
udp_tunnel_nic_reset_ntf
__udp_tunnel_nic_device_sync
info->sync_table == qede_udp_tunnel_sync
mutex_lock(&edev->qede_lock) <- same task: deadlockThe mutex is not recursive, so the kworker blocks on itself with rtnl_lock held, and neither lock is ever released. Every task that calls rtnl_lock() afterwards (ip, ovs-vswitchd, lldpad, IPv6 addrconf, sshd) blocks forever while the node still answers ping. In a vmcore from an affected production node rtnl_mutex.owner decodes to the very kworker blocked at the innermost mutex_lock() above.
Re-sync the tunnel ports from qede_sp_task() after the internal lock is dropped, still under rtnl_lock as the udp_tunnel API requires. This mirrors qede_open(), which calls udp_tunnel_nic_reset_ntf() under rtnl without the internal lock.
qede_recovery_handler() now returns whether it has successfully reloaded an open device, and the caller re-syncs the ports only in that case. This keeps the old gating exactly: a device that was down or a failed recovery returns false, as those paths never reached the udp_tunnel_nic_reset_ntf() call before either.
This was the only user of the qede_lock()/qede_unlock() helpers, so remove them.
--- drivers/net/ethernet/qlogic/qede/qede_main.c | 44 ++++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-)
drivers/net/ethernet/qlogic/qede/qede_main.c +22 -22
@@ -107,7 +107,7 @@ static void qede_remove(struct pci_dev *pdev);static void qede_shutdown (struct pci_dev *pdev);static void qede_link_update (void *dev,struct qed_link_output *link);static void qede_schedule_recovery_handler (void *dev); -static void qede_recovery_handler (struct qede_dev *edev); +static bool qede_recovery_handler (struct qede_dev *edev);static void qede_schedule_hw_err_handler (void *dev,enum qed_hw_err_type err_type);static void qede_get_eth_tlv_data (void *edev,void *data);
@@ -1043,21 +1043,6 @@ void __qede_unlock(struct qede_dev *edev)mutex_unlock (&edev->qede_lock); } -/* This version of the lock should be used when acquiring the RTNL lock is also -* needed in addition to the internal qede lock. -*/ -static void qede_lock (struct qede_dev *edev) -{ -rtnl_lock (); -__qede_lock (edev); -} - -static void qede_unlock (struct qede_dev *edev) -{ -__qede_unlock (edev); -rtnl_unlock (); -} -static void qede_periodic_task (struct work_struct *work) { struct qede_dev *edev = container_of(work, struct qede_dev,
@@ -1094,6 +1079,8 @@ static void qede_sp_task(struct work_struct *work)*/ if (test_and_clear_bit (QEDE_SP_RECOVERY , &edev->sp_flags)) { +bool reloaded; +cancel_delayed_work_sync (&edev->periodic_task);#ifdef CONFIG_QED_SRIOV /* SRIOV must be disabled outside the lock to avoid a deadlock.
@@ -1102,9 +1089,17 @@ static void qede_sp_task(struct work_struct *work)if (pci_num_vf (edev->pdev))qede_sriov_configure (edev->pdev,0 );#endif -qede_lock (edev); -qede_recovery_handler (edev); -qede_unlock (edev); +rtnl_lock (); +__qede_lock (edev); + reloaded =qede_recovery_handler (edev); +__qede_unlock (edev); + +/* The udp_tunnel core synchronously calls back into +* qede_udp_tunnel_sync(), which takes the qede lock. +*/ +if (reloaded) +udp_tunnel_nic_reset_ntf (edev->ndev); +rtnl_unlock (); }__qede_lock (edev);
@@ -2645,9 +2640,13 @@ static void qede_recovery_failed(struct qede_dev *edev) edev->ops->common->set_power_state (edev->cdev, PCI_D3hot); } -static void qede_recovery_handler (struct qede_dev *edev) +/* Returns true if an open device was successfully reloaded and its +* udp_tunnel ports need to be re-synced by the caller. +*/ +static bool qede_recovery_handler (struct qede_dev *edev) {u32 curr_state = edev->state; +bool reloaded = false;int rc;DP_NOTICE (edev,"Starting a recovery process\n" );
@@ -2677,17 +2676,18 @@ static void qede_recovery_handler(struct qede_dev *edev) goto err;qede_config_rx_mode (edev->ndev); -udp_tunnel_nic_reset_ntf (edev->ndev); + reloaded = true; } edev->state = curr_state;DP_NOTICE (edev,"Recovery handling is done\n" ); -return ; +return reloaded; err:qede_recovery_failed (edev); +return false; }static void qede_atomic_hw_err_handler (struct qede_dev *edev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 186/438 drm/i915/hdmi: Poll for 200 msec for TMDS_Scrambler_Status
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jerome Tollet <[email protected]>
[ Upstream commit 1afb8eaeec44fd011f2b93ccd9fd426d753d963b ]
HDMI 2.0 section 6.1.3.1 specifies that after enabling Scrambling_Enable and starting scrambled video transmission, the source should poll Scrambling_Status until it reads 1 or until a timeout of 200 ms expires.
Add a polling step after enabling the HDMI port to check the scrambling status when HDMI scrambling is enabled.
On some HDMI 2.0 sinks, omitting this check can result in 4K@60Hz (594 MHz) failing to come up correctly because the sink has not yet finished its scrambling setup. In practice, waiting for the scrambling status here fixes such sinks.
While this synchronous polling is not itself explicitly required for correct modeset sequencing, HDMI 2.0 section 6.1.3.1 does recommend it as the way for the source to verify that the TMDS link is functioning correctly with scrambling enabled.
v3:
- Add explicit HDMI 2.0 section reference in code comment
- Clarify commit message around the observed sink fix
v2:
- Poll TMDS_Scrambler_Status for up to 200 ms instead of using a fixed delay
--- drivers/gpu/drm/i915/display/intel_ddi.c | 2 ++ drivers/gpu/drm/i915/display/intel_hdmi.c | 26 +++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_hdmi.h | 2 ++ 3 files changed, 30 insertions(+)
drivers/gpu/drm/i915/display/intel_ddi.c +2 -0
@@ -3502,6 +3502,8 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state, }intel_ddi_buf_enable (encoder, buf_ctl); + +intel_hdmi_poll_for_scrambling_enable (crtc_state, connector); } static void intel_ddi_enable(struct intel_atomic_state *state,
drivers/gpu/drm/i915/display/intel_hdmi.c +26 -0
@@ -2693,6 +2693,32 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_drm_connector_attach_max_bpc_property (&connector->base,8 ,12 ); } +/* +* HDMI 2.0 spec, section 6.1.3.1 (Scrambling Control): after +* enabling Scrambling_Enable and starting scrambled video +* transmission, poll Scrambling_Status for up to 200 ms. +*/ +void +intel_hdmi_poll_for_scrambling_enable (const struct intel_crtc_state *crtc_state, +struct drm_connector *_connector) +{ +struct intel_connector *connector =to_intel_connector (_connector); +struct intel_display *display =to_intel_display (crtc_state); +bool scrambling_enabled = false; +int ret; + +if (!crtc_state->hdmi_scrambling) +return ; + +/* Poll for a max of 200 msec as per HDMI spec */ + ret =poll_timeout_us (scrambling_enabled =drm_scdc_get_scrambling_status (&connector->base), + scrambling_enabled,1000 ,200 *1000 , false); +if (ret) +drm_dbg_kms (display->drm, +"[CONNECTOR:%d:%s] Timed out waiting for scrambling enable\n" , + connector->base.base.id, connector->base.name); +} +/* * intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup * @encoder: intel_encoder
drivers/gpu/drm/i915/display/intel_hdmi.h +2 -0
@@ -70,5 +70,7 @@ void hsw_read_infoframe(struct intel_encoder *encoder,const struct intel_crtc_state *crtc_state, unsigned int type, void *frame, ssize_t len); +void intel_hdmi_poll_for_scrambling_enable (const struct intel_crtc_state *crtc_state, +struct drm_connector *_connector);#endif /* __INTEL_HDMI_H__ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 187/438 ksmbd: return success for deferred final close
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit c5db4de8988f1a621556ca5c4537f77b766ca07d ]
ksmbd_close_fd() marks an open file as FP_CLOSED and drops the file table reference. If another in-flight request still holds a reference, the final close is deferred until that request drops its reference.
The function currently returns -EINVAL in that deferred-final-close case because fp is cleared when the reference count does not reach zero. That turns a valid close into STATUS_FILE_CLOSED.
smb2.compound_find.compound_find_close sends QUERY_DIRECTORY and then closes the same directory handle before receiving the find response. The query holds a reference while it builds the response, so close must mark the handle closed and return success even though final teardown is delayed. Track whether the handle was successfully transitioned to FP_CLOSED and return success when only the final close is deferred.
Stable-dep-of: e7188199eff4 ("ksmbd: fix use-after-free in __close_file_table_ids()")
--- fs/smb/server/vfs_cache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/smb/server/vfs_cache.c +3 -1
@@ -580,6 +580,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id) {struct ksmbd_file *fp;struct ksmbd_file_table *ft; +bool closed = false;if (!has_file_id (id))return 0 ;
@@ -594,6 +595,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id) fp =NULL ; else { fp->f_state =FP_CLOSED ; + closed = true;if (!atomic_dec_and_test (&fp->refcount)) fp =NULL ; }
@@ -601,7 +603,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)write_unlock (&ft->lock);if (!fp) -return -EINVAL ; +return closed ?0 : -EINVAL ;__put_fd_final (work, fp);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 188/438 ksmbd: fix use-after-free in __close_file_table_ids()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit e7188199eff46a636f3436356f0aae039be6dd66 ]
A ksmbd_file can remain alive after logical close while another session holds a temporary reference obtained through ksmbd_lookup_fd_inode(). ksmbd_close_fd() currently marks the file closed and drops the idr-owned reference, but leaves the pointer published in the closing session's idr until the final reference is dropped.
If the foreign holder performs the final ksmbd_fd_put(), __put_fd_final() supplies the foreign session's file table to __ksmbd_close_fd(). The object is then freed without being removed from its owner's idr, and the owner session later dereferences the stale pointer during file-table teardown.
Remove the volatile id from the owner's idr while ksmbd_close_fd() still holds that table's lock, and clear volatile_id before dropping the idr-owned reference. A later foreign final put then only performs physical destruction and cannot remove the object from the wrong table.
--- fs/smb/server/vfs_cache.c | 2 ++ 1 file changed, 2 insertions(+)
fs/smb/server/vfs_cache.c +2 -0
@@ -595,6 +595,8 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id) fp =NULL ; else { fp->f_state =FP_CLOSED ; +idr_remove (ft->idr, id); + fp->volatile_id =KSMBD_NO_FID ; closed = true;if (!atomic_dec_and_test (&fp->refcount)) fp =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 189/438 ksmbd: use memcmp() to compare ClientGUIDs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit e8bb506e6ef749ac0336f3e579d8d02396b7d832 ]
ClientGUID is a fixed-size binary value and can contain embedded NUL bytes. strncmp() stops comparing at the first NUL byte, so different ClientGUID values can incorrectly be treated as equal.
Use memcmp() in SMB3 multichannel session binding and FSCTL_VALIDATE_NEGOTIATE_INFO to compare all SMB2_CLIENT_GUID_SIZE bytes.
--- fs/smb/server/smb2pdu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/server/smb2pdu.c +2 -2
@@ -1792,7 +1792,7 @@ int smb2_sess_setup(struct ksmbd_work *work) goto out_err; } -if (strncmp (conn->ClientGUID, sess->ClientGUID, +if (memcmp (conn->ClientGUID, sess->ClientGUID,SMB2_CLIENT_GUID_SIZE )) { rc = -ENOENT ; goto out_err;
@@ -8186,7 +8186,7 @@ static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn, goto err_out; } -if (strncmp (neg_req->Guid, conn->ClientGUID,SMB2_CLIENT_GUID_SIZE )) { +if (memcmp (neg_req->Guid, conn->ClientGUID,SMB2_CLIENT_GUID_SIZE )) { ret = -EINVAL ; goto err_out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 190/438 iomap: add a separate bio_set for iomap_split_ioend
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <[email protected]>
[ Upstream commit c679ce3be6cb63763d68ab9b5d9d73ddc0a40762 ]
iomap_split_ioend can split bios that already come from iomap_ioend_bioset and thus deadlock when the bioset is exhausted.
Add a separate bio_set to avoid this deadlock.
Christian Brauner <[email protected]> says:
Mark iomap_ioend_split_bioset static as it is only used in ioend.c, fixing the sparse warning reported by the kernel test robot.
--- fs/iomap/ioend.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
fs/iomap/ioend.c +19 -2
@@ -13,6 +13,7 @@struct bio_set iomap_ioend_bioset;EXPORT_SYMBOL_GPL (iomap_ioend_bioset); +static struct bio_set iomap_ioend_split_bioset;struct iomap_ioend *iomap_init_ioend (struct inode *inode,struct bio *bio,loff_t file_offset,u16 ioend_flags)
@@ -485,7 +486,8 @@ struct iomap_ioend *iomap_split_ioend(struct iomap_ioend *ioend, sector_offset =ALIGN_DOWN (sector_offset <<SECTOR_SHIFT ,i_blocksize (ioend->io_inode)) >>SECTOR_SHIFT ; - split =bio_split (bio, sector_offset,GFP_NOFS , &iomap_ioend_bioset); + split =bio_split (bio, sector_offset,GFP_NOFS , + &iomap_ioend_split_bioset);if (IS_ERR (split))return ERR_CAST (split); split->bi_private = bio->bi_private;
@@ -508,8 +510,23 @@ EXPORT_SYMBOL_GPL(iomap_split_ioend);static int __init iomap_ioend_init (void ) { -return bioset_init (&iomap_ioend_bioset,4 * (PAGE_SIZE /SECTOR_SIZE ), +const unsigned int nr_mempool_entries =4 * (PAGE_SIZE /SECTOR_SIZE ); +int error; + + error =bioset_init (&iomap_ioend_bioset, nr_mempool_entries, offsetof(struct iomap_ioend , io_bio),BIOSET_NEED_BVECS ); +if (error) +return error; + error =bioset_init (&iomap_ioend_split_bioset, nr_mempool_entries, + offsetof(struct iomap_ioend , io_bio), +BIOSET_NEED_BVECS ); +if (error) + goto out_exit_ioend_bioset; +return 0 ; + +out_exit_ioend_bioset: +bioset_exit (&iomap_ioend_bioset); +return error; }fs_initcall (iomap_ioend_init);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 191/438 mshv: Fix race in mshv_irqfd_deassign
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
[ Upstream commit 0762262ac3e70f65b3bb843fe892f8bac1562d08 ]
mshv_irqfd_deactivate() and the hlist traversal of pt_irqfds_list require pt->pt_irqfds_lock to be held, but mshv_irqfd_deassign() omits it. This races with the EPOLLHUP path in mshv_irqfd_wakeup(), which does take the lock before calling mshv_irqfd_deactivate().
Additionally, mshv_irqfd_deactivate() uses hlist_del() which poisons the node pointers rather than resetting them. Since mshv_irqfd_is_active() relies on hlist_unhashed() (checks pprev == NULL), a poisoned node still appears active. If a concurrent path calls mshv_irqfd_deactivate() again on the same irqfd, the guard fails to prevent a double hlist_del() on poisoned pointers.
Fix both issues:
- Add the missing spin_lock_irq/spin_unlock_irq around the list traversal in mshv_irqfd_deassign(), matching mshv_irqfd_release().
- Use hlist_del_init() instead of hlist_del() so the node is properly marked as unhashed after removal, making the is_active guard reliable.
--- drivers/hv/mshv_eventfd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/hv/mshv_eventfd.c +3 -2
@@ -284,7 +284,7 @@ static void mshv_irqfd_deactivate(struct mshv_irqfd *irqfd)if (!mshv_irqfd_is_active (irqfd))return ; -hlist_del (&irqfd->irqfd_hnode); +hlist_del_init (&irqfd->irqfd_hnode);queue_work (irqfd_cleanup_wq, &irqfd->irqfd_shutdown); }
@@ -541,13 +541,14 @@ static int mshv_irqfd_deassign(struct mshv_partition *pt,if (IS_ERR (eventfd))return PTR_ERR (eventfd); +spin_lock_irq (&pt->pt_irqfds_lock);hlist_for_each_entry_safe (irqfd, n, &pt->pt_irqfds_list, irqfd_hnode) {if (irqfd->irqfd_eventfd_ctx == eventfd && irqfd->irqfd_irqnum == args->gsi) -mshv_irqfd_deactivate (irqfd); } +spin_unlock_irq (&pt->pt_irqfds_lock);eventfd_ctx_put (eventfd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 192/438 mshv: Fix level-triggered check on uninitialized data
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
[ Upstream commit 0289a67cd70bf9d3807e289f4efd643e16a6c6b4 ]
In mshv_irqfd_assign(), the level-triggered validation for resample irqfds checks irqfd_lapic_irq.lapic_control.level_triggered before mshv_irqfd_update() has populated the field. Since the irqfd struct is zero-allocated, level_triggered is always 0 at that point, causing the check to always reject resample irqfds with -EINVAL. This makes level-triggered interrupt resampling — used to avoid interrupt storms with assigned devices — completely non-functional.
Move the check after the mshv_irqfd_update() call, which resolves the IRQ routing entry and populates irqfd_lapic_irq with the actual trigger mode.
--- drivers/hv/mshv_eventfd.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-)
drivers/hv/mshv_eventfd.c +14 -11
@@ -473,6 +473,19 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,init_poll_funcptr (&irqfd->irqfd_polltbl, mshv_irqfd_queue_proc);spin_lock_irq (&pt->pt_irqfds_lock); + ret =0 ; +hlist_for_each_entry (tmp, &pt->pt_irqfds_list, irqfd_hnode) { +if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx) +continue ; +/* This fd is used for another irq already. */ + ret = -EBUSY ; +spin_unlock_irq (&pt->pt_irqfds_lock); + goto fail; + } + + idx =srcu_read_lock (&pt->pt_irq_srcu); +mshv_irqfd_update (pt, irqfd); +#if IS_ENABLED (CONFIG_X86 )if (args->flags &BIT (MSHV_IRQFD_BIT_RESAMPLE ) && !irqfd->irqfd_lapic_irq.lapic_control.level_triggered) {
@@ -481,22 +494,12 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,* Otherwise return with failure */ spin_unlock_irq (&pt->pt_irqfds_lock); +srcu_read_unlock (&pt->pt_irq_srcu, idx); ret = -EINVAL ; goto fail; }#endif - ret =0 ; -hlist_for_each_entry (tmp, &pt->pt_irqfds_list, irqfd_hnode) { -if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx) -continue ; -/* This fd is used for another irq already. */ - ret = -EBUSY ; -spin_unlock_irq (&pt->pt_irqfds_lock); - goto fail; - } - idx =srcu_read_lock (&pt->pt_irq_srcu); -mshv_irqfd_update (pt, irqfd);hlist_add_head (&irqfd->irqfd_hnode, &pt->pt_irqfds_list);spin_unlock_irq (&pt->pt_irqfds_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 193/438 mshv: Fix missing error code on VP allocation failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
[ Upstream commit f546be6a19d24d02be576d8617cb26c7acb61594 ]
In mshv_partition_ioctl_create_vp(), when kzalloc for the VP struct fails, the code jumps to the cleanup path without setting ret. At that point ret is 0 from the preceding successful mshv_vp_stats_map() call, so the function returns success to userspace despite having failed to create the VP. No fd is installed and no VP is registered in pt_vp_array, but userspace has no way to know the operation failed.
Set ret to -ENOMEM before jumping to the cleanup path.
--- drivers/hv/mshv_root_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hv/mshv_root_main.c +3 -1
@@ -1117,8 +1117,10 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition, goto unmap_ghcb_page; vp =kzalloc_obj (*vp); -if (!vp) +if (!vp) { + ret = -ENOMEM ; goto unmap_stats_pages; + } vp->vp_partition =mshv_partition_get (partition);if (!vp->vp_partition) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 194/438 mshv: Order pt_vp_array publish against irqfd assertion path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
[ Upstream commit b098dc869219c15dc49bf9cf63fb5fc1481d3373 ]
mshv_partition_ioctl_create_vp() initialises a VP struct (allocations, mutex_init, init_waitqueue_head, page mappings) and then publishes the pointer into partition->pt_vp_array. Several ISR paths read this array
locklessly: the intercept ISR, the two scheduler ISRs, and mshv_try_assert_irq_fast() on the irqfd fast path.
Of these, only mshv_try_assert_irq_fast() can structurally race the publish. It runs from an eventfd waker without holding pt_mutex, and MSHV_IRQFD does not require the target lapic_apic_id (== vp_index) to refer to an existing VP at registration time. A user can therefore register an irqfd targeting a yet-to-be-created VP, then trigger mshv_try_assert_irq_fast() concurrently with MSHV_CREATE_VP for the same index. On weakly-ordered architectures the reader can observe a non-NULL pointer in pt_vp_array before the initialising stores to the VP struct become visible, leading to use of partially-initialised fields (e.g. vp_register_page).
The other ISR readers cannot reach this race: the hypervisor will not generate intercept or scheduler messages for a VP that has never been told to run, and the user can only call MSHV_RUN_VP on the VP fd returned by MSHV_CREATE_VP, which by construction is returned after the publish. Leave those readers as plain loads.
Use smp_store_release() in mshv_partition_ioctl_create_vp() to publish the pointer, and pair it with smp_load_acquire() in mshv_try_assert_irq_fast(). On x86 these compile to plain accesses under TSO; on ARM64 they emit one-instruction acquire/release barriers, acceptable on this fast path.
The destroy-side path (destroy_partition() clearing pt_vp_array[i] to NULL after kfree(vp)) has a separate ordering and lifetime concern that is out of scope here.
--- drivers/hv/mshv_eventfd.c | 9 ++++++++- drivers/hv/mshv_root_main.c | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-)
drivers/hv/mshv_eventfd.c +8 -1
@@ -169,7 +169,14 @@ static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd)return -EOPNOTSUPP ;#endif - vp = partition->pt_vp_array[irq->lapic_apic_id]; +/* +* Pairs with smp_store_release() in mshv_partition_ioctl_create_vp(). +* MSHV_IRQFD does not require the target lapic_apic_id to refer to an +* existing VP, so this read can race a concurrent VP creation; the +* acquire ensures that a non-NULL pointer implies the VP's +* initialising stores are visible. +*/ + vp =smp_load_acquire (&partition->pt_vp_array[irq->lapic_apic_id]);if (!vp->vp_register_page)return -EOPNOTSUPP ;
drivers/hv/mshv_root_main.c +7 -1
@@ -1157,7 +1157,13 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,/* already exclusive with the partition mutex for all ioctls */ partition->pt_vp_count++; - partition->pt_vp_array[args.vp_index] = vp; +/* +* Pairs with smp_load_acquire() in mshv_try_assert_irq_fast(), which +* can run concurrently from an irqfd waker without holding pt_mutex. +* The release ensures the VP's initialising stores are visible to any +* reader that observes a non-NULL pointer in pt_vp_array. +*/ +smp_store_release (&partition->pt_vp_array[args.vp_index], vp); goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 195/438 mshv: Publish VP to pt_vp_array before installing the file descriptor
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
[ Upstream commit 72e3b0311aa90568a4b42a64445d1d3e1dc5a34d ]
mshv_partition_ioctl_create_vp() called anon_inode_getfd() before publishing the new VP into partition->pt_vp_array. anon_inode_getfd() includes fd_install(), so the fd was live in current->files before the publish ran.
A concurrent MSHV_RUN_VP ioctl on that fd does not serialise against the in-progress MSHV_CREATE_VP — it takes vp->vp_mutex, not the partition mutex. Once the VP starts running and traps, mshv_intercept_isr() can look up partition->pt_vp_array[vp_index] and observe NULL, silently dropping the intercept message.
Split the fd creation: reserve an fd with get_unused_fd_flags(), create the file with anon_inode_getfile(), publish the VP via smp_store_release(), and finally call fd_install() as the userspace-visibility commit point.
--- drivers/hv/mshv_root_main.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-)
drivers/hv/mshv_root_main.c +22 -7
@@ -1072,6 +1072,8 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,struct mshv_vp *vp;struct page *intercept_msg_page, *register_page, *ghcb_page;struct hv_stats_page *stats_pages[2 ]; +struct file *file; +int fd;long ret;if (copy_from_user (&args, arg,sizeof (args)))
@@ -1146,14 +1148,18 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,if (ret) goto put_partition; -/* -* Keep anon_inode_getfd last: it installs fd in the file struct and -* thus makes the state accessible in user space. -*/ - ret =anon_inode_getfd ("mshv_vp" , &mshv_vp_fops, vp, -O_RDWR |O_CLOEXEC ); -if (ret <0 ) + fd =get_unused_fd_flags (O_RDWR |O_CLOEXEC ); +if (fd <0 ) { + ret = fd; goto remove_debugfs_vp; + } + + file =anon_inode_getfile ("mshv_vp" , &mshv_vp_fops, vp, +O_RDWR |O_CLOEXEC ); +if (IS_ERR (file)) { + ret =PTR_ERR (file); + goto put_unused_vp_fd; + }/* already exclusive with the partition mutex for all ioctls */ partition->pt_vp_count++;
@@ -1165,8 +1171,17 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,*/ smp_store_release (&partition->pt_vp_array[args.vp_index], vp); +/* +* fd_install() is the userspace-visibility commit point. Must be the +* last operation that can fail or be observed. +*/ +fd_install (fd, file); + ret = fd; + goto out; +put_unused_vp_fd: +put_unused_fd (fd); remove_debugfs_vp:mshv_debugfs_vp_remove (vp); put_partition:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 196/438 ring-buffer: Fix subbuf_ids memory leak in rb_allocate_cpu_buffer() error path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit 260b20d9b78bf002f89088fb62d60e8dee98f6f8 ]
In rb_allocate_cpu_buffer(), cpu_buffer->subbuf_ids is allocated using kcalloc() when buffer->remote is non-NULL. If a subsequent page allocation fails (e.g., ring_buffer_desc_page() returns NULL or rb_allocate_pages() fails), execution jumps to fail_free_reader.
While __free(kfree) automatically frees the outer cpu_buffer structure at scope exit, kfree(cpu_buffer) does not recursively free nested heap pointers such as cpu_buffer->subbuf_ids, resulting in a memory leak.
Fix this by explicitly freeing cpu_buffer->subbuf_ids in the fail_free_reader error unwinding path when cpu_buffer->remote is set.
--- kernel/trace/ring_buffer.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/ring_buffer.c +1 -0
@@ -2489,6 +2489,7 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)return_ptr (cpu_buffer); fail_free_reader: +kfree (cpu_buffer->subbuf_ids);free_buffer_page (cpu_buffer->reader_page);return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 197/438 iommufd/viommu: Release the igroup lock on the vdevice_size error path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 339bd11591593ab7ce88136ab7fd01ef3813b724 upstream.
iommufd_vdevice_alloc_ioctl() takes idev->igroup->lock, then validates the driver's vdevice_size against the core structure size with a WARN_ON_ONCE. On failure that guard jumps to out_put_idev, below out_unlock_igroup, so it skips the mutex_unlock(), leaving the igroup lock held and deadlocking the next vDEVICE operation on that group.
Jump to out_unlock_igroup instead.
--- drivers/iommu/iommufd/viommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/iommufd/viommu.c +1 -1
@@ -189,7 +189,7 @@ int iommufd_vdevice_alloc_ioctl(struct iif (WARN_ON_ONCE (viommu->ops->vdevice_size < vdev_size || !viommu->ops->vdevice_init)) { rc = -EOPNOTSUPP ; - goto out_put_idev; + goto out_unlock_igroup; } vdev_size = viommu->ops->vdevice_size; }
Greg Kroah-Hartman
maintainerPATCH 198/438 iommufd/viommu: Publish a vDEVICE only after vdevice_init() succeeds
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 9be311cfbe6154da146a7408e0d5e518a9321ed3 upstream.
iommufd_vdevice_alloc_ioctl() adds the vDEVICE to the viommu->vdevs xarray with xa_cmpxchg() before the driver's vdevice_init() op runs. That op is where a driver validates the device and may reject it, but the xarray entry is already live by then: a concurrent IOMMU_HWPT_INVALIDATE can look it up with iommufd_viommu_find_dev() and run the driver invalidation path against a device that vdevice_init() would have refused.
Reserve the index with xa_insert(): it stores a zero entry that reads back as NULL, and returns -EBUSY on a duplicate virt_id. Run vdevice_init() and store the vDEVICE pointer only once it succeeds. A failed vdevice_init() releases the reservation, so lookups observe the vDEVICE only after it is fully initialized and accepted.
--- drivers/iommu/iommufd/viommu.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
drivers/iommu/iommufd/viommu.c +15 -5
@@ -143,7 +143,7 @@ void iommufd_vdevice_destroy(struct iommint iommufd_vdevice_alloc_ioctl (struct iommufd_ucmd *ucmd) {struct iommu_vdevice_alloc *cmd = ucmd->cmd; -struct iommufd_vdevice *vdev, *curr; +struct iommufd_vdevice *vdev;size_t vdev_size =sizeof (*vdev);struct iommufd_viommu *viommu;struct iommufd_device *idev;
@@ -218,18 +218,28 @@ int iommufd_vdevice_alloc_ioctl(struct i*/ idev->vdev = vdev; - curr =xa_cmpxchg (&viommu->vdevs, virt_id,NULL , vdev,GFP_KERNEL ); -if (curr) { - rc =xa_err (curr) ?: -EEXIST ; +/* +* Reserve the slot with a zero entry (reads back as NULL) until the +* vdevice_init() op accepts the vDEVICE. Only the xa_* helpers hide a +* reserved entry, so never use a raw xas_* iterator on this xarray. +*/ + rc =xa_insert (&viommu->vdevs, virt_id,NULL ,GFP_KERNEL ); +if (rc) { +if (rc == -EBUSY ) + rc = -EEXIST ; goto out_abort; }if (viommu->ops && viommu->ops->vdevice_init) { rc = viommu->ops->vdevice_init (vdev); -if (rc) +if (rc) { +xa_release (&viommu->vdevs, virt_id); goto out_abort; + } } +xa_store (&viommu->vdevs, virt_id, vdev,GFP_KERNEL ); + cmd->out_vdevice_id = vdev->obj.id; rc =iommufd_ucmd_respond (ucmd,sizeof (*cmd));if (rc)
Greg Kroah-Hartman
maintainerPATCH 199/438 iommufd: Reject DMABUF pages from the access pin path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit 5f3fc0ad9a41883a62098359b9fdbe4257f20e53 upstream.
DMABUF pages are not supported for iommufd access pinning. iommufd_access_pin_pages() returns struct page pointers for in-kernel CPU access, but DMABUF-backed iopt_pages do not carry a userspace address that can be passed to the GUP path.
iopt_pages_rw_access() already rejects IOPT_ADDRESS_DMABUF before doing CPU access. Apply the same rejection to iopt_area_add_access() before it takes pages->mutex and calls iopt_pages_fill_xarray(). Otherwise a DMABUF-backed iopt_pages can reach the hole-fill path, where pfn_reader_user_pin() interprets the union as uptr and
calls pin_user_pages_fast()/pin_user_pages_remote().
This fix also avoids the lockdep warning reported from that path, where pages_dmabuf_mutex_key is held while gup_fast_fallback() may acquire mmap_lock.
--- drivers/iommu/iommufd/pages.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/iommu/iommufd/pages.c +3 -0
@@ -2451,6 +2451,9 @@ int iopt_area_add_access(struct iopt_areif ((flags &IOMMUFD_ACCESS_RW_WRITE ) && !pages->writable)return -EPERM ; +if (iopt_is_dmabuf (pages)) +return -EINVAL ; +mutex_lock (&pages->mutex); access =iopt_pages_get_exact_access (pages, start_index, last_index);if (access) {
Greg Kroah-Hartman
maintainerPATCH 200/438 iommufd: Fix wrong hwpt passed to iommufd_auto_response_faults on replace
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit ba5c0f28a26e7d9be1e0997f8920dd638e2782fd upstream.
iommufd_hwpt_replace_device() calls:
iommufd_auto_response_faults(hwpt, old_handle);
passing the *new* hwpt together with the handle of the device's *old* domain. This should be a parameter mismatch:
1. Semantically, iommufd_auto_response_faults(x, handle) scans x->fault's deliver list and response xarray for groups matching "handle". A group is queued under the hwpt that was attached at fault-delivery time. old_handle is fetched *before* the domain switch, so its group lives on old->fault, not on the new hwpt->fault.
2. Historically, the first argument was "old". The routine was introduced by commit b7d8833677ba ("iommufd: Fault-capable hwpt attach/detach/replace") as __fault_domain_replace_dev() in fault.c, correctly calling iommufd_auto_response_faults(old, curr). Commit fb21b1568ada ("iommufd: Make attach_handle generic than fault specific") moved this into iommufd_hwpt_replace_device() in device.c and swapped it to "hwpt". This should be a refactor regression, not an intentional change.
Fix this by passing "old" instead.
--- drivers/iommu/iommufd/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/iommufd/device.c +1 -1
@@ -589,7 +589,7 @@ static int iommufd_hwpt_replace_device(sif (rc) goto out_free_handle; -iommufd_auto_response_faults (hwpt, old_handle); +iommufd_auto_response_faults (old, old_handle);kfree (old_handle);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 201/438 iommu/iommufd: Fix IOPF group ownership UAF
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit 738e6f32e61d80b554e37015ecb7bc620b88001c upstream.
iopf_group_alloc() links each last-page IOPF group into the generic IOPF pending list before invoking the domain fault handler. iommufd_fault_iopf_handler() also queued an accepted group in the IOMMUFD deliver list without removing it from the generic pending list.
When detach or HWPT replacement drops the device's IOPF reference count to zero, an IOMMU driver may call iopf_queue_remove_device(). That function responds to and frees groups through the generic pending list without removing the same groups from IOMMUFD's deliver list or response xarray. A later read, response, or cleanup can then access the freed group and cause a UAF.
Fix this by dequeuing an accepted group from the generic pending list before IOMMUFD queues it for userspace response.
Make iopf_group_response() send a response regardless of pending-list membership, so the dequeued group can still be completed by IOMMUFD.
--- drivers/iommu/io-pgfault.c | 24 +++++++++++++++++++----- drivers/iommu/iommufd/eventq.c | 2 ++ include/linux/iommu.h | 5 +++++ 3 files changed, 26 insertions(+), 5 deletions(-)
drivers/iommu/io-pgfault.c +19 -5
@@ -332,17 +332,31 @@ void iopf_group_response(struct iopf_gro .code = status, }; -/* Only send response if there is a fault report pending */ mutex_lock (&fault_param->lock); -if (!list_empty (&group->pending_node)) { - ops->page_response (dev, &group->last_fault, &resp); -list_del_init (&group->pending_node); - } + ops->page_response (dev, &group->last_fault, &resp); +list_del_init (&group->pending_node);mutex_unlock (&fault_param->lock); }EXPORT_SYMBOL_GPL (iopf_group_response);/** +* iopf_group_dequeue - Dequeue a page fault group from the pending list +* @group: the group to dequeue +* +* The fault handler is responsible for responding to the group after +* this function returns. +*/ +void iopf_group_dequeue (struct iopf_group *group) +{ +struct iommu_fault_param *fault_param = group->fault_param; + +mutex_lock (&fault_param->lock); +list_del_init (&group->pending_node); +mutex_unlock (&fault_param->lock); +} +EXPORT_SYMBOL_GPL (iopf_group_dequeue); + +/** * iopf_queue_discard_partial - Remove all pending partial fault * @queue: the queue whose partial faults need to be discarded *
drivers/iommu/iommufd/eventq.c +2 -0
@@ -484,6 +484,8 @@ int iommufd_fault_iopf_handler(struct io hwpt = group->attach_handle->domain->iommufd_hwpt; fault = hwpt->fault; +iopf_group_dequeue (group); +spin_lock (&fault->common.lock);list_add_tail (&group->node, &fault->common.deliver);spin_unlock (&fault->common.lock);
include/linux/iommu.h +5 -0
@@ -1676,6 +1676,7 @@ void iopf_free_group(struct iopf_group *int iommu_report_device_fault (struct device *dev,struct iopf_fault *evt);void iopf_group_response (struct iopf_group *group,enum iommu_page_response_code status); +void iopf_group_dequeue (struct iopf_group *group);#else static inline int iopf_queue_add_device (struct iopf_queue *queue,struct device *dev)
@@ -1721,5 +1722,9 @@ static inline void iopf_group_response(s enum iommu_page_response_code status) { } + +static inline void iopf_group_dequeue (struct iopf_group *group) +{ +}#endif /* CONFIG_IOMMU_IOPF */ #endif /* __LINUX_IOMMU_H */
Greg Kroah-Hartman
maintainerPATCH 202/438 kbuild: Stop modifying $(objtree)/Makefile when building oot-kmods oos
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolas Schier <[email protected]>
commit 39d6e68f50f4a444a6ba23b9ea2eaee806601c6d upstream.
Update output Makefile in the corresponding tree only: for out-of-source in-tree builds update $(objtree)/Makefile, for out-of-source out-of-tree module builds update $(KBUILD_EXTMOD_OUTPUT)/Makefile instead.
In-source builds are not affected.
Since commit c9bb03ac2c66 ("kbuild: reduce output spam when building out of tree"), building out-of-tree kernel modules out-of-source (make M=... MO=...) causes a rewrite of $(objtree)/Makefile with KBUILD_EXTMOD and KBUILD_EXTMOD_OUTPUT being set. That is problematic:
* $(objtree)/ must not be changed in any way when building out-of-tree modules as it breaks other uses of $(objtree).
* Setting KBUILD_EXTMOD and KBUILD_EXTMOD_OUTPUT in $(objtree)/Makefile kills the tree for incremental builds that start right there ('make -C $(objtree)'); builds starting in $(srctree) reset $(objtree)/Makefile to its original content.
Further, $(KBUILD_EXTMOD_OUTPUT)/Makefile was not generated any more at all.
This commit restores the previous kbuild behaviour prior to commit c9bb03ac2c66 ("kbuild: reduce output spam when building out of tree") but leaves in-place the use of filechk for output spam reduction.
--- Makefile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
Makefile +3 -5
@@ -695,13 +695,11 @@ filechk_makefile = { \ echo "include $(abs_srctree)/Makefile"; \ } -$(objtree)/Makefile: FORCE +PHONY += $(CURDIR)/Makefile +$(CURDIR)/Makefile: FORCE $(call filechk,makefile) -# Prevent $(srcroot)/Makefile from inhibiting the rule to run. -PHONY += $(objtree)/Makefile - -outputmakefile: $(objtree)/Makefile +outputmakefile: $(CURDIR)/Makefile ifeq ($(KBUILD_EXTMOD),) @if [ -f $(srctree)/.config -o \ -d $(srctree)/include/config -o \
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 203/438 ACPI: CPPC: Check all controls for fast switching
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Loehle <[email protected]>
commit 11055a46f398779b69aa36afb7c9f4124529a075 upstream.
ACPI 6.2, Section 6.2.11.2 permits _CPC registers to use flexible address spaces. Linux advertises that capability through _OSC and parses the address space of each _CPC register independently. A directly accessible DESIRED_PERF combined with PCC-backed limits is therefore a valid configuration.
cppc_allow_fast_switch() only checks DESIRED_PERF, although the fast-switch callback passes DESIRED_PERF, MIN_PERF and MAX_PERF to cppc_set_perf(). If a limit uses PCC, that function can sleep while called from scheduler context.
Allow fast switching only when every supported control used by the callback has an address space already accepted for fast access. Check the complete policy domain, including initialized CPUs that are currently offline and may later become the policy's managing CPU.
--- drivers/acpi/cppc_acpi.c | 22 +++++++++++++++++----- drivers/cpufreq/cppc_cpufreq.c | 2 +- include/acpi/cppc_acpi.h | 5 +++-- 3 files changed, 21 insertions(+), 8 deletions(-)
drivers/acpi/cppc_acpi.c +17 -5
@@ -475,17 +475,29 @@ bool acpi_cpc_valid(void) }EXPORT_SYMBOL_GPL (acpi_cpc_valid); -bool cppc_allow_fast_switch (void ) +bool cppc_allow_fast_switch (const struct cpumask *cpus) { -struct cpc_register_resource *desired_reg; +struct cpc_register_resource *desired_reg, *min_reg, *max_reg;struct cpc_desc *cpc_ptr;int cpu; -for_each_online_cpu (cpu) { +for_each_cpu (cpu, cpus) { cpc_ptr =per_cpu (cpc_desc_ptr, cpu); +if (!cpc_ptr) +return false; desired_reg = &cpc_ptr->cpc_regs[DESIRED_PERF ]; -if (!CPC_IN_SYSTEM_MEMORY (desired_reg) && - !CPC_IN_SYSTEM_IO (desired_reg)) + min_reg = &cpc_ptr->cpc_regs[MIN_PERF ]; + max_reg = &cpc_ptr->cpc_regs[MAX_PERF ]; + +if (!CPC_SUPPORTED (desired_reg) || + (!CPC_IN_SYSTEM_MEMORY (desired_reg) && + !CPC_IN_SYSTEM_IO (desired_reg)) || + (CPC_SUPPORTED (min_reg) && + !CPC_IN_SYSTEM_MEMORY (min_reg) && + !CPC_IN_SYSTEM_IO (min_reg)) || + (CPC_SUPPORTED (max_reg) && + !CPC_IN_SYSTEM_MEMORY (max_reg) && + !CPC_IN_SYSTEM_IO (max_reg)))return false; }
drivers/cpufreq/cppc_cpufreq.c +1 -1
@@ -694,7 +694,7 @@ static int cppc_cpufreq_cpu_init(struct goto out; } - policy->fast_switch_possible =cppc_allow_fast_switch (); + policy->fast_switch_possible =cppc_allow_fast_switch (policy->cpus); policy->dvfs_possible_from_any_cpu = true;/*
include/acpi/cppc_acpi.h +3 -2
@@ -166,7 +166,7 @@ extern u64 cppc_get_dmi_max_khz(void);extern unsigned int cppc_perf_to_khz (struct cppc_perf_caps *caps,unsigned int perf);extern unsigned int cppc_khz_to_perf (struct cppc_perf_caps *caps,unsigned int freq);extern bool acpi_cpc_valid (void ); -extern bool cppc_allow_fast_switch (void ); +bool cppc_allow_fast_switch (const struct cpumask *cpus);extern int acpi_get_psd_map (unsigned int cpu,struct cppc_cpudata *cpu_data);extern int cppc_get_transition_latency (int cpu);extern bool cpc_ffh_supported (void );
@@ -230,7 +230,8 @@ static inline bool acpi_cpc_valid(void) {return false; } -static inline bool cppc_allow_fast_switch (void ) + +static inline bool cppc_allow_fast_switch (const struct cpumask *cpus) {return false; }
Greg Kroah-Hartman
maintainerPATCH 204/438 mm: mglru: fix stale batch updates after memcg reparenting
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qi Zheng <[email protected]>
commit de4660898b7aa7e03d3b120a6bfa6b26211e4e77 upstream.
The mglru page table walker batches per-generation size deltas in walk->nr_pages while walking page tables without holding the lruvec lock. The reset_batch_size() later folds those deltas into walk->lruvec under the lruvec lock.
The page table walker can run concurrently with the memcg reparenting path as follows:
CPU0 CPU1
==== ====
walk_mm
--> walk_page_range
--> update_batch_size
--> walk->nr_pages += delta
mem_cgroup_css_offline
--> memcg_reparent_objcgs
--> lock lruvec
lru_gen_reparent_memcg
--> reparent child folios to parent
unlock lruvec
lock lruvec
reset_batch_size
--> child lrugen->nr_pages += deltaThis will trigger the following warning in lru_gen_exit_memcg():
VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, sizeof(lruvec->lrugen.nr_pages)));
And the user-visible impact of underestimated nr_pages in MGLRU was premature OOMs because MGLRU does not try to reclaim memory when nr_pages reaches zero, but there are still more pages.
To fix it, make reset_batch_size() check CSS_DYING under RCU before flushing the pending batch. A non-dying memcg keeps the original lruvec stable against RCU-delayed offlining; a dying memcg redirects the deltas to the first non-dying ancestor.
--- include/linux/memcontrol.h | 25 +++++++++++++++++++++++++ mm/vmscan.c | 11 ++++------- 2 files changed, 29 insertions(+), 7 deletions(-)
include/linux/memcontrol.h +25 -0
@@ -1475,6 +1475,31 @@ static inline void lruvec_lock_irq(strucspin_lock_irq (&lruvec->lru_lock); } +static inline struct lruvec *lruvec_live_lock_irq (struct lruvec *lruvec) +{ +#ifdef CONFIG_MEMCG +struct pglist_data *pgdat =lruvec_pgdat (lruvec); +struct mem_cgroup *memcg =lruvec_memcg (lruvec); + +rcu_read_lock (); + +/* +* The memcg can be NULL when the memory controller is disabled. +* Otherwise, the caller keeps the memcg owning @lruvec alive. +*/ +while (unlikely (memcg &&css_is_dying (&memcg->css))) { + memcg =parent_mem_cgroup (memcg); + lruvec =mem_cgroup_lruvec (memcg, pgdat); + } + +spin_lock_irq (&lruvec->lru_lock); +#else +lruvec_lock_irq (lruvec); +#endif + +return lruvec; +} +static inline void lruvec_unlock (struct lruvec *lruvec) {spin_unlock (&lruvec->lru_lock);
mm/vmscan.c +4 -7
@@ -3268,7 +3268,7 @@ static void update_batch_size(struct lrustatic void reset_batch_size (struct lru_gen_mm_walk *walk) {int gen, type, zone; -struct lruvec *lruvec = walk->lruvec; +struct lruvec *lruvec =lruvec_live_lock_irq (walk->lruvec);struct lru_gen_folio *lrugen = &lruvec->lrugen; walk->batched =0 ;
@@ -3288,6 +3288,8 @@ static void reset_batch_size(struct lru_ lru +=LRU_ACTIVE ;__update_lru_size (lruvec, lru, zone, delta); } + +lruvec_unlock_irq (lruvec); }static int should_skip_vma (unsigned long start,unsigned long end,struct mm_walk *args)
@@ -3782,11 +3784,8 @@ static void walk_mm(struct mm_struct *mmmmap_read_unlock (mm); } -if (walk->batched) { -lruvec_lock_irq (lruvec); +if (walk->batched)reset_batch_size (walk); -lruvec_unlock_irq (lruvec); - }cond_resched (); }while (err == -EAGAIN );
@@ -4884,9 +4883,7 @@ retry: walk = current->reclaim_state->mm_walk;if (walk && walk->batched) { walk->lruvec = lruvec; -lruvec_lock_irq (lruvec);reset_batch_size (walk); -lruvec_unlock_irq (lruvec); } mod_lruvec_state(lruvec, PGDEMOTE_KSWAPD + reclaimer_offset(sc),
Greg Kroah-Hartman
maintainerPATCH 205/438 mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiryl Shutsemau (Meta) <[email protected]>
commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23 upstream.
copy_hugetlb_page_range() clears the uffd-wp bit of migration and hwpoison entries with huge_pte_clear_uffd_wp(), which operates on the present-PTE bit position. Swap entries keep the uffd-wp state elsewhere -- the migration branch reads and sets it with pte_swp_uffd_wp() and pte_swp_mkuffd_wp() -- and the present-PTE position falls into the swap payload. On x86-64 it lands in the inverted swap offset, where a naturally-aligned hugetlb PFN always has the affected bit set, so the clear advances the encoded PFN by two pages.
No userfaultfd needs to be involved: the clear is guarded only by the child VMA not being uffd-wp registered, so a plain fork() with an in-flight hugetlb migration entry (or a poisoned hugetlb page) corrupts the entry copied into the child. Instrumenting the clear and forking after MADV_HWPOISON on a 2MB anon hugetlb page shows:
offset before=120e00
offset after =120e02
The fallout is mostly latent: rmap walks match migration entries by folio range and remove_migration_pte() rebuilds the PTE from the folio, so a within-folio PFN skew heals once migration completes. But any path that re-encodes the corrupted offset -- e.g. hugetlb_change_protection() rewriting a writable migration entry via make_readable_migration_entry(swp_offset(entry)) -- propagates it.
Migration entries legitimately carry uffd-wp, so clear it with pte_swp_clear_uffd_wp(), matching copy_nonpresent_pte() and move_huge_pte().
A hwpoison entry, on the other hand, never carries the uffd-wp bit: it is installed fresh by make_hwpoison_entry() (try_to_unmap_one() does not preserve uffd-wp on the hwpoison path) and hugetlb_change_protection() leaves hwpoison entries untouched. There was nothing to clear there, only the corruption, so drop the clear entirely.
--- mm/hugetlb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
mm/hugetlb.c +7 -3
@@ -4917,8 +4917,12 @@ again: softleaf =softleaf_from_pte (entry);if (unlikely (softleaf_is_hwpoison (softleaf))) { -if (!userfaultfd_wp (dst_vma)) - entry =huge_pte_clear_uffd_wp (entry); +/* +* A hwpoison entry never carries the uffd-wp bit: it is +* installed fresh by make_hwpoison_entry() and +* hugetlb_change_protection() leaves it untouched, so +* there is nothing to clear for the child. +*/ set_huge_pte_at (dst, addr, dst_pte, entry, sz); }else if (unlikely (softleaf_is_migration (softleaf))) {bool uffd_wp =pte_swp_uffd_wp (entry);
@@ -4936,7 +4940,7 @@ again:set_huge_pte_at (src, addr, src_pte, entry, sz); }if (!userfaultfd_wp (dst_vma)) - entry =huge_pte_clear_uffd_wp (entry); + entry =pte_swp_clear_uffd_wp (entry);set_huge_pte_at (dst, addr, dst_pte, entry, sz); }else if (unlikely (pte_is_marker (entry))) {const pte_marker marker =copy_pte_marker (softleaf, dst_vma);
Greg Kroah-Hartman
maintainerPATCH 206/438 pinctrl: microchip-sgpio: add missing select REGMAP_MMIO
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Boortz <[email protected]>
commit 25cb6e9a13123d1039cdc75b446ac52e1ebdc26d upstream.
The driver calls ocelot_regmap_from_resource() via <linux/mfd/ocelot.h>, which internally uses devm_regmap_init_mmio() and requires REGMAP_MMIO. The Kconfig entry does not select REGMAP_MMIO, causing a build failure when no other driver in the config happens to pull in REGMAP_MMIO:
include/linux/mfd/ocelot.h:34:24: error: implicit declaration of function 'devm_regmap_init_mmio'
Found by randconfig testing on arm64; tinyconfig reproducer below.
--- drivers/pinctrl/Kconfig | 1 + 1 file changed, 1 insertion(+)
drivers/pinctrl/Kconfig +1 -0
@@ -416,6 +416,7 @@ config PINCTRL_MICROCHIP_SGPIO select GENERIC_PINCONF select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS + select REGMAP_MMIO help Support for the serial GPIO interface used on Microsemi and Microchip SoCs. By using a serial interface, the SIO
Greg Kroah-Hartman
maintainerPATCH 207/438 pinctrl: devicetree: dont free uninitialized dev_name on error path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit 015b5bcbcb622b32317642be91a7f79aa5413649 upstream.
dt_remember_or_free_map() duplicates dev_name for each map entry. If kstrdup_const() fails, dt_free_map() frees dev_name in all num_maps entries, including entries that have not been initialized.
Some pinctrl drivers, including pinctrl-imx, allocate the map with kmalloc() and leave dev_name for the core to initialize. The untouched entries therefore contain uninitialized data which is passed to kfree_const().
Reproduced on qemu's mcimx6ul-evk (pinctrl-imx) with failslab injection while binding the pinctrl-consuming device, under KASAN:
BUG: KASAN: double-free in dt_free_map+0x34/0xa4 Free of addr c425a900 by task init/1 kfree from dt_free_map+0x34/0xa4 dt_free_map from dt_remember_or_free_map+0x184/0x198 dt_remember_or_free_map from pinctrl_dt_to_map+0x33c/0x4c8 pinctrl_dt_to_map from create_pinctrl+0x9c/0x5c0
Initialize all dev_name fields to NULL before duplicating the device name, making the full-map cleanup safe after a partial failure.
--- drivers/pinctrl/devicetree.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/pinctrl/devicetree.c +4 -0
@@ -69,6 +69,10 @@ static int dt_remember_or_free_map(strucint i;struct pinctrl_dt_map *dt_map; +/* Initialize dev_name before any allocation can fail */ +for (i =0 ; i < num_maps; i++) + map[i].dev_name =NULL ; +/* Initialize common mapping table entry fields */ for (i =0 ; i < num_maps; i++) {const char *devname;
Greg Kroah-Hartman
maintainerPATCH 208/438 btrfs: raid56: fix scrub read assembly submitting no reads
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mykola Lysenko <[email protected]>
commit c4c0673e4cb15b0c127e6d00732a2427bdd12c11 upstream.
Commit 5387bd958180 ("btrfs: raid56: remove sector_ptr structure") converted the bio-list membership checks from sector pointers to physical addresses. The two conversions in rmw_assemble_write_bios() kept their polarity (skip the sector when it is NOT in the bio list, i.e. when there is nothing to write), but scrub_assemble_read_bios() has the opposite polarity -- skip the sector when it IS in the bio list, because then there is nothing to read -- and the conversion flipped it:
- sector = sector_in_rbio(rbio, stripe, sectornr, 1); - if (sector) + paddr = sector_paddr_in_rbio(rbio, stripe, sectornr, 1); + if (paddr == INVALID_PADDR) continue;
Since a parity-scrub rbio's bio list only holds the empty completion bio, the result is that scrub_assemble_read_bios() submits no reads at all. finish_parity_scrub() then compares the parity it computes from the (cached, correct) data stripes against whatever happens to be in the freshly allocated, uninitialized stripe pages:
- if the garbage differs from the computed parity, the sector is "repaired" and written back -- accidentally producing the correct on-disk result;
- if a recycled page happens to still hold the old (correct) parity content, the sector is deemed clean, dropped from dbitmap, and the actually-corrupt on-disk parity is left in place. (Scrub reports no errors either way: there is no counter for P/Q corruption by design, so the bug here is purely the failure to read and repair.)
The second case is intermittent because it depends on page-allocator recycling. Observed with fstests btrfs/297 (raid5, 2 devices): the corrupted P stripe intermittently stays corrupt after a scrub -- roughly 1/10 runs on x86-64 KVM and up to 7/8 on a UML build whose timing favors page reuse.
Since the bio-list check can never be true for a parity-scrub rbio -- raid56_parity_alloc_scrub_rbio() adds a single empty completion bio (asserting bi_size == 0), bio_paddrs[] is only populated by index_rbio_pages() which is never called for BTRFS_RBIO_PARITY_SCRUB, and rbio_can_merge() refuses to merge rbios of different operations -- remove the dead check entirely and assert the invariant instead, as suggested by Qu Wenruo.
After this fix the injected corruption is read, detected and repaired in every run (8/8 UML, 10/10 KVM), and the new assertion never fires across the full fstests raid group.
--- fs/btrfs/raid56.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
fs/btrfs/raid56.c +5 -6
@@ -2911,13 +2911,12 @@ static int scrub_assemble_read_bios(struct btrfs_raid_bio *rbio)continue ;/* -* We want to find all the sectors missing from the rbio and -* read them from the disk. If sector_paddr_in_rbio() finds a sector -* in the bio list we don't need to read it off the stripe. +* A parity-scrub rbio carries no data in its bio list: the +* only bio there is the empty completion bio added by +* raid56_parity_alloc_scrub_rbio(). Every sector is read +* from the stripe, so only assert that invariant here. */ - paddrs =sector_paddrs_in_rbio (rbio, stripe, sectornr,1 ); -if (paddrs ==NULL ) -continue ; +ASSERT (!sector_paddrs_in_rbio (rbio, stripe, sectornr,1 )); paddrs =rbio_stripe_paddrs (rbio, stripe, sectornr);/*
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 209/438 erofs: cap LZMA stream pool size
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit c9b47e6b23114e939b17f818471c7a46e59006e7 upstream.
fs/erofs/decompressor_lzma.c sizes the module-global MicroLZMA stream pool from num_possible_cpus() when the lzma_streams module parameter is unset, then z_erofs_load_lzma_config() preallocates one image-supplied dictionary per stream, accepting dictionaries up to 8 MiB. On high-CPU systems, a small EROFS image can pin hundreds of MiB of vmalloc-backed decoder state until the erofs module is unloaded.
Impact: An EROFS image mounted by the system can pin up to 8 MiB of vmalloc memory per LZMA stream, either as intended or unexpectedly.
Bound the default stream count by a new CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS option, default 16, so the worst-case default preallocation is 128 MiB if the number of CPUs is no less than 16 while preserving the existing per-image dictionary limit. An explicit lzma_streams module parameter is still honoured as-is, so administrators who deliberately size the pool are not affected.
--- fs/erofs/Kconfig | 14 ++++++++++++++ fs/erofs/decompressor_lzma.c | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-)
fs/erofs/Kconfig +14 -0
@@ -131,6 +131,20 @@ config EROFS_FS_ZIP_LZMA Say N if you want to disable LZMA compression support. +config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS + int "EROFS LZMA default maximum decompression streams" + depends on EROFS_FS_ZIP_LZMA + range 1 NR_CPUS + default 16 + help + By default EROFS allocates one LZMA decompression stream per CPU. + Each stream can hold a dictionary of up to 8 MiB taken from the + mounted image, so on systems with many CPUs this can reserve a lot + of memory. This caps the default; the lzma_streams module parameter + still overrides it. + + If unsure, keep the default of 16. + config EROFS_FS_ZIP_DEFLATE bool "EROFS DEFLATE compressed data support" depends on EROFS_FS_ZIP
fs/erofs/decompressor_lzma.c +2 -1
@@ -51,7 +51,8 @@ static int __init z_erofs_lzma_init(void/* by default, use # of possible CPUs instead */ if (!z_erofs_lzma_nstrms) - z_erofs_lzma_nstrms =num_possible_cpus (); + z_erofs_lzma_nstrms = min_t(unsigned int, num_possible_cpus(), +CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS );for (i =0 ; i < z_erofs_lzma_nstrms; ++i) {struct z_erofs_lzma *strm =kzalloc_obj (*strm);
Greg Kroah-Hartman
maintainerPATCH 210/438 pinctrl: bm1880: add missing select GENERIC_PINCONF
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Boortz <[email protected]>
commit dad6e107b3cd9d20514e7799b7ad8674f81e3f30 upstream.
drivers/pinctrl/pinctrl-bm1880.c initialises its pinconf_ops with .is_generic = true, but that field is only present when CONFIG_GENERIC_PINCONF is enabled (guarded by #ifdef in pinconf.h). The Kconfig entry for PINCTRL_BM1880 never selects GENERIC_PINCONF, so any config that enables CONFIG_PINCTRL_BM1880=y without CONFIG_GENERIC_PINCONF=y fails to compile:
drivers/pinctrl/pinctrl-bm1880.c:1288:10: error: 'const struct pinconf_ops' has no member named 'is_generic'
Found by randconfig testing on arm64; tinyconfig reproducer below. Add the missing select to fix the build.
--- drivers/pinctrl/Kconfig | 1 + 1 file changed, 1 insertion(+)
drivers/pinctrl/Kconfig +1 -0
@@ -166,6 +166,7 @@ config PINCTRL_BM1880 depends on OF && (ARCH_BITMAIN || COMPILE_TEST) default ARCH_BITMAIN select PINMUX + select GENERIC_PINCONF help Pinctrl driver for Bitmain BM1880 SoC.
Greg Kroah-Hartman
maintainerPATCH 211/438 fortify: Disable -Wstringop-overread in tests
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Chancellor <[email protected]>
commit c1f3e770eec26d6f96dd6d2ea30555ba7c09a244 upstream.
clang recently added support for -Wstringop-overread [1], which is on by default like -Wfortify-source. This breaks the usage of -Werror in the fortify tests, resulting in the following false positive warnings in the kernel build:
warning: unsafe memcmp() usage lacked '__read_overflow2' warning in lib/test_fortify/read_overflow2-memcmp.c
warning: unsafe memcmp() usage lacked '__read_overflow' warning in lib/test_fortify/read_overflow-memcmp.c
warning: unsafe memchr() usage lacked '__read_overflow' warning in lib/test_fortify/read_overflow-memchr.c
Examining the fortify test logs shows a warning like the following in each of the failed logs:
In file included from lib/test_fortify/read_overflow2-memcmp.c:5:
lib/test_fortify/test_fortify.h:34:2: error: 'memcmp' reading 17 bytes from a region of size 16 [-Werror,-Wstringop-overread]
34 | TEST;
| ^
lib/test_fortify/read_overflow2-memcmp.c:3:2: note: expanded from macro 'TEST'
3 | memcmp(large, small, sizeof(small) + 1)
| ^1 error generated.
Disable -Wstringop-overread for the fortify tests, as it defeats the purpose of testing the Linux specific implementation of fortify, like -Wfortify-source.
--- lib/test_fortify/Makefile | 1 + 1 file changed, 1 insertion(+)
lib/test_fortify/Makefile +1 -0
@@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 ccflags-y := $(call cc-disable-warning,fortify-source) +ccflags-y += $(call cc-disable-warning,stringop-overread) quiet_cmd_test_fortify = TEST $@ cmd_test_fortify = $(CONFIG_SHELL) $(src)/test_fortify.sh \
Greg Kroah-Hartman
maintainerPATCH 212/438 lib: test_hmm: use device devt for coherent device range selection
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
commit 4fc089235378d1f9ddb6bcbe67c192ffdcaae0ed upstream.
Commit af69016dab96 ("lib: test_hmm: implement a device release method") moved the initial dmirror_allocate_chunk() call before cdev_device_add(). That means the struct cdev has not been added yet, so cdev_add() has not initialized mdevice->cdevice.dev.
The coherent-device range selection uses the device minor to choose between spm_addr_dev0 and spm_addr_dev1. Reading MINOR(mdevice->cdevice.dev) before cdev_add() therefore always sees an uninitialized dev_t. As a result, both coherent devices select the same physical range, and adding the second device fails due to the overlapping dev_pagemap range.
Use mdevice->device.devt instead. It is initialized in dmirror_device_init() before dmirror_allocate_chunk() is called and is the same dev_t later passed to cdev_device_add().
--- lib/test_hmm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/test_hmm.c +1 -1
@@ -581,7 +581,7 @@ static int dmirror_allocate_chunk(struct dmirror_device *mdevice, devmem->pagemap.type =MEMORY_DEVICE_PRIVATE ;break ;case HMM_DMIRROR_MEMORY_DEVICE_COHERENT : - devmem->pagemap.range.start = (MINOR (mdevice->cdevice.dev) -2 ) ? + devmem->pagemap.range.start = (MINOR (mdevice->device.devt) -2 ) ? spm_addr_dev0 : spm_addr_dev1; devmem->pagemap.range.end = devmem->pagemap.range.start +
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 213/438 btrfs: zoned: fix missing chunk metadata reservation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Yang <[email protected]>
commit 8bc4d7209611e8aa9d5409b6a4a86a9eb91b69a3 upstream.
reserve_chunk_space() stores the return value of btrfs_zoned_activate_one_bg() in ret. The helper can return 1 after successfully activating a block group, but ret is later used to decide whether to reserve metadata for chunk tree updates.
As a result, successful activation skips btrfs_block_rsv_add() and leaves trans->chunk_bytes_reserved unchanged. Use a separate variable for the activation result so positive success does not affect the later reservation. Keep activation failures in ret instead of returning early so the function uses the common tail path.
--- fs/btrfs/block-group.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-)
fs/btrfs/block-group.c +19 -15
@@ -4504,25 +4504,29 @@ static void reserve_chunk_space(struct bif (IS_ERR (bg)) { ret =PTR_ERR (bg); }else { +int activate_ret; +/* * We have a new chunk. We also need to activate it for * zoned filesystem. */ - ret =btrfs_zoned_activate_one_bg (info, true); -if (ret <0 ) -return ; - -/* -* If we fail to add the chunk item here, we end up -* trying again at phase 2 of chunk allocation, at -* btrfs_create_pending_block_groups(). So ignore -* any error here. An ENOSPC here could happen, due to -* the cases described at do_chunk_alloc() - the system -* block group we just created was just turned into RO -* mode by a scrub for example, or a running discard -* temporarily removed its free space entries, etc. -*/ -btrfs_chunk_alloc_add_chunk_item (trans, bg); + activate_ret =btrfs_zoned_activate_one_bg (info, true); +if (activate_ret <0 ) { + ret = activate_ret; + }else { +/* +* If we fail to add the chunk item here, we end +* up trying again at phase 2 of chunk allocation, +* at btrfs_create_pending_block_groups(). So +* ignore any error here. An ENOSPC here could +* happen, due to the cases described at +* do_chunk_alloc() - the system block group we +* just created was just turned into RO mode by a +* scrub for example, or a running discard +* temporarily removed its free space entries, etc. +*/ +btrfs_chunk_alloc_add_chunk_item (trans, bg); + } } }
Greg Kroah-Hartman
maintainerPATCH 214/438 ocfs2: fix boundary check in ocfs2_check_dir_entry() to use buffer offset
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joseph Qi <[email protected]>
commit df8ce7ab48d01ac4f247599b35f0506d95ff57e1 upstream.
Commit 390ac56cf0f6 ("ocfs2: add boundary check to ocfs2_check_dir_entry()") added an out-of-bounds guard using the caller-supplied 'offset' argument:
if (offset > size - OCFS2_DIR_REC_LEN(1)) return 0;
However, 'offset' and 'size' are not measured against the same base for all callers. In the block-based lookup path, ocfs2_find_entry_el() passes 'offset' as an absolute offset into the whole directory:
i = ocfs2_search_dirblock(bh, dir, name, namelen, block << sb->s_blocksize_bits, bh->b_data, sb->s_blocksize, res_dir);
while 'size' is a single block size (sb->s_blocksize). For any directory entry located in the second or later block, 'offset' is >= sb->s_blocksize, so the guard rejects every such entry even though it is perfectly valid and lies entirely within its block buffer.
This makes mounting fail for filesystems whose system directory spans more than one block, e.g. a volume formatted with a small block size:
mkfs.ocfs2 -b 512 -C 4096 -N 2 -T datafiles --fs-features=usrquota,grpquota
ocfs2_check_dir_entry:314 ERROR: directory entry (#18: offset=512) too close to end or out-of-bounds ocfs2_init_local_system_inodes:496 ERROR: status=-22, sysfile=12, slot=0 ocfs2_mount_volume:1757 ERROR: status = -22
The dirent's position within the buffer being validated is ((char *)de - buf), which is what the rest of the function already uses (via next_offset) and what must be bounds-checked against 'size'. Compute that buffer-relative offset and use it for the guard. The subtraction is reordered to size - buf_offset < OCFS2_DIR_REC_LEN(1) to avoid an unsigned underflow when size is smaller than the minimal record length.
--- fs/ocfs2/dir.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/ocfs2/dir.c +3 -2
@@ -302,10 +302,11 @@ static int ocfs2_check_dir_entry(struct unsigned long offset) {const char *error_msg =NULL ; +unsigned long buf_offset = (char *)de - buf;unsigned long next_offset;int rlen; -if (offset > size -OCFS2_DIR_REC_LEN (1 )) { +if (buf_offset > size || size - buf_offset <OCFS2_DIR_REC_LEN (1 )) {/* Dirent is (maybe partially) beyond the buffer * boundaries so touching 'de' members is unsafe. */
@@ -316,7 +317,7 @@ static int ocfs2_check_dir_entry(struct } rlen =le16_to_cpu (de->rec_len); - next_offset = ((char *) de - buf) + rlen; + next_offset = buf_offset + rlen;if (unlikely (rlen <OCFS2_DIR_REC_LEN (1 ))) error_msg ="rec_len is smaller than minimal" ;
Greg Kroah-Hartman
maintainerPATCH 215/438 mm: migrate_device: fix pte_pfn/pte_dirty called on non-present PTE
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kefeng Wang <[email protected]>
commit 63867c82d0c0c2d182016a32b1cc0103116b0ea5 upstream.
pte_pfn() and pte_dirty() have undefined behaviour when called on a non-present PTE. In migrate_vma_collect_pmd(), these functions may be invoked on non-present entries (e.g., device-private entries), leading to potential crashes from pte_pfn() or incorrect dirty folio accounting from pte_dirty(). Fix both by guarding with pte_present() checks.
--- mm/migrate_device.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
mm/migrate_device.c +3 -2
@@ -401,7 +401,8 @@ again:bool anon_exclusive;pte_t swp_pte; -flush_cache_page (vma, addr,pte_pfn (pte)); +if (pte_present (pte)) +flush_cache_page (vma, addr,pte_pfn (pte)); anon_exclusive =folio_test_anon (folio) &&PageAnonExclusive (page);if (anon_exclusive) {
@@ -422,7 +423,7 @@ again: migrate->cpages++;/* Set the dirty flag on the folio now the pte is gone. */ -if (pte_dirty (pte)) +if (pte_present (pte) &&pte_dirty (pte))folio_mark_dirty (folio);/* Setup special migration page table entry */
Greg Kroah-Hartman
maintainerPATCH 216/438 mm/util: dont read __page_2 for order-1 folios in snapshot_page()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
commit 7441d6348c70738e9ed307510db171c7a9b3f4bf upstream.
snapshot_page() currently reads __page_2 after checking nr_pages > 1, but it should only do so when nr_pages > 2.
If an order-1 folio is allocated at the end of a vmemmap section, __page_2 will not exist and reading it will cause a fault.
During DLPAR memory remove on a 22 TB ppc64le LPAR, snapshot_page() oopsed on the page isolation path while reading an order-1 folio's __page_2 from an adjacent absent section (unmapped vmemmap).
Fix this to avoid reading memmap that doesn't exist (e.g., a vmemmap hole).
--- mm/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/util.c +1 -1
@@ -1352,7 +1352,7 @@ again:if (ps->idx <MAX_FOLIO_NR_PAGES ) {memcpy (&ps->folio_snapshot, foliop,2 *sizeof (struct page )); nr_pages =folio_nr_pages (&ps->folio_snapshot); -if (nr_pages >1 ) +if (nr_pages >2 )memcpy (&ps->folio_snapshot.__page_2, &foliop->__page_2,sizeof (struct page ));set_ps_flags (ps, foliop, page);
Greg Kroah-Hartman
maintainerPATCH 217/438 selftest: fix headers in fclog.c
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jori Koolstra <[email protected]>
commit e3a0127eee04db8769e53c8102c4e76aa49be8c3 upstream.
fclog.c does not compile because it is missing fcntl.h, needed for O_RDONLY etc.
There are also some redundant includes that are also in kselftest_harness.h.
--- tools/testing/selftests/filesystems/fclog.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
tools/testing/selftests/filesystems/fclog.c +1 -3
@@ -6,10 +6,8 @@#include <assert.h> #include <errno.h> +#include <fcntl.h> #include <sched.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <unistd.h> #include <sys/mount.h>
Greg Kroah-Hartman
maintainerPATCH 218/438 fs/proc/task_mmu: fix PAGEMAP_SCAN written state for unpopulated ptes
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiryl Shutsemau (Meta) <[email protected]>
commit 07b4377bdbe74a3ec0c8da5849d014f70e003384 upstream.
PAGEMAP_SCAN reports an unpopulated pte differently depending on which path serves the request. The PAGE_IS_WRITTEN fast path in pagemap_scan_pmd_entry() reports a pte_none as written (and, under PM_SCAN_WP_MATCHING, arms a marker); pagemap_page_category() returns 0 for the same pte_none. A request that cannot take the fast path (an extra category bit, category_anyof_mask or category_inverted) therefore reports the pte as clean and skips arming it.
A range that was populated and then MADV_DONTNEED'd reads as written via one mask and clean via another, and in the latter case is not re-armed for the next round -- an incremental-dump consumer (e.g. CRIU) using a richer mask drops the zapped range and stops tracking writes to it.
Report pte_none as written in pagemap_page_category() too. A pte_none carries no uffd-wp marker, i.e. it is not write-protected -- the same condition under which the present and swap cases already report PAGE_IS_WRITTEN. The fast path applies no VMA test, so neither does this.
The hugetlb and fully-unpopulated-PMD (no page table) scans have no PAGE_IS_WRITTEN fast path, so they do not exhibit the per-entry divergence and are left unchanged.
Add a pagemap_ioctl selftest that populates a range, drops it with MADV_DONTNEED, and checks that the fast path and the generic (category_anyof_mask) path both report every page written.
--- fs/proc/task_mmu.c | 14 ++++++- tools/testing/selftests/mm/pagemap_ioctl.c | 56 ++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-)
fs/proc/task_mmu.c +12 -2
@@ -2345,8 +2345,18 @@ static unsigned long pagemap_page_catego {unsigned long categories; -if (pte_none (pte)) -return 0 ; +if (pte_none (pte)) { +/* +* An unpopulated pte carries no uffd-wp marker, i.e. it is not +* write-protected, the same condition under which the present +* and swap cases below report PAGE_IS_WRITTEN. Report it here +* too so this generic path agrees with the PAGE_IS_WRITTEN fast +* path in pagemap_scan_pmd_entry(), which reports pte_none as +* written and, under PM_SCAN_WP_MATCHING, arms a marker. The +* fast path applies no VMA test, so neither does this. +*/ +return PAGE_IS_WRITTEN ; + }if (pte_present (pte)) {struct page *page;
tools/testing/selftests/mm/pagemap_ioctl.c +55 -1
74 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 219/438 fs/proc/task_mmu: fix PAGEMAP_SCAN written state for PMD holes
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiryl Shutsemau (Meta) <[email protected]>
commit 40de8160ca7f67d14619ee0351ce5d68fc4a237a upstream.
PAGEMAP_SCAN reports an unpopulated PTE in a uffd-wp VMA as written, but a range with no page table at all -- a PMD hole -- is skipped:pagemap_scan_pte_hole() tests p->cur_vma_category, which never carries PAGE_IS_WRITTEN, so the hole is neither reported nor (under PM_SCAN_WP_MATCHING) armed.
In a uffd-wp VMA, WP_UNPOPULATED installs uffd-wp markers when protecting a range, allocating page tables as needed, so an unpopulated slot is treated as written -- see the pte_none() handling in pagemap_page_category(). A missing marker therefore means the range was zapped, e.g. via MADV_DONTNEED. This applies to anon and shmem VMAs.
An anonymous THP is write-protected in place as a huge PMD, so a full-PMD MADV_DONTNEED clears it to pmd_none -- a hole with no page table -- and pagemap_scan_pte_hole() misses it. For a MAP_PRIVATE|MAP_ANON mapping MADV_DONTNEED has fill-with-zeros semantics, so a write-tracking checkpoint/migration tool (e.g. CRIU) treats the range as unchanged and keeps its previous contents; after restore or live migration the process reads stale data instead of zeroes -- data corruption.
Report a hole in a non-hugetlb uffd-wp VMA as written, matching the pte_none handling in pagemap_page_category(); the existing PM_SCAN_WP_MATCHING path then arms it via uffd_wp_range().
hugetlb is excluded: pagemap_hugetlb_category() reports an empty hugetlb entry (huge_pte_none) as not-written, unlike pagemap_page_category(), which reports pte_none as written. pagemap_scan_pte_hole() fires for a hugetlb slot only when it has no page table; keeping that not-written matches how an allocated-but-empty hugetlb entry reads, so the hole and the empty-entry cases agree within the VMA.
--- fs/proc/task_mmu.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
fs/proc/task_mmu.c +18 -2
@@ -2962,12 +2962,28 @@ static int pagemap_scan_pte_hole(unsigne {struct pagemap_scan_private *p = walk->private;struct vm_area_struct *vma = walk->vma; +unsigned long categories;int ret, err; -if (!vma || !pagemap_scan_is_interesting_page (p->cur_vma_category, p)) +if (!vma)return 0 ; - ret =pagemap_scan_output (p->cur_vma_category, p, addr, &end); +/* +* In a uffd-wp VMA an unpopulated range is treated as written: +* uffd-wp registration populates page tables and installs markers +* with WP_UNPOPULATED, so a missing marker means the range was +* zapped. See the pte_none() handling in pagemap_page_category(). +* +* hugetlb differs, see pagemap_hugetlb_category(). +*/ + categories = p->cur_vma_category; +if (userfaultfd_wp (vma) && !is_vm_hugetlb_page (vma)) + categories |=PAGE_IS_WRITTEN ; + +if (!pagemap_scan_is_interesting_page (categories, p)) +return 0 ; + + ret =pagemap_scan_output (categories, p, addr, &end);if (addr == end)return ret;
Greg Kroah-Hartman
maintainerPATCH 220/438 mm/percpu-km: fix bitmap overflow and accounting in pcpu_create_chunk()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zi Yan <[email protected]>
commit 89b1b79c308818a715e75f28744b70d8940a07c9 upstream.
In pcpu_create_chunk(), nr_pages is the total contiguous backing allocation, i.e., nr_units * pcpu_unit_pages, but pcpu_chunk_populated() uses it to set chunk->populated, whose size is pcpu_unit_pages, bitmap. Since bit N in chunk->populated means page offset N inside every unit is backed. When nr_units > 1, the function writes beyond chunk->populated. Fix it by using chunk->nr_pages.
It also fixes the global pcpu_nr_empty_pop_pages accounting, since pcpu_balance_free() only iterates up to chunk->nr_pages.
Commit a63d4ac4ab609 ("percpu: make percpu-km set chunk->populated bitmap properly") introduced the bitmap overflow issue. Later, commit b539b87fed37f ("percpu: implmeent pcpu_nr_empty_pop_pages and chunk->nr_populated") added pcpu_nr_empty_pop_pages and caused the accounting issue.
--- mm/percpu-km.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/percpu-km.c +1 -1
@@ -75,7 +75,7 @@ static struct pcpu_chunk *pcpu_create_ch chunk->base_addr =page_address (pages);spin_lock_irqsave (&pcpu_lock, flags); -pcpu_chunk_populated (chunk,0 , nr_pages); +pcpu_chunk_populated (chunk,0 , chunk->nr_pages);spin_unlock_irqrestore (&pcpu_lock, flags);pcpu_stats_chunk_alloc ();
Greg Kroah-Hartman
maintainerPATCH 221/438 mm/hugetlb: fix list corruption in allocate_file_region_entries()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiangfeng Cai <[email protected]>
commit dd9623f58ec702a07b2d67179d6fcea79c52231a upstream.
allocate_file_region_entries() tops up resv->region_cache with freshly allocated file_region descriptors. The allocation uses GFP_KERNEL, so resv->lock is dropped around it: the new entries are gathered on a stack-local list head, allocated_regions, and spliced into resv->region_cache once the lock is re-acquired.
The splice used list_splice(), which moves the entries but does not re-initialize the source head, so allocated_regions is left pointing at an entry that now lives on resv->region_cache. The top-up runs in a while loop that re-checks the cache deficit after re-acquiring the lock. For a shared mapping the resv_map is shared by every mapper of the hugetlbfs inode, so a concurrent region_chg()/region_add()/region_del() on the same resv_map can consume cache entries during the unlocked window and force a second iteration. That iteration calls list_add() on the stale head and corrupts the list; with CONFIG_DEBUG_LIST the __list_add_valid() check trips:
list_add corruption. next->prev should be prev (ffffc900011ff7f8), but was ffff88814c281460. (next=ffff88814c545640). kernel BUG at lib/list_debug.c:31!
allocate_file_region_entries+0x191/0x420 region_chg+0x267/0x300 hugetlb_reserve_pages+0x387/0xc80 hugetlbfs_file_mmap+0x2ce/0x3f0 mmap_region+0x1348/0x1a80 do_mmap+0x85e/0xb90 vm_mmap_pgoff+0x18c/0x330 ksys_mmap_pgoff+0x2a1/0x3e0 do_syscall_64+0xd7/0x420
Without CONFIG_DEBUG_LIST the bad list_add() silently links a kernel-stack address into resv->region_cache, leading to later use-after-free.
This was observed as a real host panic on a dense KVM host where a QEMU guest-RAM hugetlbfs file was mapped MAP_SHARED by both QEMU and a separate SPDK/DPDK vhost-user target, generating concurrent region_* traffic on one shared resv_map.
Use list_splice_init() so the source head is re-initialized empty after each splice, making the retry loop safe.
--- mm/hugetlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/hugetlb.c +1 -1
@@ -693,7 +693,7 @@ static int allocate_file_region_entries(spin_lock (&resv->lock); -list_splice (&allocated_regions, &resv->region_cache); +list_splice_init (&allocated_regions, &resv->region_cache); resv->region_cache_count += to_allocate; }
Greg Kroah-Hartman
maintainerPATCH 222/438 userfaultfd: wait on source PMD during UFFDIO_MOVE
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Usama Arif <[email protected]>
commit 4165b7d1c45c2da0dfefe528f8d1fb7d79f0d344 upstream.
move_pages_huge_pmd() snapshots src_pmdval under src_ptl, drops the lock, and, for migration entries, waits with pmd_migration_entry_wait().
Passing &src_pmdval is wrong. pmd_migration_entry_wait() must lock and re-read the real page-table PMD; on split-PMD-lock kernels, a stack address also resolves to the wrong lock. softleaf_entry_wait_on_locked() then waits without a folio reference, which is safe only while serialized against migration-entry removal by the real PT lock.
Pass src_pmd, matching __handle_mm_fault() and hmm_vma_walk_pmd().
--- mm/huge_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/huge_memory.c +1 -1
@@ -2836,7 +2836,7 @@ int move_pages_huge_pmd(struct mm_structif (!pmd_trans_huge (src_pmdval)) {spin_unlock (src_ptl);if (pmd_is_migration_entry (src_pmdval)) { -pmd_migration_entry_wait (mm, &src_pmdval); +pmd_migration_entry_wait (mm, src_pmd);return -EAGAIN ; }return -ENOENT ;
Greg Kroah-Hartman
maintainerPATCH 223/438 mm/vmstat: fold stranded per-cpu node stats when a node comes online
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gregory Price <[email protected]>
commit ea3034b2b00fa50c8d2518d0804c9d427bbafa86 upstream.
A per-node vmstat counter is pgdat->vm_stat[] plus per-cpu deltas. A balanced counter can sit split as global=+N / per-cpu=-N.
The folds reconciling the split only walk online nodes, so when try_offline_node() marks a node offline the per-cpu deltas are stranded.
A subsequent online resets the per-cpu area but not pgdat->vm_stat[], orphaning the +N permanently. All NR_VM_NODE_STAT_ITEMS are affected.
The existing code zeroes the per-cpu counters and causes a permanent skew. Fold the stranded deltas instead, before the node rejoins the online set. The node is not online yet and the hotplug lock is held, so the remote access to per-cpu values is safe.
Discovered when node compaction hung for a nearly empty node, as the math to determine throttling broke. Reproduced by repeated memory hotplug/unplug cycles on a node under pressure: NR_ISOLATED_ANON ratchets up and never returns to zero.
--- mm/mm_init.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
mm/mm_init.c +11 -4
@@ -1548,7 +1548,7 @@ void __ref free_area_init_core_hotplug(s {int nid = pgdat->node_id;enum zone_type z; -int cpu; +int cpu, i;pgdat_init_internals (pgdat);
@@ -1566,10 +1566,17 @@ void __ref free_area_init_core_hotplug(s pgdat->node_start_pfn =0 ; pgdat->node_present_pages =0 ; -for_each_online_cpu (cpu) { -struct per_cpu_nodestat *p; +/* +* Hot-unplug can leave per-cpu vmstat deltas unfolded (folders skip +* offline nodes) - reconcile this at online. Foreign access to counters +* is safe: the node is not online yet and we hold the hotplug lock. +*/ +for_each_possible_cpu (cpu) { +struct per_cpu_nodestat *p =per_cpu_ptr (pgdat->per_cpu_nodestats, cpu); - p =per_cpu_ptr (pgdat->per_cpu_nodestats, cpu); +for (i =0 ; i <NR_VM_NODE_STAT_ITEMS ; i++) +if (p->vm_node_stat_diff[i]) +node_page_state_add (p->vm_node_stat_diff[i], pgdat, i);memset (p,0 ,sizeof (*p)); }
Greg Kroah-Hartman
maintainerPATCH 224/438 KVM: x86: Cancel delayed I/O APIC EOI handling before destroying vCPUs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit 9910e835580fef3bef53b70241dd00c4bffad693 upstream.
Cancel (and flush) the I/O APIC's delayed EOI handling work during the "pre VM destroy" phase, before vCPUs are destroyed, as processing the EOI broadcast will inject another IRQ if the line is asserted, i.e. will try to deliver an IRQ to the target vCPU(s). Canceling the work after vCPUs are destroyed leads to UAF if the delayed work is processed after vCPUs are destroyed.
BUG: KASAN: slab-use-after-free in __kvm_irq_delivery_to_apic_fast+0x9bf/0xa20 arch/x86/kvm/lapic.c:1250 Read of size 8 at addr ffff8880499abea0 by task kworker/1:2/1218 CPU: 1 UID: 0 PID: 1218 Comm: kworker/1:2 Not tainted 7.1.0-rc7 #5 PREEMPT(lazy) Hardware name: QEMU Ubuntu 25.10 PC v2 (i440FX + PIIX, + 10.1 machine, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: events kvm_ioapic_eoi_inject_work Call Trace: <TASK> __dump_stack lib/dump_stack.c:94 dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 print_report+0x139/0x4ad mm/kasan/report.c:482 kasan_report+0xe4/0x1d0 mm/kasan/report.c:595 __kvm_irq_delivery_to_apic_fast+0x9bf/0xa20 arch/x86/kvm/lapic.c:1250 __kvm_irq_delivery_to_apic+0xd8/0xbf0 arch/x86/kvm/lapic.c:1345 kvm_irq_delivery_to_apic arch/x86/kvm/lapic.h:129 ioapic_service+0x308/0x590 arch/x86/kvm/ioapic.c:492 kvm_ioapic_eoi_inject_work+0x13c/0x190 arch/x86/kvm/ioapic.c:532 process_one_work+0xa59/0x19a0 kernel/workqueue.c:3314 process_scheduled_works kernel/workqueue.c:3397 worker_thread+0x5eb/0xe50 kernel/workqueue.c:3478 kthread+0x370/0x450 kernel/kthread.c:436 ret_from_fork+0x72b/0xd30 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 </TASK>
Note, the VM is unreachable once kvm_destroy_vm() starts, and scheduling new work via kvm_ioapic_send_eoi() can only be done via KVM_RUN, i.e. requires a live vCPU.
Alternatively, KVM could simply destroy the I/O APIC during the "pre" phase of VM destruction, but that gets more than a bit sketchy as KVM expects the I/O APIC to exist if ioapic_in_kernel() is true, and nested virtualization in particular has a bad habit of touching VM-scope state during vCPU destruction. E.g. attempting to free the PIC during the pre phase would lead to a NULL pointer dereference in kvm_cpu_has_extint(), and it's not hard to imagine the I/O APIC having a similar flaw.
Message-ID: <[email protected]>
--- arch/x86/kvm/x86.c | 6 ++++++ 1 file changed, 6 insertions(+)
arch/x86/kvm/x86.c +6 -0
@@ -13460,9 +13460,15 @@ void kvm_arch_pre_destroy_vm(struct kvm* iterating over vCPUs in a different task while vCPUs are being freed * is unsafe, i.e. will lead to use-after-free. The PIT also needs to * be stopped before IRQ routing is freed. +* +* Do NOT free the in-kernel PIC or I/O APIC here (but as above, make +* sure to flush any background work), as KVM expects interrupt routing +* structures to be valid until vCPUs are destroyed. */ #ifdef CONFIG_KVM_IOAPIC kvm_free_pit (kvm); +if (kvm->arch.vioapic) +cancel_delayed_work_sync (&kvm->arch.vioapic->eoi_inject);#endif kvm_mmu_pre_destroy_vm (kvm);
Greg Kroah-Hartman
maintainerPATCH 225/438 tracing/probes: Reject $arg0 in meta argument expansion
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raushan Patel <[email protected]>
commit 00a8ce2a2a9fa17674e1feec4d9105c1a5d6a419 upstream.
traceprobe_expand_meta_args() parses $argN with simple_strtoul() and calls sprint_nth_btf_arg(n - 1, ...). For $arg0, n is 0 so the index is -1. Because ctx->nr_params is signed, the "idx >= nr_params" guard in sprint_nth_btf_arg() does not catch the negative index, and ctx->params[-1].name_off is read out of bounds.
The normal per-argument path (parse_probe_vars()) already rejects $arg0 via its argument-number check, but meta-argument expansion runs before per-argument parsing and substitutes the value first, bypassing that check.
Reject $arg0 explicitly during expansion.
--- kernel/trace/trace_probe.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/trace/trace_probe.c +5 -1
@@ -1906,7 +1906,11 @@ const char **traceprobe_expand_meta_argstrace_probe_log_err (0 ,BAD_VAR );return ERR_PTR (-ENOENT ); } -/* Note: $argN starts from $arg1 */ +/* Note: $argN starts from $arg1, so $arg0 is invalid. */ +if (n ==0 ) { +trace_probe_log_err (0 ,BAD_ARG_NUM ); +return ERR_PTR (-EINVAL ); + } ret =sprint_nth_btf_arg (n -1 , type, buf + used, bufsize - used, ctx);if (ret <0 )
Greg Kroah-Hartman
maintainerPATCH 226/438 tracing/fprobe: Roll back on enable_trace_fprobe() failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raushan Patel <[email protected]>
commit aca0cd1bf16574327ef64f3178e5f5e37a61ef0b upstream.
enable_trace_fprobe() sets the file link or the TP_FLAG_PROFILE flag and then registers each trace_fprobe in the probe list. If __register_trace_fprobe() fails partway through, the function returns immediately without unregistering the trace_fprobes it already registered or undoing the file link / flag it set, leaving the event half-enabled and leaking the registered fprobe(s).
enable_trace_kprobe() already handles this with a rollback path. Do the same for fprobe: on failure, unregister all probes and clear the file link or profile flag.
--- kernel/trace/trace_fprobe.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
kernel/trace/trace_fprobe.c +11 -1
@@ -1481,11 +1481,21 @@ static int enable_trace_fprobe(struct trlist_for_each_entry (tf,trace_probe_probe_list (tp), tp.list) { ret =__register_trace_fprobe (tf);if (ret <0 ) -return ret; + goto err; } }return 0 ; + +err: +/* Failed to enable one of them. Roll back all */ +list_for_each_entry (tf,trace_probe_probe_list (tp), tp.list) +__unregister_trace_fprobe (tf); +if (file) +trace_probe_remove_file (tp, file); +else +trace_probe_clear_flag (tp,TP_FLAG_PROFILE ); +return ret; }/*
Greg Kroah-Hartman
maintainerPATCH 227/438 KVM: VMX: add memory clobber to asm for VMX instructions
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Bonzini <[email protected]>
commit 0e65cd9e5d41c34f86b7c347967bedac54926041 upstream.
VMCLEAR/VMREAD/VMWRITE/VMPTRLD access the internal VMCS cache, which is not visible to the compiler; without a memory clobber, the compiler can reorder them in troublesome ways because "asm volatile" and "asm goto" only protect against removal of the asm. For example, placing a VMWRITE before the corresponding VMCS pointer is loaded can lead to corruption. While none of this has been observed, it is better to prevent than cure.
Likewise, INVEPT and INVVPID access the TLB and, even though in their case the effect is only visible to the next VMLAUNCH/VMRESUME, it is technically correct to add the clobber there too. So avoid any urge to special case them, and simply hardcode "memory" into the clobber list of vmx_asm1() and vmx_asm2(). __vmcs_readl() open-codes its own asm, so add the clobber there as well.
--- arch/x86/kvm/vmx/vmx_ops.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/kvm/vmx/vmx_ops.h +4 -4
@@ -101,7 +101,7 @@ static __always_inline unsigned long __v : [output] "=r" (value) : [field] "r" (field) - : "cc" + : "cc", "memory" : do_fail, do_exception);return value;
@@ -145,7 +145,7 @@ do_exception: : ASM_CALL_CONSTRAINT, [output] "=&r" (value) : [field] "r" (field) - : "cc"); + : "cc", "memory");return value;#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
@@ -192,7 +192,7 @@ do { \ asm goto("1: " __stringify(insn) " %0\n\t" \ "jna %l[error]\n\t" \ _ASM_EXTABLE(1b, %l[fault]) \ - : : op1 : "cc" : error, fault); \ + : : op1 : "cc", "memory" : error, fault); \return ; \ error: \instrumentation_begin (); \
@@ -208,7 +208,7 @@ do { \ asm goto("1: " __stringify(insn) " %1, %0\n\t" \ "jna %l[error]\n\t" \ _ASM_EXTABLE(1b, %l[fault]) \ - : : op1, op2 : "cc" : error, fault); \ + : : op1, op2 : "cc", "memory" : error, fault);\return; \ error: \ instrumentation_begin(); \
Greg Kroah-Hartman
maintainerPATCH 228/438 KVM: SVM: Update x2APIC MSR intercepts if AVIC is inhibited while L2 is active
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 7d3aae206663c4e006b25a1c7a20a4029e67da76 upstream.
Always update x2APIC MSR intercepts for L1 when AVIC is deactivated, even if L2 is active and KVM is using a separate MSR bitmap to run L2. If AVIC is fully enabled prior to running L2, and is then inhibited while L2 is active (for a VM-scoped inhibit), then KVM will run L1 with AVIC disabled, but with x2APIC MSR intercepts disabled, i.e. will allow L1 to read most of the host's APIC state, send arbitrary interrupts, change task priority, and ultimately trivially DoS the host.
E.g. sending a self-IPI in L1 on HYPERV_REENLIGHTENMENT_VECTOR, 0xee, with CONFIG_HYPERV=n in the host kernel as a "safe" PoC, yields:
Spurious interrupt (vector 0xee) on CPU#425. Acked
And hacking KVM to abuse kvm_set_posted_intr_wakeup_handler() to register a handler and WARN on POSTED_INTR_WAKEUP_VECTOR yields:
------------[ cut here ]------------ WARNING: arch/x86/kvm/svm/svm.c:5594 at pi_wakeup_handler+0x9/0x10 [kvm_amd], CPU#156: nested_x2apic_t/316940 CPU: 156 UID: 0 PID: 316940 Comm: nested_x2apic_t Tainted: G S U Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER Hardware name: Google Astoria-Turin/astoria, BIOS 0.20260209.0-0 02/09/2026 RIP: 0010:pi_wakeup_handler+0x9/0x10 [kvm_amd] Call Trace: <IRQ> sysvec_kvm_posted_intr_wakeup_ipi+0x64/0x80 </IRQ> <TASK> asm_sysvec_kvm_posted_intr_wakeup_ipi+0x1a/0x20 RIP: 0010:vcpu_run+0x1430/0x1e40 [kvm] kvm_arch_vcpu_ioctl_run+0x2c1/0x600 [kvm] kvm_vcpu_ioctl+0x580/0x6b0 [kvm] __se_sys_ioctl+0x6d/0xb0 do_syscall_64+0x10a/0x480 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x46ff4b </TASK> ---[ end trace 0000000000000000 ]---
--- arch/x86/kvm/svm/avic.c | 8 -------- 1 file changed, 8 deletions(-)
arch/x86/kvm/svm/avic.c +0 -8
@@ -240,14 +240,6 @@ static void avic_deactivate_vmcb(structif (!is_sev_es_guest (&svm->vcpu))svm_set_intercept (svm,INTERCEPT_CR8_WRITE ); -/* -* If running nested and the guest uses its own MSR bitmap, there -* is no need to update L0's msr bitmap -*/ -if (is_guest_mode (&svm->vcpu) && -vmcb12_is_intercept (&svm->nested.ctl,INTERCEPT_MSR_PROT )) -return ; -/* Enabling MSR intercept for x2APIC registers */ avic_set_x2apic_msr_interception (svm, true); }
Greg Kroah-Hartman
maintainerPATCH 229/438 KVM: s390: pci: Reject adapter interrupt forwarding if already enabled
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit 8fa01be5a6149404adb82c0979a78f6347edd3ef upstream.
The MPCIFC instruction doesn't allow registering adapter interrupts without first unregistering. So reject any request to enable interrupt forwarding if its already enabled for the zPCI device. This also fixes overwriting and thus leaking resources when the ioctl is called multiple times for the same device.
--- arch/s390/kvm/pci.c | 4 ++++ 1 file changed, 4 insertions(+)
arch/s390/kvm/pci.c +4 -0
@@ -237,6 +237,10 @@ static int kvm_s390_pci_aif_enable(strucif (zdev->gisa ==0 )return -EINVAL ; +/* AIF already enabled for the device */ +if (zdev->kzdev->fib.fmt0.aibv !=0 ) +return -EINVAL ; + kvm = zdev->kzdev->kvm; msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
Greg Kroah-Hartman
maintainerPATCH 230/438 KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit 36f6999ecde3976731a8bfc0b8e667da6f593069 upstream.
The account_mem() and unaccount_mem() functions call get_uid() which increments the reference count of struct user_struct on every invocation. But we don't decrement the count by calling free_uid(). It also accounted/unaccounted the pages against the current->mm. But its possible the unaccount_mem() can be called from a different process context than the one that originally pinned the pages.
Let's fix this by storing the pinning process user_struct and mm_struct when accounting for pinned pages, and subsequently free these resources when the pages are unpinned.
--- arch/s390/kvm/pci.c | 43 ++++++++++++++++++++++++++++++++----------- arch/s390/kvm/pci.h | 2 ++ 2 files changed, 34 insertions(+), 11 deletions(-)
arch/s390/kvm/pci.c +32 -11
@@ -190,33 +190,54 @@ static int kvm_zpci_clear_airq(struct zpreturn cc ? -EIO :0 ; } -static inline void unaccount_mem (unsigned long nr_pages) +static inline void unaccount_mem (struct kvm_zdev *kzdev,unsigned long nr_pages) { -struct user_struct *user =get_uid (current_user ()); +struct user_struct *user = kzdev->user_account; +struct mm_struct *mm_account = kzdev->mm_account; -if (user) +if (user) {atomic_long_sub (nr_pages, &user->locked_vm); -if (current->mm) -atomic64_sub (nr_pages, ¤t->mm->pinned_vm); +free_uid (user); + kzdev->user_account =NULL ; + } + +if (mm_account) { +atomic64_sub (nr_pages, &mm_account->pinned_vm); +mmdrop (mm_account); + kzdev->mm_account =NULL ; + } } -static inline int account_mem (unsigned long nr_pages) +static inline int account_mem (struct kvm_zdev *kzdev,unsigned long nr_pages) {struct user_struct *user =get_uid (current_user ());unsigned long page_limit, cur_pages, new_pages; +int rc =0 ; page_limit =rlimit (RLIMIT_MEMLOCK ) >>PAGE_SHIFT ; cur_pages =atomic_long_read (&user->locked_vm);do { new_pages = cur_pages + nr_pages; -if (new_pages > page_limit) -return -ENOMEM ; +if (new_pages > page_limit) { + rc = -ENOMEM ; + goto out; + } }while (!atomic_long_try_cmpxchg (&user->locked_vm, &cur_pages, new_pages)); -atomic64_add (nr_pages, ¤t->mm->pinned_vm); +if (current->mm) { +mmgrab (current->mm); +atomic64_add (nr_pages, ¤t->mm->pinned_vm); + } + + kzdev->user_account = user; + kzdev->mm_account = current->mm;return 0 ; + +out: +free_uid (user); +return rc; } static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
@@ -279,7 +300,7 @@ static int kvm_s390_pci_aif_enable(struc }/* Account for pinned pages, roll back on failure */ -if (account_mem (pcount)) +if (account_mem (zdev->kzdev, pcount)) goto unpin2;/* AISB must be allocated before we can fill in GAITE */
@@ -400,7 +421,7 @@ static int kvm_s390_pci_aif_disable(stru pcount++; }if (pcount >0 ) -unaccount_mem (pcount); +unaccount_mem (kzdev, pcount); out:mutex_unlock (&aift->aift_lock);
arch/s390/kvm/pci.h +2 -0
@@ -22,6 +22,8 @@ struct kvm_zdev {struct kvm *kvm;struct zpci_fib fib;struct list_head entry; +struct user_struct *user_account; +struct mm_struct *mm_account; };struct zpci_gaite {
Greg Kroah-Hartman
maintainerPATCH 231/438 KVM: s390: pci: Fix missing error codes and memory unaccounting
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit f86842e4d6c482300f4567f492d512c9ccf5bc4f upstream.
In kvm_s390_pci_aif_enable() two error paths failed to set an error code, causing the function to return 0 on failure. It also failed to rollback memory accounting on failure. Fix both by propagating an error code on failure and calling unaccount_mem() in the cleanup path.
--- arch/s390/kvm/pci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
arch/s390/kvm/pci.c +7 -2
@@ -300,14 +300,17 @@ static int kvm_s390_pci_aif_enable(struc }/* Account for pinned pages, roll back on failure */ -if (account_mem (zdev->kzdev, pcount)) + rc =account_mem (zdev->kzdev, pcount); +if (rc) goto unpin2;/* AISB must be allocated before we can fill in GAITE */ mutex_lock (&aift->aift_lock); bit =airq_iv_alloc_bit (aift->sbv); -if (bit ==-1UL ) +if (bit ==-1UL ) { + rc = -ENOMEM ; goto unlock; + } zdev->aisb = bit;/* store the summary bit number */ zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK |
@@ -351,6 +354,8 @@ static int kvm_s390_pci_aif_enable(strucreturn rc; unlock: +if (pcount >0 ) +unaccount_mem (zdev->kzdev, pcount);mutex_unlock (&aift->aift_lock); unpin2:if (fib->fmt0.sum ==1 )
Greg Kroah-Hartman
maintainerPATCH 232/438 KVM: s390: pci: Fix resource leak on IRQ registration failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit 5580c9858f1e00f60191eb09c3add359836d60b6 upstream.
Currently if kvm_zpci_set_airq() fails, kvm_s390_pci_aif_enable() returns the error code but doesn't do any resource cleanup thus leaking resources. Fix this by cleaning up all the resources such as the GAITE, AIBV, AISB and unpinning any pinned pages. While at it, remove dead code that stored FIB values that were never referenced.
As part of the cleanup, we are also holding the aift_lock a bit longer, as we hold the lock while executing the MPCIFC instruction. Though this is not strictly necessary, it means we don't have to drop and re-acquire in the error case.
--- arch/s390/kvm/pci.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-)
arch/s390/kvm/pci.c +21 -8
@@ -339,19 +339,32 @@ static int kvm_s390_pci_aif_enable(struc aift->kzdev[zdev->aisb] = zdev->kzdev;spin_unlock_irq (&aift->gait_lock); -/* Update guest FIB for re-issue */ - fib->fmt0.aisbo = zdev->aisb &63 ; - fib->fmt0.aisb =virt_to_phys (aift->sbv->vector) + (zdev->aisb /64 ) *8 ; - fib->fmt0.isc = gisc; -/* Save some guest fib values in the host for later use */ - zdev->kzdev->fib.fmt0.isc = fib->fmt0.isc; + zdev->kzdev->fib.fmt0.isc = gisc; zdev->kzdev->fib.fmt0.aibv = fib->fmt0.aibv; -mutex_unlock (&aift->aift_lock);/* Issue the clp to setup the irq now */ rc =kvm_zpci_set_airq (zdev); -return rc; +if (!rc) { +mutex_unlock (&aift->aift_lock); +return rc; + } + +/* Start cleanup */ + zdev->kzdev->fib.fmt0.isc =0 ; + zdev->kzdev->fib.fmt0.aibv =0 ; + +spin_lock_irq (&aift->gait_lock); + gaite->count--; + gaite->aisb =0 ; + gaite->gisc =0 ; + gaite->aisbo =0 ; + gaite->gisa =0 ; + aift->kzdev[zdev->aisb] =NULL ; +spin_unlock_irq (&aift->gait_lock); + +airq_iv_release (zdev->aibv); + zdev->aibv =NULL ; unlock:if (pcount >0 )
Greg Kroah-Hartman
maintainerPATCH 233/438 KVM: s390: pci: Fix NULL dereference on AIBV allocation failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit 8bf09b9b7d3232806df95f409581f8a9fd99a3fa upstream.
The airq_iv_create() can return NULL on failure, but the return value was never checked. If it fails, zdev->aibv will be NULL and fail when dereferenced in kvm_zpci_set_airq(). Add a NULL check and free the previously allocated AISB bit and zdev->aisb on failure.
--- arch/s390/kvm/pci.c | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/s390/kvm/pci.c +8 -0
@@ -317,6 +317,11 @@ static int kvm_s390_pci_aif_enable(strucAIRQ_IV_GUESTVEC , phys_to_virt(fib->fmt0.aibv)); +if (!zdev->aibv) { + rc = -ENOMEM ; + goto free_aisb; + } +spin_lock_irq (&aift->gait_lock); gaite = aift->gait + zdev->aisb;
@@ -366,6 +371,9 @@ static int kvm_s390_pci_aif_enable(strucairq_iv_release (zdev->aibv); zdev->aibv =NULL ; +free_aisb: +airq_iv_free_bit (aift->sbv, zdev->aisb); + zdev->aisb =0 ; unlock:if (pcount >0 )unaccount_mem (zdev->kzdev, pcount);
Greg Kroah-Hartman
maintainerPATCH 234/438 KVM: s390: pci: Validate AIBV and AISB before pinning guest pages
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit 868d32ac72cba21c5c6d8a66a814b7c25a3a5c01 upstream.
The AIBV holds one bit per MSI-X vector for a given function. The size of the bit vector is derived from the NOI and the AIBVO. If the size of the AIBV exceeds a single page boundary, then reject the request as we cannot safely pin the guest AIBV.
Similarly reject the request if the AISB address is not 8-byte aligned as the architecture requires doubleword alignment for the summary bit address. Since the AISBO can address up to 64 bits, the size of the AISB can only be 8 bytes for the function. This also ensures the AISB doesn't exceed a single page boundary.
--- arch/s390/kvm/pci.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
arch/s390/kvm/pci.c +15 -1
@@ -244,7 +244,7 @@ static int kvm_s390_pci_aif_enable(struc bool assist) {struct page *pages[1 ], *aibv_page, *aisb_page =NULL ; -unsigned int msi_vecs, idx; +unsigned int msi_vecs, idx, size;struct zpci_gaite *gaite;unsigned long hva, bit;struct kvm *kvm;
@@ -271,6 +271,14 @@ static int kvm_s390_pci_aif_enable(strucreturn gisc;/* Replace AIBV address */ + size =BITS_TO_LONGS (msi_vecs + fib->fmt0.aibvo) *sizeof (unsigned long ); + npages =DIV_ROUND_UP ((fib->fmt0.aibv & ~PAGE_MASK ) + size,PAGE_SIZE ); +/* AIBV cannot span more than 1 page */ +if (npages >1 ) { + rc = -EINVAL ; + goto out; + } + idx =srcu_read_lock (&kvm->srcu); hva =gfn_to_hva (kvm,gpa_to_gfn ((gpa_t )fib->fmt0.aibv)); npages =pin_user_pages_fast (hva,1 ,FOLL_WRITE |FOLL_LONGTERM , pages);
@@ -286,6 +294,12 @@ static int kvm_s390_pci_aif_enable(struc/* Pin the guest AISB if one was specified */ if (fib->fmt0.sum ==1 ) { +/* AISB must be dword aligned */ +if (fib->fmt0.aisb &0x7 ) { + rc = -EINVAL ; + goto unpin1; + } + idx =srcu_read_lock (&kvm->srcu); hva =gfn_to_hva (kvm,gpa_to_gfn ((gpa_t )fib->fmt0.aisb)); npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM,
Greg Kroah-Hartman
maintainerPATCH 235/438 dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <[email protected]>
commit a10ea943356b9d70c5616a0a06f6fa97cfdaccb1 upstream.
dibs_lo_attach_dmb(), dibs_lo_detach_dmb() and dibs_lo_unregister_dmb() look up the dmb_node under dmb_ht_lock, drop the lock and only then operate on the node's refcount. Nothing keeps the node alive across that window: __dibs_lo_unregister_dmb() removes the node from the hash table under the write lock and immediately frees it.
A concurrent final put can therefore free the node between the lookup and the refcount operation:
CPU0 (attach) CPU1 (owner unregisters)
read_lock_bh(&dmb_ht_lock)
find dmb_node (refcnt == 1)read_unlock_bh(&dmb_ht_lock)
refcount_dec_and_test() 1 -> 0
write_lock_bh(&dmb_ht_lock)
hash_del(&dmb_node->list)
write_unlock_bh(&dmb_ht_lock)
kfree(dmb_node)refcount_inc_not_zero(&dmb_node->refcnt) <-- use-after-free
The same window exists for the refcount_dec_and_test() calls in the detach and unregister paths.
Close the race structurally by making hash table membership and the refcount transitions atomic with respect to each other:
- Perform the final refcount_dec_and_test() and hash_del() in a single dmb_ht_lock write-side critical section, in both the unregister and the detach path. Freeing the node still happens after the lock is dropped, which is safe because a node whose refcount reached zero has left the hash table and can no longer be found.
- This establishes the invariant that any node found in the hash table holds at least one reference, and that the final reference can only be dropped under the write lock. dibs_lo_attach_dmb() can thus take its reference with a plain refcount_inc() while still holding the read lock; refcount_inc_not_zero() is no longer needed.
__dibs_lo_unregister_dmb() no longer touches the hash table and is renamed to dibs_lo_free_dmb() accordingly.
Note: commit cc21191b584c ("dibs: Move data path to dibs layer") moved the code to its current location; the race was introduced earlier by commit c3a910f2380f ("net/smc: implement DMB-merged operations of loopback-ism").
Tested SMC-D via ISM and dibs loopback.
--- drivers/dibs/dibs_loopback.c | 47 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 23 deletions(-)
drivers/dibs/dibs_loopback.c +24 -23
@@ -118,14 +118,9 @@ err_bit:return rc; } -static void __dibs_lo_unregister_dmb (struct dibs_lo_dev *ldev, -struct dibs_lo_dmb_node *dmb_node) +static void dibs_lo_free_dmb (struct dibs_lo_dev *ldev, +struct dibs_lo_dmb_node *dmb_node) { -/* remove dmb from hash table */ -write_lock_bh (&ldev->dmb_ht_lock); -hash_del (&dmb_node->list); -write_unlock_bh (&ldev->dmb_ht_lock); -clear_bit (dmb_node->sba_idx, ldev->sba_idx_mask);folio_put (virt_to_folio (dmb_node->cpu_addr));kfree (dmb_node);
@@ -139,27 +134,33 @@ static int dibs_lo_unregister_dmb(structstruct dibs_lo_dmb_node *dmb_node =NULL , *tmp_node;struct dibs_lo_dev *ldev;unsigned long flags; +bool last; ldev = dibs->drv_priv;/* find dmb from hash table */ -read_lock_bh (&ldev->dmb_ht_lock); +write_lock_bh (&ldev->dmb_ht_lock);hash_for_each_possible (ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {if (tmp_node->token == dmb->dmb_tok) { dmb_node = tmp_node;break ; } } -read_unlock_bh (&ldev->dmb_ht_lock); -if (!dmb_node) +if (!dmb_node) { +write_unlock_bh (&ldev->dmb_ht_lock);return -EINVAL ; + } + last =refcount_dec_and_test (&dmb_node->refcnt); +if (last) +hash_del (&dmb_node->list); +write_unlock_bh (&ldev->dmb_ht_lock); -if (refcount_dec_and_test (&dmb_node->refcnt)) { +if (last) {spin_lock_irqsave (&dibs->lock, flags); dibs->dmb_clientid_arr[dmb_node->sba_idx] =NO_DIBS_CLIENT ;spin_unlock_irqrestore (&dibs->lock, flags); -__dibs_lo_unregister_dmb (ldev, dmb_node); +dibs_lo_free_dmb (ldev, dmb_node); }return 0 ; }
@@ -188,14 +189,9 @@ static int dibs_lo_attach_dmb(struct dibread_unlock_bh (&ldev->dmb_ht_lock);return -EINVAL ; } +refcount_inc (&dmb_node->refcnt);read_unlock_bh (&ldev->dmb_ht_lock); -if (!refcount_inc_not_zero (&dmb_node->refcnt)) -/* the dmb is being unregistered, but has -* not been removed from the hash table. -*/ -return -EINVAL ; -/* provide dmb information */ dmb->idx = dmb_node->sba_idx; dmb->dmb_tok = dmb_node->token;
@@ -209,11 +205,12 @@ static int dibs_lo_detach_dmb(struct dib {struct dibs_lo_dmb_node *dmb_node =NULL , *tmp_node;struct dibs_lo_dev *ldev; +bool last; ldev = dibs->drv_priv;/* find dmb_node according to dmb->dmb_tok */ -read_lock_bh (&ldev->dmb_ht_lock); +write_lock_bh (&ldev->dmb_ht_lock);hash_for_each_possible (ldev->dmb_ht, tmp_node, list, token) {if (tmp_node->token == token) { dmb_node = tmp_node;
@@ -221,13 +218,17 @@ static int dibs_lo_detach_dmb(struct dib } }if (!dmb_node) { -read_unlock_bh (&ldev->dmb_ht_lock); +write_unlock_bh (&ldev->dmb_ht_lock);return -EINVAL ; } -read_unlock_bh (&ldev->dmb_ht_lock); + last =refcount_dec_and_test (&dmb_node->refcnt); +if (last) +hash_del (&dmb_node->list); +write_unlock_bh (&ldev->dmb_ht_lock); + +if (last) +dibs_lo_free_dmb (ldev, dmb_node); -if (refcount_dec_and_test (&dmb_node->refcnt)) -__dibs_lo_unregister_dmb (ldev, dmb_node);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 236/438 sctp: validate Adaptation Indication parameter length
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Charles Vosburgh <[email protected]>
commit 74b21f52c5c5a71a05c0ff70e513f4f04ff28b17 upstream.
The Adaptation Layer Indication parameter contains a fixed 32-bit Adaptation Code Point after its parameter header. However, sctp_verify_param() accepts a header-only parameter because the generic parameter walker only requires the header to be present.
sctp_process_param() then reads adaptation_ind beyond the declared parameter. When the malformed parameter is last in an INIT, the read starts at the receive skb tail, and the value is copied into the state cookie returned in the INIT ACK. This may disclose four receive-buffer tail bytes.
Require the declared parameter length to match the fixed structure size and abort the association through the existing invalid parameter length path otherwise.
--- net/sctp/sm_make_chunk.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/sctp/sm_make_chunk.c +6 -0
@@ -2168,7 +2168,13 @@ static enum sctp_ierror sctp_verify_paracase SCTP_PARAM_HEARTBEAT_INFO :case SCTP_PARAM_UNRECOGNIZED_PARAMETERS :case SCTP_PARAM_ECN_CAPABLE : +break ;case SCTP_PARAM_ADAPTATION_LAYER_IND : +if (ntohs (param.p->length) !=sizeof (*param.aind)) { +sctp_process_inv_paramlength (asoc, param.p, + chunk, err_chunk); + retval =SCTP_IERROR_ABORT ; + }break ;case SCTP_PARAM_SUPPORTED_EXT :
Greg Kroah-Hartman
maintainerPATCH 237/438 audit: fix potential integer overflow in audit_log_n_string()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit f865c143629d4094866a811dba5f329250bad486 upstream.
audit_log_n_string() computes new_len as "slen + 3" (enclosing quotes plus the NUL terminator) and stores it into an int, while slen is a size_t. For a sufficiently large slen the addition can overflow and/or the result be truncated when assigned to the int new_len, so the "new_len > avail" check can be bypassed and the subsequent memcpy(ptr, string, slen) can write past the skb tail.
This is the same class of bug that was fixed for the hex sibling in commit 65dfde57d1e2 ("audit: fix potential integer overflow in audit_log_n_hex()"); both helpers are reached through audit_log_n_untrustedstring() with the same length source.
Make new_len a size_t and use check_add_overflow() to catch the overflow, mirroring the audit_log_n_hex() fix. No functional change for the in-tree callers, which all pass bounded lengths.
--- kernel/audit.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
kernel/audit.c +9 -2
@@ -2120,7 +2120,8 @@ void audit_log_n_hex(struct audit_buffervoid audit_log_n_string (struct audit_buffer *ab,const char *string,size_t slen) { -int avail, new_len; +int avail; +size_t new_len;unsigned char *ptr;struct sk_buff *skb;
@@ -2130,7 +2131,13 @@ void audit_log_n_string(struct audit_bufBUG_ON (!ab->skb); skb = ab->skb; avail =skb_tailroom (skb); - new_len = slen +3 ;/* enclosing quotes + null terminator */ + +/* enclosing quotes + null terminator */ +if (check_add_overflow (slen,3 , &new_len)) { +audit_log_format (ab,"?" ); +return ; + } +if (new_len > avail) { avail =audit_expand (ab, new_len);if (!avail)
Greg Kroah-Hartman
maintainerPATCH 238/438 audit: fix potential use-after-free in audit_del_rule()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luxiao Xu <[email protected]>
commit 246df90b5f1a8a6e6abbd2f058b029558720adec upstream.
audit_del_rule() destroys e->rule.exe via audit_remove_mark_rule() before unlinking the rule from RCU-visible filter lists and waiting for a grace period. Concurrent readers in audit_filter() and audit_filter_rules() still dereference e->rule.exe, while the fsnotify mark can be freed on an independent lifetime path. This creates a use-after-free window during rule deletion.
Fix this by unlinking the rule from the RCU-visible lists and invoking synchronize_rcu() before calling audit_remove_mark_rule() (and other rule removal helpers). This ensures that all existing RCU readers have exited the critical section before any underlying resources are destroyed.
--- kernel/auditfilter.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/auditfilter.c +4 -2
@@ -1045,6 +1045,10 @@ int audit_del_rule(struct audit_entry *e goto out; } +list_del_rcu (&e->list); +list_del (&e->rule.list); +synchronize_rcu (); +if (e->rule.watch)audit_remove_watch_rule (&e->rule);
@@ -1062,8 +1066,6 @@ int audit_del_rule(struct audit_entry *e audit_signals--;#endif -list_del_rcu (&e->list); -list_del (&e->rule.list);call_rcu (&e->rcu, audit_free_rule_rcu); out:
Greg Kroah-Hartman
maintainerPATCH 239/438 Bluetooth: btusb: Fix short read errors in btusb_qca_send_vendor_req()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit cac43d360c928bc0cbbd18809632388265649761 upstream.
If btusb_qca_send_vendor_req() gets a "short" read from a device, it will accidentally treat that as a "real" read and populate the returned value with some unknown and probably totally invalid data.
Fix this logic error up by calling usb_control_msg_recv() which guarantees a "full" read happens, and then simplify the error checking for when btusb_qca_send_vendor_req() is called.
--- drivers/bluetooth/btusb.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-)
drivers/bluetooth/btusb.c +9 -21
@@ -3407,28 +3407,16 @@ static const char *qca_get_fw_subdirectostatic int btusb_qca_send_vendor_req (struct usb_device *udev,u8 request,void *data,u16 size) { -int pipe, err; -u8 *buf; - - buf =kmalloc (size,GFP_KERNEL ); -if (!buf) -return -ENOMEM ; +int err;/* Found some of USB hosts have IOT issues with ours so that we should * not wait until HCI layer is ready. */ - pipe =usb_rcvctrlpipe (udev,0 ); - err =usb_control_msg (udev, pipe, request,USB_TYPE_VENDOR |USB_DIR_IN , -0 ,0 , buf, size,USB_CTRL_GET_TIMEOUT ); -if (err <0 ) { + err =usb_control_msg_recv (udev,0 , request,USB_TYPE_VENDOR |USB_DIR_IN , +0 ,0 , data, size,USB_CTRL_GET_TIMEOUT , +GFP_KERNEL ); +if (err)dev_err (&udev->dev,"Failed to access otp area (%d)" , err); - goto done; - } - -memcpy (data, buf, size); - -done: -kfree (buf);return err; }
@@ -3635,7 +3623,7 @@ static bool btusb_qca_need_patch(structstruct qca_version ver;if (btusb_qca_send_vendor_req (udev,QCA_GET_TARGET_VERSION , &ver, -sizeof (ver)) <0 ) +sizeof (ver)))return false;/* only low ROM versions need patches */ return !(le32_to_cpu (ver.rom_version) & ~0xffffU );
@@ -3653,7 +3641,7 @@ static int btusb_setup_qca(struct hci_de err =btusb_qca_send_vendor_req (udev,QCA_GET_TARGET_VERSION , &ver,sizeof (ver)); -if (err <0 ) +if (err)return err; ver_rom =le32_to_cpu (ver.rom_version);
@@ -3676,7 +3664,7 @@ static int btusb_setup_qca(struct hci_de err =btusb_qca_send_vendor_req (udev,QCA_CHECK_STATUS , &status,sizeof (status)); -if (err <0 ) +if (err)return err;if (!(status &QCA_PATCH_UPDATED )) {
@@ -3687,7 +3675,7 @@ static int btusb_setup_qca(struct hci_de err =btusb_qca_send_vendor_req (udev,QCA_GET_TARGET_VERSION , &ver,sizeof (ver)); -if (err <0 ) +if (err)return err; btdata->qca_dump.fw_version =le32_to_cpu (ver.patch_version);
Greg Kroah-Hartman
maintainerPATCH 240/438 Bluetooth: btmtk: Fix short read errors in btmtk_usb_uhw_reg_read()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit b186c18c4843dd58adc29443369bddc71cb626a3 upstream.
If btmtk_usb_uhw_reg_read() gets a "short" read from a device, it will accidentally treat that as a "real" read and populate the returned value with some unknown and probably totally invalid data.
Fix this logic error up by calling usb_control_msg_recv() which guarantees a "full" read happens, and then simplify the error checking for when btmtk_usb_uhw_reg_read() is called.
Note, one caller of btmtk_usb_uhw_reg_read() does not check the return value, but as we pre-initialize the return value as 0, an incorrect read will not do anything wrong.
--- drivers/bluetooth/btmtk.c | 50 ++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 28 deletions(-)
drivers/bluetooth/btmtk.c +22 -28
@@ -804,30 +804,24 @@ static int btmtk_usb_uhw_reg_write(strucstatic int btmtk_usb_uhw_reg_read (struct hci_dev *hdev,u32 reg,u32 *val) {struct btmtk_data *data =hci_get_priv (hdev); -int pipe, err; -void *buf; - - buf =kzalloc (4 ,GFP_KERNEL ); -if (!buf) -return -ENOMEM ; +u8 buf[sizeof (u32)]; +int err; - pipe =usb_rcvctrlpipe (data->udev,0 ); - err =usb_control_msg (data->udev, pipe,0x01 , -0xDE , - reg >>16 , reg &0xffff , - buf,4 ,USB_CTRL_GET_TIMEOUT ); -if (err <0 ) { + *val =0 ; + err =usb_control_msg_recv (data->udev,0 ,0x01 , +0xDE , + reg >>16 , reg &0xffff , + buf,sizeof (buf),USB_CTRL_GET_TIMEOUT , +GFP_KERNEL ); +if (err) {bt_dev_err (hdev,"Failed to read uhw reg(%d)" , err); - goto err_free_buf; +return err; } *val =get_unaligned_le32 (buf);bt_dev_dbg (hdev,"reg=%x, value=0x%08x" , reg, *val); -err_free_buf: -kfree (buf); - -return err; +return 0 ; }static int btmtk_usb_reg_read (struct hci_dev *hdev,u32 reg,u32 *val)
@@ -877,7 +871,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (dev_id ==0x7922 ) { err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_SUBSYS_RST , &val); -if (err <0 ) +if (err)return err; val |=0x00002020 ; err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_SUBSYS_RST , val);
@@ -887,7 +881,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_SUBSYS_RST , &val); -if (err <0 ) +if (err)return err; val |=BIT (0 ); err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_SUBSYS_RST , val);
@@ -896,14 +890,14 @@ int btmtk_usb_subsys_reset(struct hci_demsleep (100 ); }else if (dev_id ==0x7925 || dev_id ==0x6639 ) { err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_RESET_REG_CONNV3 , &val); -if (err <0 ) +if (err)return err; val |= (1 <<5 ); err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_RESET_REG_CONNV3 , val);if (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_RESET_REG_CONNV3 , &val); -if (err <0 ) +if (err)return err; val &=0xFFFF00FF ; val |= (1 <<13 );
@@ -914,7 +908,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_RESET_REG_CONNV3 , &val); -if (err <0 ) +if (err)return err; val |= (1 <<0 ); err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_RESET_REG_CONNV3 , val);
@@ -924,13 +918,13 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_UDMA_INT_STA_BT , &val); -if (err <0 ) +if (err)return err; err =btmtk_usb_uhw_reg_write (hdev,MTK_UDMA_INT_STA_BT1 ,0x000000FF );if (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_UDMA_INT_STA_BT1 , &val); -if (err <0 ) +if (err)return err;msleep (100 ); }else {
@@ -940,7 +934,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_WDT_STATUS , &val); -if (err <0 ) +if (err)return err;/* Reset the bluetooth chip via USB interface. */ err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_SUBSYS_RST ,1 );
@@ -950,13 +944,13 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_UDMA_INT_STA_BT , &val); -if (err <0 ) +if (err)return err; err =btmtk_usb_uhw_reg_write (hdev,MTK_UDMA_INT_STA_BT1 ,0x000000FF );if (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_UDMA_INT_STA_BT1 , &val); -if (err <0 ) +if (err)return err;/* MT7921 need to delay 20ms between toggle reset bit */ msleep (20 );
@@ -964,7 +958,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_SUBSYS_RST , &val); -if (err <0 ) +if (err)return err; }
Greg Kroah-Hartman
maintainerPATCH 241/438 Bluetooth: btmtk: Fix short read errors in btmtk_usb_reg_read()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit 0cc4b5649ae83deb8222100dba31aa0f100a19cd upstream.
If btmtk_usb_reg_read() gets a "short" read from a device, it will accidentally treat that as a "real" read and populate the returned value with some unknown and probably totally invalid data.
Fix this logic error up by calling usb_control_msg_recv() which guarantees a "full" read happens, and then simplify the error checking for when btmtk_usb_reg_read() is called (it's really just btmtk_usb_id_get() that calls btmtk_usb_reg_read(), so fix up those return sites.
--- drivers/bluetooth/btmtk.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-)
drivers/bluetooth/btmtk.c +15 -21
@@ -827,27 +827,21 @@ static int btmtk_usb_uhw_reg_read(structstatic int btmtk_usb_reg_read (struct hci_dev *hdev,u32 reg,u32 *val) {struct btmtk_data *data =hci_get_priv (hdev); -int pipe, err, size =sizeof (u32); -void *buf; - - buf =kzalloc (size,GFP_KERNEL ); -if (!buf) -return -ENOMEM ; +u8 buf[sizeof (u32)]; +int err; - pipe =usb_rcvctrlpipe (data->udev,0 ); - err =usb_control_msg (data->udev, pipe,0x63 , -USB_TYPE_VENDOR |USB_DIR_IN , - reg >>16 , reg &0xffff , - buf, size,USB_CTRL_GET_TIMEOUT ); + *val =0 ; + err =usb_control_msg_recv (data->udev,0 ,0x63 , +USB_TYPE_VENDOR |USB_DIR_IN , + reg >>16 , reg &0xffff , + buf,sizeof (buf),USB_CTRL_GET_TIMEOUT , +GFP_KERNEL );if (err <0 ) - goto err_free_buf; +return err; *val =get_unaligned_le32 (buf); -err_free_buf: -kfree (buf); - -return err; +return 0 ; }static int btmtk_usb_id_get (struct hci_dev *hdev,u32 reg,u32 *id)
@@ -974,7 +968,7 @@ int btmtk_usb_subsys_reset(struct hci_de } err =btmtk_usb_id_get (hdev,0x70010200 , &val); -if (err <0 || (!val && dev_id !=0x6639 )) +if (err || (!val && dev_id !=0x6639 ))bt_dev_err (hdev,"Can't get device id, subsys reset fail." );return err;
@@ -1318,24 +1312,24 @@ int btmtk_usb_setup(struct hci_dev *hdev calltime =ktime_get (); err =btmtk_usb_id_get (hdev,0x80000008 , &dev_id); -if (err <0 ) { +if (err) {bt_dev_err (hdev,"Failed to get device id (%d)" , err);return err; }if (!dev_id || dev_id !=0x7663 ) { err =btmtk_usb_id_get (hdev,0x70010200 , &dev_id); -if (err <0 ) { +if (err) {bt_dev_err (hdev,"Failed to get device id (%d)" , err);return err; } err =btmtk_usb_id_get (hdev,0x80021004 , &fw_version); -if (err <0 ) { +if (err) {bt_dev_err (hdev,"Failed to get fw version (%d)" , err);return err; } err =btmtk_usb_id_get (hdev,0x70010020 , &fw_flavor); -if (err <0 ) { +if (err) {bt_dev_err (hdev,"Failed to get fw flavor (%d)" , err);return err; }
Greg Kroah-Hartman
maintainerPATCH 242/438 Bluetooth: mgmt: fix pending command UAF in EIR updates
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit 8f2f62855a41d1730fb9e8122912bd2c8d6bed5d upstream.
MGMT_OP_SET_LOCAL_NAME is handled asynchronously on powered controllers and can run set_name_sync(). When the controller is BR/EDR capable, set_name_sync() updates the local name and then rebuilds EIR data through eir_create(). The EIR builder walks hdev->uuids, but the UUID list can be changed and entries can be freed by MGMT_OP_ADD_UUID and MGMT_OP_REMOVE_UUID.
pending_eir_or_class() is meant to serialize management commands that can change EIR or the class of device, but it did not include MGMT_OP_SET_LOCAL_NAME. In addition, it walked hdev->mgmt_pending without hdev->mgmt_pending_lock even though pending commands are added and removed under that mutex. A racing command completion can therefore remove and free a pending command while pending_eir_or_class() is still inspecting it, leading to a use-after-free in the pending-command list or allowing a local name update to rebuild EIR while UUID entries are being removed.
Take hdev->mgmt_pending_lock while scanning hdev->mgmt_pending and treat MGMT_OP_SET_LOCAL_NAME as an EIR/class-affecting pending command on the powered asynchronous path. Check for a conflicting pending command before copying the new short name so a rejected SET_LOCAL_NAME request does not modify hdev->short_name.
--- net/bluetooth/mgmt.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
net/bluetooth/mgmt.c +18 -2
@@ -2699,18 +2699,28 @@ static int mgmt_hci_cmd_sync(struct sockstatic bool pending_eir_or_class (struct hci_dev *hdev) {struct mgmt_pending_cmd *cmd; +bool pending = false; + +mutex_lock (&hdev->mgmt_pending_lock);list_for_each_entry (cmd, &hdev->mgmt_pending, list) {switch (cmd->opcode) {case MGMT_OP_ADD_UUID :case MGMT_OP_REMOVE_UUID :case MGMT_OP_SET_DEV_CLASS : +case MGMT_OP_SET_LOCAL_NAME :case MGMT_OP_SET_POWERED : -return true; + pending = true; +break ; } + +if (pending) +break ; } -return false; +mutex_unlock (&hdev->mgmt_pending_lock); + +return pending; }static const u8 bluetooth_base_uuid[] = {
@@ -4046,6 +4056,12 @@ static int set_local_name(struct sock *s goto failed; } +if (hdev_is_powered (hdev) &&pending_eir_or_class (hdev)) { + err =mgmt_cmd_status (sk, hdev->id,MGMT_OP_SET_LOCAL_NAME , +MGMT_STATUS_BUSY ); + goto failed; + } +memcpy (hdev->short_name, cp->short_name,sizeof (hdev->short_name));if (!hdev_is_powered (hdev)) {
Greg Kroah-Hartman
maintainerPATCH 243/438 Bluetooth: SCO: give the socket its own sco_conn reference
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aldo Ariel Panzardo <[email protected]>
commit abd93c85c8667add738ee82aeab95dd9fc8265a2 upstream.
sco_conn_del() drops a reference it does not own. It takes one transient reference via sco_conn_hold_unless_zero() and releases it with the sco_conn_put() that follows sco_sock_hold(); the additional put in the !sk branch releases a second one:
conn = sco_conn_hold_unless_zero(conn);
...
sk = sco_sock_hold(conn);
sco_conn_unlock(conn);
sco_conn_put(conn);
if (!sk) {
sco_conn_put(conn);
return;
}When close() races the controller's Disconnection Complete, sco_chan_del() clears conn->sk and drops the socket's reference while sco_conn_del() is running. sco_conn_del() then sees sk == NULL, its own put drops the count to zero and frees the conn, and the second put writes to the freed kref:
BUG: KASAN: slab-use-after-free in sco_conn_put.part.0+0x1a/0x190
Write of size 4 at addr ffff8881099dec74 by task kworker/u17:3/413
Workqueue: hci1 hci_rx_work
Call Trace:
sco_conn_put.part.0+0x1a/0x190
hci_disconn_complete_evt+0x1ee/0x3e0
hci_event_packet+0x54a/0x650
hci_rx_work+0x321/0x3d0
Allocated by task 413:
sco_conn_add+0x72/0x1a0
sco_connect_cfm+0x88/0x670
Freed by task 413:
sco_conn_del.isra.0+0x3f/0xf0
hci_disconn_complete_evt+0x1ee/0x3e0
refcount_t: underflow; use-after-free.The root cause is that the socket stores the connection without holding a reference of its own. __sco_chan_add() does:
sco_pi(sk)->conn = conn;
so the socket borrows whatever reference its caller happened to hold, and the callers paper over that with ad-hoc holds and puts. Give the socket a counted reference instead: __sco_chan_add() takes one and it is released together with the channel (sco_chan_del()) and in sco_sock_destruct(). With the socket holding its own reference, sco_conn_del() no longer needs the extra put and the redundant hold in sco_conn_ready() goes away.
Making the socket own its reference means the connection is now actually freed on the error paths of sco_connect() where it used to leak, which in turn runs sco_conn_free() and its hci_conn_drop(conn->hcon). To keep the hci_conn accounting balanced, make that ownership explicit as well:sco_conn_add() consumes one hci_conn reference and the sco_conn owns it for its lifetime. sco_connect() hands over the reference returned by hci_connect_sco() and no longer drops it on the error paths; sco_connect_cfm(), which is not given a reference, takes one with hci_conn_hold() before handing it to sco_conn_add() (and drops it again if the allocation fails); and the explicit hci_conn_hold() in sco_conn_ready() is removed. Every reference then has a single, clear owner.
--- net/bluetooth/sco.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
net/bluetooth/sco.c +13 -9
@@ -190,6 +190,9 @@ static void sco_sock_clear_timer(struct }/* ---- SCO connections ---- */ +/* Consumes a reference on @hcon, which the returned sco_conn owns until it is +* freed. On failure (NULL return) the reference is left for the caller to drop. +*/ static struct sco_conn *sco_conn_add (struct hci_conn *hcon) {struct sco_conn *conn = hcon->sco_data;
@@ -200,6 +203,9 @@ static struct sco_conn *sco_conn_add(strsco_conn_lock (conn); conn->hcon = hcon;sco_conn_unlock (conn); + }else { +/* conn already owns a reference on hcon */ +hci_conn_drop (hcon); }return conn; }
@@ -267,10 +273,8 @@ static void sco_conn_del(struct hci_connsco_conn_unlock (conn);sco_conn_put (conn); -if (!sk) { -sco_conn_put (conn); +if (!sk)return ; - }/* Kill socket */ lock_sock (sk);
@@ -285,7 +289,7 @@ static void __sco_chan_add(struct sco_co {BT_DBG ("conn %p" , conn); -sco_pi (sk)->conn = conn; +sco_pi (sk)->conn =sco_conn_hold (conn); conn->sk = sk;if (parent)
@@ -368,15 +372,15 @@ static int sco_connect(struct sock *sk)*/ if (sk->sk_state !=BT_OPEN && sk->sk_state !=BT_BOUND ) {release_sock (sk); -hci_conn_drop (hcon); +sco_conn_put (conn); err = -EBADFD ; goto unlock; } err =sco_chan_add (conn, sk,NULL ); +sco_conn_put (conn);if (err) {release_sock (sk); -hci_conn_drop (hcon); goto unlock; }
@@ -1452,8 +1456,6 @@ static void sco_conn_ready(struct sco_cobacpy (&sco_pi (sk)->src, &conn->hcon->src);bacpy (&sco_pi (sk)->dst, &conn->hcon->dst); -sco_conn_hold (conn); -hci_conn_hold (conn->hcon);__sco_chan_add (conn, sk, parent);if (test_bit (BT_SK_DEFER_SETUP , &bt_sk (parent)->flags))
@@ -1509,10 +1511,12 @@ static void sco_connect_cfm(struct hci_cif (!status) {struct sco_conn *conn; - conn =sco_conn_add (hcon); + conn =sco_conn_add (hci_conn_hold (hcon));if (conn) {sco_conn_ready (conn);sco_conn_put (conn); + }else { +hci_conn_drop (hcon); } }else sco_conn_del (hcon,bt_to_errno (status));
Greg Kroah-Hartman
maintainerPATCH 244/438 Bluetooth: mgmt: fix UAF in pair command cancellation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit d0a7b48ad0921bd88effaee10bf970ab1d5d0ddd upstream.
The pairing completion and authentication failure callbacks look up the pending MGMT_OP_PAIR_DEVICE command by walking hdev->mgmt_pending. The lookup returned a command that was still linked on the shared pending list, without keeping mgmt_pending_lock held for the later dereference and removal.
A concurrent MGMT_OP_CANCEL_PAIR_DEVICE request can remove and free the same pending command before the callback uses it. The reverse race is also possible when cancel_pair_device() gets a command from pending_find() and a callback removes it before the cancel path dereferences it. This can lead to a use-after-free and a second list_del().
Make the pairing lookup helpers transfer ownership of the pending command by removing it from hdev->mgmt_pending while holding mgmt_pending_lock. The callbacks and cancel path then complete the command and free it directly, so racing paths cannot find or free the same command again. Take a temporary hci_conn reference in cancel_pair_device() because the command completion drops the reference stored in the pending command.
--- net/bluetooth/mgmt.c | 64 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 18 deletions(-)
net/bluetooth/mgmt.c +46 -18
@@ -3527,11 +3527,13 @@ static int set_io_capability(struct sock NULL, 0); } -static struct mgmt_pending_cmd *find_pairing (struct hci_conn *conn) +static struct mgmt_pending_cmd *remove_pairing (struct hci_conn *conn) {struct hci_dev *hdev = conn->hdev;struct mgmt_pending_cmd *cmd; +mutex_lock (&hdev->mgmt_pending_lock); +list_for_each_entry (cmd, &hdev->mgmt_pending, list) {if (cmd->opcode !=MGMT_OP_PAIR_DEVICE )continue ;
@@ -3539,9 +3541,39 @@ static struct mgmt_pending_cmd *find_paiif (cmd->user_data != conn)continue ; +list_del (&cmd->list); +mutex_unlock (&hdev->mgmt_pending_lock);return cmd; } +mutex_unlock (&hdev->mgmt_pending_lock); + +return NULL ; +} + +static struct mgmt_pending_cmd *remove_pairing_by_addr (struct hci_dev *hdev, +bdaddr_t *bdaddr) +{ +struct mgmt_pending_cmd *cmd; +struct hci_conn *conn; + +mutex_lock (&hdev->mgmt_pending_lock); + +list_for_each_entry (cmd, &hdev->mgmt_pending, list) { +if (cmd->opcode !=MGMT_OP_PAIR_DEVICE ) +continue ; + + conn = cmd->user_data; +if (bacmp (bdaddr, &conn->dst) !=0 ) +continue ; + +list_del (&cmd->list); +mutex_unlock (&hdev->mgmt_pending_lock); +return cmd; + } + +mutex_unlock (&hdev->mgmt_pending_lock); +return NULL ; }
@@ -3579,10 +3611,10 @@ void mgmt_smp_complete(struct hci_conn *u8 status = complete ?MGMT_STATUS_SUCCESS :MGMT_STATUS_FAILED ;struct mgmt_pending_cmd *cmd; - cmd =find_pairing (conn); + cmd =remove_pairing (conn);if (cmd) { cmd->cmd_complete (cmd, status); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); } }
@@ -3592,14 +3624,14 @@ static void pairing_complete_cb(struct hBT_DBG ("status %u" , status); - cmd =find_pairing (conn); + cmd =remove_pairing (conn);if (!cmd) {BT_DBG ("Unable to find a pending command" );return ; } cmd->cmd_complete (cmd,mgmt_status (status)); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); }static void le_pairing_complete_cb (struct hci_conn *conn,u8 status)
@@ -3611,14 +3643,14 @@ static void le_pairing_complete_cb(strucif (!status)return ; - cmd =find_pairing (conn); + cmd =remove_pairing (conn);if (!cmd) {BT_DBG ("Unable to find a pending command" );return ; } cmd->cmd_complete (cmd,mgmt_status (status)); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); } static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -3775,23 +3807,17 @@ static int cancel_pair_device(struct soc goto unlock; } - cmd =pending_find (MGMT_OP_PAIR_DEVICE , hdev); + cmd =remove_pairing_by_addr (hdev, &addr->bdaddr);if (!cmd) { err =mgmt_cmd_status (sk, hdev->id,MGMT_OP_CANCEL_PAIR_DEVICE ,MGMT_STATUS_INVALID_PARAMS ); goto unlock; } - conn = cmd->user_data; - -if (bacmp (&addr->bdaddr, &conn->dst) !=0 ) { - err =mgmt_cmd_status (sk, hdev->id,MGMT_OP_CANCEL_PAIR_DEVICE , -MGMT_STATUS_INVALID_PARAMS ); - goto unlock; - } + conn =hci_conn_get (cmd->user_data); cmd->cmd_complete (cmd,MGMT_STATUS_CANCELLED ); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); err =mgmt_cmd_complete (sk, hdev->id,MGMT_OP_CANCEL_PAIR_DEVICE ,0 , addr,sizeof (*addr));
@@ -3809,6 +3835,8 @@ static int cancel_pair_device(struct socif (conn->conn_reason ==CONN_REASON_PAIR_DEVICE )hci_abort_conn (conn,HCI_ERROR_REMOTE_USER_TERM ); +hci_conn_put (conn); + unlock:hci_dev_unlock (hdev);return err;
@@ -10156,14 +10184,14 @@ void mgmt_auth_failed(struct hci_conn *c ev.addr.type =link_to_bdaddr (conn->type, conn->dst_type); ev.status = status; - cmd =find_pairing (conn); + cmd =remove_pairing (conn);mgmt_event (MGMT_EV_AUTH_FAILED , conn->hdev, &ev,sizeof (ev), cmd ? cmd->sk :NULL );if (cmd) { cmd->cmd_complete (cmd, status); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); } }
Greg Kroah-Hartman
maintainerPATCH 245/438 Bluetooth: hci_sync: Fix advertising data UAFs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit cdc36db204ffd97b947d64374cf23a210dc74777 upstream.
hci_find_adv_instance() returns an adv_info pointer that is valid only while hdev->lock is held. The advertising command-sync paths perform instance lookups without that lock and, in some cases, retain the pointer while waiting for a controller response.
An advertising termination event can therefore interleave as follows:
hci_cmd_sync_work hci_rx_work
hci_find_adv_instance()
__hci_cmd_sync_status()
wait for controller reply hci_dev_lock()
hci_remove_adv_instance()
kfree(adv)
adv->scan_rsp_changed = false
KASAN reported:
BUG: KASAN: slab-use-after-free in hci_set_ext_scan_rsp_data_sync+0x2e1/0x300 Write of size 1 at addr ffff88810a45d21d by task kworker/u17:0/88 Workqueue: hci0 hci_cmd_sync_work Call Trace: hci_set_ext_scan_rsp_data_sync+0x2e1/0x300 hci_schedule_adv_instance_sync+0x390/0x4c0 hci_cmd_sync_work+0x173/0x300 Allocated by task 87: hci_add_adv_instance+0x538/0xac0 add_advertising+0x885/0x1160 Freed by task 89: kfree+0x131/0x3c0 hci_remove_adv_instance+0x1d8/0x3b0 hci_le_ext_adv_term_evt+0x17b/0x730
Protect the instance lookup and payload construction in the extended advertising, scan response, and periodic advertising data paths. Snapshot the advertising parameters under hdev->lock, but release the lock before waiting for the controller.
Clear advertising-data dirty bits before issuing their commands and restore them after a failure using a fresh lookup. Likewise, update the reported transmit power through a fresh lookup after the parameter command completes. No adv_info pointer then survives an HCI command wait.
--- net/bluetooth/hci_sync.c | 131 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 34 deletions(-)
net/bluetooth/hci_sync.c +97 -34
@@ -1233,10 +1233,11 @@ static int hci_set_adv_set_random_addr_s }static int -hci_set_ext_adv_params_sync (struct hci_dev *hdev,struct adv_info *adv, +hci_set_ext_adv_params_sync (struct hci_dev *hdev,u8 instance,const struct hci_cp_le_set_ext_adv_params *cp,struct hci_rp_le_set_ext_adv_params *rp) { +struct adv_info *adv;struct sk_buff *skb; skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(*cp),
@@ -1264,11 +1265,15 @@ hci_set_ext_adv_params_sync(struct hci_dif (!rp->status) { hdev->adv_addr_type = cp->own_addr_type; -if (!cp->handle) { +if (!instance) {/* Store in hdev for instance 0 */ hdev->adv_tx_power = rp->tx_power; - }else if (adv) { - adv->tx_power = rp->tx_power; + }else { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (adv) + adv->tx_power = rp->tx_power; +hci_dev_unlock (hdev); } }
@@ -1284,9 +1289,13 @@ static int hci_set_ext_adv_data_sync(strint err;if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); -if (!adv || !adv->adv_data_changed) +if (!adv || !adv->adv_data_changed) { +hci_dev_unlock (hdev);return 0 ; + } } len = eir_create_adv_data(hdev, instance, pdu->data,
@@ -1297,16 +1306,27 @@ static int hci_set_ext_adv_data_sync(str pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; pdu->frag_pref =LE_SET_ADV_DATA_NO_FRAG ; +if (adv) { + adv->adv_data_changed = false; +hci_dev_unlock (hdev); + } + err =__hci_cmd_sync_status (hdev,HCI_OP_LE_SET_EXT_ADV_DATA ,struct_size (pdu, data, len), pdu,HCI_CMD_TIMEOUT ); -if (err) +if (err) { +if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (adv) + adv->adv_data_changed = true; +hci_dev_unlock (hdev); + } +return err; + } -/* Update data if the command succeed */ -if (adv) { - adv->adv_data_changed = false; - }else { +if (!instance) {memcpy (hdev->adv_data, pdu->data, len); hdev->adv_data_len = len; }
@@ -1360,22 +1380,22 @@ int hci_setup_ext_adv_instance_sync(strustruct adv_info *adv;bool secondary_adv; -if (instance >0 ) { - adv =hci_find_adv_instance (hdev, instance); -if (!adv) -return -EINVAL ; - }else { - adv =NULL ; - } -/* Updating parameters of an active instance will return a -* Command Disallowed error, so we must first disable the -* instance if it is active. +* Command Disallowed error, so disable it before taking a snapshot. */ -if (adv) { +if (instance >0 ) { err =hci_disable_ext_adv_instance_sync (hdev, instance);if (err)return err; + +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (!adv) { +hci_dev_unlock (hdev); +return -EINVAL ; + } + }else { + adv =NULL ; } flags =hci_adv_instance_flags (hdev, instance);
@@ -1386,8 +1406,11 @@ int hci_setup_ext_adv_instance_sync(stru connectable = (flags &MGMT_ADV_FLAG_CONNECTABLE ) ||mgmt_get_connectable (hdev); -if (!is_advertising_allowed (hdev, connectable)) +if (!is_advertising_allowed (hdev, connectable)) { +if (instance) +hci_dev_unlock (hdev);return -EPERM ; + }/* Set require_privacy to true only when non-connectable * advertising is used and it is not periodic.
@@ -1398,8 +1421,11 @@ int hci_setup_ext_adv_instance_sync(stru err =hci_get_random_address (hdev, require_privacy,adv_use_rpa (hdev, flags), adv, &own_addr_type, &random_addr); -if (err <0 ) +if (err <0 ) { +if (instance) +hci_dev_unlock (hdev);return err; + }memset (&cp,0 ,sizeof (cp));
@@ -1450,6 +1476,9 @@ int hci_setup_ext_adv_instance_sync(stru cp.channel_map = hdev->le_adv_channel_map; cp.handle = adv ? adv->handle : instance; +if (instance) +hci_dev_unlock (hdev); +if (flags &MGMT_ADV_FLAG_SEC_2M ) { cp.primary_phy =HCI_ADV_PHY_1M ; cp.secondary_phy =HCI_ADV_PHY_2M ;
@@ -1462,12 +1491,12 @@ int hci_setup_ext_adv_instance_sync(stru cp.secondary_phy =HCI_ADV_PHY_1M ; } - err =hci_set_ext_adv_params_sync (hdev, adv, &cp, &rp); + err =hci_set_ext_adv_params_sync (hdev, instance, &cp, &rp);if (err)return err;/* Update adv data as tx power is known now */ - err =hci_set_ext_adv_data_sync (hdev, cp.handle); + err =hci_set_ext_adv_data_sync (hdev, instance);if (err)return err;
@@ -1475,9 +1504,14 @@ int hci_setup_ext_adv_instance_sync(stru own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED) && bacmp(&random_addr, BDADDR_ANY)) {/* Check if random address need to be updated */ -if (adv) { -if (!bacmp (&random_addr, &adv->random_addr)) +if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (!adv || !bacmp (&random_addr, &adv->random_addr)) { +hci_dev_unlock (hdev);return 0 ; + } +hci_dev_unlock (hdev); }else {if (!bacmp (&random_addr, &hdev->random_addr))return 0 ;
@@ -1499,9 +1533,13 @@ static int hci_set_ext_scan_rsp_data_synint err;if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); -if (!adv || !adv->scan_rsp_changed) +if (!adv || !adv->scan_rsp_changed) { +hci_dev_unlock (hdev);return 0 ; + } } len =eir_create_scan_rsp (hdev, instance, pdu->data);
@@ -1511,15 +1549,27 @@ static int hci_set_ext_scan_rsp_data_syn pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; pdu->frag_pref =LE_SET_ADV_DATA_NO_FRAG ; +if (adv) { + adv->scan_rsp_changed = false; +hci_dev_unlock (hdev); + } + err =__hci_cmd_sync_status (hdev,HCI_OP_LE_SET_EXT_SCAN_RSP_DATA ,struct_size (pdu, data, len), pdu,HCI_CMD_TIMEOUT ); -if (err) +if (err) { +if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (adv) + adv->scan_rsp_changed = true; +hci_dev_unlock (hdev); + } +return err; + } -if (adv) { - adv->scan_rsp_changed = false; - }else { +if (!instance) {memcpy (hdev->scan_rsp_data, pdu->data, len); hdev->scan_rsp_data_len = len; }
@@ -1534,8 +1584,14 @@ static int __hci_set_scan_rsp_data_sync(memset (&cp,0 ,sizeof (cp)); +if (instance) +hci_dev_lock (hdev); + len =eir_create_scan_rsp (hdev, instance, cp.data); +if (instance) +hci_dev_unlock (hdev); +if (hdev->scan_rsp_data_len == len && !memcmp (cp.data, hdev->scan_rsp_data, len))return 0 ;
@@ -1670,9 +1726,13 @@ static int hci_set_per_adv_data_sync(strstruct adv_info *adv =NULL ;if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); -if (!adv || !adv->periodic) +if (!adv || !adv->periodic) { +hci_dev_unlock (hdev);return 0 ; + } } len =eir_create_per_adv_data (hdev, instance, pdu->data);
@@ -1681,6 +1741,9 @@ static int hci_set_per_adv_data_sync(str pdu->handle = adv ? adv->handle : instance; pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; +if (adv) +hci_dev_unlock (hdev); +return __hci_cmd_sync_status (hdev,HCI_OP_LE_SET_PER_ADV_DATA ,struct_size (pdu, data, len), pdu,HCI_CMD_TIMEOUT );
@@ -6501,7 +6564,7 @@ static int hci_le_ext_directed_advertisiif (err)return err; - err =hci_set_ext_adv_params_sync (hdev,NULL , &cp, &rp); + err =hci_set_ext_adv_params_sync (hdev,0 , &cp, &rp);if (err)return err;
Greg Kroah-Hartman
maintainerPATCH 246/438 Bluetooth: HIDP: reject frames without a transaction header
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sangho Lee <[email protected]>
commit 47778d2c2087b5d192398f6fddf692d16a5431cf upstream.
hidp_recv_ctrl_frame() and hidp_recv_intr_frame() read skb->data[0] before checking that the L2CAP SDU contains a transaction header. A connected HIDP peer can send an empty basic-mode SDU and make both paths use an uninitialized byte from skb tailroom.
KMSAN reports the use in hidp_session_run(), with the uninitialized value originating in __alloc_skb() through vhci_write(). The control path produces two reports and the interrupt path produces one.
The byte can also be controlled by a malformed lower-layer packet. If an HCI ACL packet contains an L2CAP PDU with a declared zero-length payload followed by an extra 0x15 byte, l2cap_recv_acldata() reduces skb->len to the declared PDU length before dispatch. The current HIDP path nevertheless consumes the extra byte as HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG and terminates the HIDP session. With this change, the same packet is discarded and a subsequent feature report request succeeds.
Pull the transaction header with skb_pull_data() and discard frames that do not contain it.
--- net/bluetooth/hidp/core.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
net/bluetooth/hidp/core.c +15 -10
@@ -563,16 +563,18 @@ static int hidp_process_data(struct hidpstatic void hidp_recv_ctrl_frame (struct hidp_session *session,struct sk_buff *skb) { -unsigned char hdr, type, param; +unsigned char type, param; +u8 *hdr;int free_skb =1 ;BT_DBG ("session %p skb %p len %u" , session, skb, skb->len); - hdr = skb->data[0 ]; -skb_pull (skb,1 ); + hdr =skb_pull_data (skb,1 ); +if (!hdr) + goto free; - type = hdr &HIDP_HEADER_TRANS_MASK ; - param = hdr &HIDP_HEADER_PARAM_MASK ; + type = *hdr &HIDP_HEADER_TRANS_MASK ; + param = *hdr &HIDP_HEADER_PARAM_MASK ;switch (type) {case HIDP_TRANS_HANDSHAKE :
@@ -593,6 +595,7 @@ static void hidp_recv_ctrl_frame(structbreak ; } +free:if (free_skb)kfree_skb (skb); }
@@ -600,14 +603,15 @@ static void hidp_recv_ctrl_frame(structstatic void hidp_recv_intr_frame (struct hidp_session *session,struct sk_buff *skb) { -unsigned char hdr; +u8 *hdr;BT_DBG ("session %p skb %p len %u" , session, skb, skb->len); - hdr = skb->data[0 ]; -skb_pull (skb,1 ); + hdr =skb_pull_data (skb,1 ); +if (!hdr) + goto free; -if (hdr == (HIDP_TRANS_DATA |HIDP_DATA_RTYPE_INPUT )) { +if (*hdr == (HIDP_TRANS_DATA |HIDP_DATA_RTYPE_INPUT )) {hidp_set_timer (session);if (session->input)
@@ -619,9 +623,10 @@ static void hidp_recv_intr_frame(structBT_DBG ("report len %d" , skb->len); } }else { -BT_DBG ("Unsupported protocol header 0x%02x" , hdr); +BT_DBG ("Unsupported protocol header 0x%02x" , *hdr); } +free:kfree_skb (skb); }
Greg Kroah-Hartman
maintainerPATCH 247/438 Bluetooth: HIDP: validate numbered report payloads
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sangho Lee <[email protected]>
commit 34f53d27b81a16a02828c8fdfa4e02badc326f17 upstream.
When hidp_get_raw_report() waits for a numbered report, hidp_process_data() compares the expected report number with skb->data[0]. A connected HIDP peer can reply with only a DATA transaction header, leaving the skb empty after the header is removed.
KMSAN reports an uninitialized-value use in hidp_session_run(), with the value originating in __alloc_skb() through vhci_write(). The transaction header checks remove the empty-frame reports, but this report remains until the payload check is added.
The comparison can also consume a peer-controlled byte beyond the declared L2CAP PDU. A DATA | FEATURE response followed by an extra 0x01 byte made the current code accept that byte as report ID 1 and complete HIDIOCGFEATURE with a zero-byte result. With this change the malformed response is rejected with -EIO, while a subsequent valid response still succeeds.
Require a payload byte before comparing a numbered report ID. Unnumbered reports continue to accept an empty payload.
--- net/bluetooth/hidp/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/bluetooth/hidp/core.c +3 -2
@@ -546,9 +546,10 @@ static int hidp_process_data(struct hidp }if (test_bit (HIDP_WAITING_FOR_RETURN , &session->flags) && - param == session->waiting_report_type) { + param == session->waiting_report_type) {if (session->waiting_report_number <0 || - session->waiting_report_number == skb->data[0 ]) { + (skb->len && + session->waiting_report_number == skb->data[0 ])) {/* hidp_get_raw_report() is waiting on this report. */ session->report_return = skb; done_with_skb =0 ;
Greg Kroah-Hartman
maintainerPATCH 248/438 bpf: lwt: Fix dst reference leak on reroute failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
commit 88c17de85ddb459c3fe1e3c65d61fa366b1cf0a8 upstream.
bpf_lwt_xmit_reroute() obtains a referenced dst from the route lookup. When skb_cow_head() fails before that dst is installed on the skb, the error path only frees the skb. The skb still owns its previous dst, so the newly looked up dst reference is leaked.
Release the new dst reference before freeing the skb on this error path.
--- net/core/lwt_bpf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/core/lwt_bpf.c +3 -1
@@ -255,8 +255,10 @@ static int bpf_lwt_xmit_reroute(struct s* if there is enough header space in skb. */ err =skb_cow_head (skb,LL_RESERVED_SPACE (dst->dev)); -if (unlikely (err)) +if (unlikely (err)) { +dst_release (dst); goto err; + }skb_dst_drop (skb);skb_dst_set (skb, dst);
Greg Kroah-Hartman
maintainerPATCH 249/438 afs: Fix afs_fs_fetch_data() to set call->async
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
commit d568a43f6dbba3ba006304d95fd09862bd482a2f upstream.
Fix afs_fs_fetch_data() to set call->async on an async operation as does afs_fs_fetch_data64().
--- fs/afs/fsclient.c | 3 +++ 1 file changed, 3 insertions(+)
fs/afs/fsclient.c +3 -0
@@ -477,6 +477,9 @@ void afs_fs_fetch_data(struct afs_operatif (!call)return afs_op_nomem (op); +if (op->flags &AFS_OPERATION_ASYNC ) + call->async = true; +/* marshall the parameters */ bp = call->request; bp[0 ] =htonl (FSFETCHDATA );
Greg Kroah-Hartman
maintainerPATCH 250/438 afs: Fix afs_fs_fetch_data() to subtract transferred from len
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
commit 222052c6be186f2074b3a4d741d5de200f654c43 upstream.
Fix afs_fs_fetch_data() to subtract subreq->transferred from subreq->len rather than adding it.
--- fs/afs/fsclient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/afs/fsclient.c +1 -1
@@ -487,7 +487,7 @@ void afs_fs_fetch_data(struct afs_operat bp[2 ] =htonl (vp->fid.vnode); bp[3 ] =htonl (vp->fid.unique); bp[4 ] =htonl (lower_32_bits (subreq->start + subreq->transferred)); - bp[5 ] =htonl (lower_32_bits (subreq->len + subreq->transferred)); + bp[5 ] =htonl (lower_32_bits (subreq->len - subreq->transferred)); call->fid = vp->fid;trace_afs_make_fs_call (call, &vp->fid);
Greg Kroah-Hartman
maintainerPATCH 251/438 afs: Fix UAF when sending a message
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
commit 4af1ec68d54b3871155914d584fb10669c41a861 upstream.
In afs_make_call(), there's a race with async call reception and destruction. If a call is dispatched that doesn't have call->write_iter set (used to specify the data content for FS.StoreData), then the first rxrpc_kernel_send_data() will not set MSG_MORE in the msghdr.
Once rxrpc_send_data() queues the last request packet, the response could come in at any time and cause the call to be completed and put. However, afs_make_call() will look at the call again to see it ->write_iter should be handled - something it's only allowed to do if it has its own ref on the call. Whilst this is the case for synchronous calls, it isn't true for async calls such as FS.FetchData.
There's also a potential UAF in afs_make_call() in the event that an asynchronous call is being sent, but the call fails in some way (e.g. it gets aborted from the server). The problem there is that afs_make_call() tries to abort a call if the rxrpc send fails, but the asynchronous notification from rxrpc may have caused the afs_call to be torn down.
generic/650 plays games with randomly taking CPUs offline, and can interject a significant delay such that the call is deallocated before afs_make_call() gets to check call->write_iter - and a UAF ensues (caught by KASAN).
BUG: KASAN: slab-use-after-free in afs_make_call+0x1c90/0x2210 [kafs] Read of size 8 at addr ffff888035e050e8 by task fsstress/1409
Fix this by making afs_make_op_call() give the op->call its own ref rather than transferring the caller's ref to it and then dropping the ref when afs_make_call() returns.
This also means that the afs_make_call() func never loses its ref on the call now.
--- fs/afs/internal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/afs/internal.h +2 -1
@@ -1421,7 +1421,7 @@ static inline void afs_make_op_call(stru {struct afs_addr_list *alist = op->estate->addresses; - op->call = call; + op->call =afs_get_call (call, afs_call_trace_get); op->type = call->type; call->op = op; call->key = op->key;
@@ -1429,6 +1429,7 @@ static inline void afs_make_op_call(stru call->peer =rxrpc_kernel_get_peer (alist->addrs[op->addr_index].peer); call->service_id = op->server->service_id;afs_make_call (call, gfp); +afs_put_call (call); }static inline void afs_extract_begin (struct afs_call *call,void *buf,size_t size)
Greg Kroah-Hartman
maintainerPATCH 252/438 ALSA: 6fire: Fix UAF at error handling during probe
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit a54bf16965f896415c3337bc4fbb40fb11941d99 upstream.
Although 6fire driver had a few fixes for dealing with the early error handling during the probe phase, it forgot a pending URB before freeing the resources, which may lead to a UAF.
This patch addresses it by doing the almost same cleanup procedure like the normal disconnect phase at the error path.
--- sound/usb/6fire/chip.c | 4 ++++ 1 file changed, 4 insertions(+)
sound/usb/6fire/chip.c +4 -0
@@ -150,6 +150,10 @@ static int usb6fire_chip_probe(struct usreturn 0 ; destroy_chip: + chip->shutdown = true; +if (card) +snd_card_disconnect (card); +usb6fire_chip_abort (chip);snd_card_free (card);return ret; }
Greg Kroah-Hartman
maintainerPATCH 253/438 ALSA: hda/realtek: Add quirk for TongFang X6SP45xU
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eckhart Mohr <[email protected]>
commit 26a94400ffa4fcbeff32e23abebb83a1a20eb401 upstream.
TongFang X6KK45xU and X6SP45xU have actually different PCI IDs. This patch Adds the missing PCI ID to fix headphone detection and clarifies the naming.
--- sound/hda/codecs/realtek/alc269.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
sound/hda/codecs/realtek/alc269.c +2 -1
@@ -7858,7 +7858,8 @@ static const struct hda_quirk alc269_fixSND_PCI_QUIRK (0x1d05 ,0x300f ,"TongFang X6AR5xxY" ,ALC2XX_FIXUP_HEADSET_MIC ),SND_PCI_QUIRK (0x1d05 ,0x3019 ,"TongFang X6FR5xxY" ,ALC2XX_FIXUP_HEADSET_MIC ),SND_PCI_QUIRK (0x1d05 ,0x3031 ,"TongFang X6AR55xU" ,ALC2XX_FIXUP_HEADSET_MIC ), -SND_PCI_QUIRK (0x1d05 ,0x3034 ,"TongFang X6xx45xU" ,ALC2XX_FIXUP_HEADSET_MIC ), +SND_PCI_QUIRK (0x1d05 ,0x3033 ,"TongFang X6SP45xU" ,ALC2XX_FIXUP_HEADSET_MIC ), +SND_PCI_QUIRK (0x1d05 ,0x3034 ,"TongFang X6KK45xU" ,ALC2XX_FIXUP_HEADSET_MIC ),SND_PCI_QUIRK (0x1d17 ,0x3288 ,"Haier Boyue G42" ,ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS ),SND_PCI_QUIRK (0x1d72 ,0x1602 ,"RedmiBook" ,ALC255_FIXUP_XIAOMI_HEADSET_MIC ), SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
Greg Kroah-Hartman
maintainerPATCH 254/438 ALSA: lx6464es: fix period byte count for 16-bit streams
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 6437033bffe8bd2af174d139af552d90d40c7ac6 upstream.
The lx6464es driver advertises both 16-bit and packed 24-bit PCM formats, but lx_trigger_start() and lx_interrupt_request_new_buffer() calculate the DMA period size as runtime->period_size * runtime->channels * 3. That is only correct for the packed 24-bit formats.
For 16-bit streams the driver submits buffers that are 50% larger than the actual ALSA period and advances the DMA address by the same wrong amount. For example, with 2 channels, 256 frames and 4 periods, the third buffer already extends beyond the ALSA buffer and the fourth buffer starts outside it.
Use snd_pcm_lib_period_bytes() so the byte count matches the runtime format, channel count and period size.
--- sound/pci/lx6464es/lx6464es.c | 5 +---- sound/pci/lx6464es/lx_core.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-)
sound/pci/lx6464es/lx6464es.c +1 -4
@@ -402,11 +402,8 @@ static void lx_trigger_start(struct lx64int err; -const u32 channels = substream->runtime->channels; -const u32 bytes_per_frame = channels *3 ; -const u32 period_size = substream->runtime->period_size;const u32 periods = substream->runtime->periods; -const u32 period_bytes = period_size * bytes_per_frame; +const u32 period_bytes =snd_pcm_lib_period_bytes (substream);dma_addr_t buf = substream->dma_buffer.addr;int i;
sound/pci/lx6464es/lx_core.c +1 -4
@@ -969,10 +969,7 @@ static int lx_interrupt_request_new_buffconst unsigned int is_capture = lx_stream->is_capture;int err; -const u32 channels = substream->runtime->channels; -const u32 bytes_per_frame = channels *3 ; -const u32 period_size = substream->runtime->period_size; -const u32 period_bytes = period_size * bytes_per_frame; +const u32 period_bytes =snd_pcm_lib_period_bytes (substream);const u32 pos = lx_stream->frame_pos;const u32 next_pos = ((pos+1 ) == substream->runtime->periods) ?0 : pos +1 ;
Greg Kroah-Hartman
maintainerPATCH 255/438 ALSA: pcm: wake linked drain waiters on unlink
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit f495b6c4c8594122918552c9be2b51eb71647cd9 upstream.
snd_pcm_drain() on a linked stream parks an on-stack wait entry on the drained peer's runtime->sleep, and after schedule_timeout() removes it only if that peer is still found in the caller's group. If group membership changes during the wait and the sleep ends by signal or timeout (so autoremove_wake_function() does not run), finish_wait() is skipped and snd_pcm_drain() returns with the entry still queued on that stream's sleep list; a later wake_up() then walks a freed stack frame. This is reachable by unlinking either the drained or the draining stream.
Unlike the close path (snd_pcm_drop() -> snd_pcm_post_stop()), snd_pcm_unlink() never wakes the sleep queues. Wake every group member under the group lock before the membership change, so a linked drainer is released and drops its entry while the streams are still grouped.
The window was opened when snd_pcm_link_rwsem stopped being held across the wait and the removal became conditional on group membership (see Fixes). The later switch to finish_wait() kept that conditional removal, so the signal/timeout case remained.
--- sound/core/pcm_native.c | 7 +++++++ 1 file changed, 7 insertions(+)
sound/core/pcm_native.c +7 -0
@@ -2357,6 +2357,7 @@ static void relink_to_local(struct snd_pstatic int snd_pcm_unlink (struct snd_pcm_substream *substream) { +struct snd_pcm_substream *s;struct snd_pcm_group *group;bool nonatomic = substream->pcm->nonatomic;bool do_free = false;
@@ -2369,6 +2370,12 @@ static int snd_pcm_unlink(struct snd_pcm group = substream->group;snd_pcm_group_lock_irq (group, nonatomic); +/* release drain waiters before changing membership, else snd_pcm_drain() +* leaves its on-stack wait entry queued on a member's sleep list +*/ +snd_pcm_group_for_each_entry (s, substream) +wake_up (&s->runtime->sleep); +relink_to_local (substream);refcount_dec (&group->refs);
Greg Kroah-Hartman
maintainerPATCH 256/438 ALSA: seq: Fix division by zero in initialize_timer()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit 21e19688433452dfbbbe6b2bb670dea6eb92f0f6 upstream.
A userspace-driven ALSA timer (SND_UTIMER) lets an unprivileged user set the backing snd_timer's hardware resolution to an arbitrary 64-bit value via SNDRV_TIMER_IOCTL_CREATE. snd_utimer_create() only rejects zero.
When such a timer is bound to a sequencer queue, initialize_timer() computes the tick period as
tmr->ticks = 1000000000 / (r * freq);
where r is that user-controlled resolution and freq is the sequencer update rate in Hz, clamped to MIN_FREQUENCY..MAX_FREQUENCY (10..6250). A resolution of 2^63 makes the 64-bit product r * freq wrap to zero for any even freq, including DEFAULT_FREQUENCY (1000), so the division faults with a divide-by-zero.
The division runs under tmr->lock with interrupts disabled, so the oops leaves the spinlock held and hangs the CPU. It is reachable by an unprivileged user with access to /dev/snd/timer and /dev/snd/seq.
Oops: divide error: 0000 [#1] SMP KASAN PTI CPU: 7 UID: 1000 PID: 456 Comm: alsa_seq_utimer Not tainted 7.2.0-rc4+ RIP: 0010:initialize_timer.constprop.0+0x20a/0x2d0 snd_seq_timer_start+0x15e/0x2b0 snd_seq_control_queue+0x56f/0xba0 snd_seq_write+0x3e0/0x730
Reject an overflowing product with check_mul_overflow() and fall back to a single tick, which also avoids feeding a wrapped-but-nonzero divisor (e.g. 2^63 * 1000 mod 2^64 == 0, or other resolutions wrapping to a small value) into the period computation.
--- sound/core/seq/seq_timer.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
sound/core/seq/seq_timer.c +4 -5
@@ -362,11 +362,10 @@ static int initialize_timer(struct snd_s tmr->ticks =1 ;if (!(t->hw.flags &SNDRV_TIMER_HW_SLAVE )) {unsigned long r =snd_timer_resolution (tmr->timeri); -if (r) { - tmr->ticks = (unsigned int )(1000000000uL / (r * freq)); -if (! tmr->ticks) - tmr->ticks =1 ; - } +unsigned long den; + +if (r && !check_mul_overflow (r, freq, &den)) + tmr->ticks =max (1U , (unsigned int )(1000000000uL / den)); } tmr->initialized =1 ;return 0 ;
Greg Kroah-Hartman
maintainerPATCH 257/438 ALSA: timer: Clear SNDRV_TIMER_IFLG_DEAD once the close completes
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit c2744d5f3aea474513fd2298daecb94a952ce441 upstream.
snd_timer_close_locked() marks an instance with SNDRV_TIMER_IFLG_DEAD and returns early when the flag is already set, but the flag is never cleared again. A completed close ends in remove_slave_links(), which leaves timeri->timer NULL, so a second close is already harmless through the timer == NULL path; the early return can only be reached by an instance that was opened again in between. For such an instance the close unlinks nothing, so snd_timer_instance_free() frees an object that is still on timer->open_list_head, still on snd_timer_master_list if it was opened with a slave key, still owns any adopted slaves, and still holds its timer and module references.
snd_seq_timer_open() reopens an instance exactly like that: it retries its fallback open on the same object after a failure that has already run snd_timer_close_locked() internally. An unprivileged user with access to /dev/snd/timer and /dev/snd/seq can force that failure, since snd_timer_check_master() returns -EBUSY when a pending slave matches the new master's (slave_class, slave_id) key and the target timer has reached max_instances, and SNDRV_TIMER_IOCTL_SELECT with dev_class = SNDRV_TIMER_CLASS_SLAVE keeps the caller-supplied dev_sclass, so a sequencer queue's key can be forged. The freed instance is afterwards dereferenced by any further snd_timer_open() on that timer, by snd_timer_check_slave(), and by /proc/asound/timers, which faults on the stale ti->owner pointer.
The flag only has to be visible while the close is in progress, which is all its other users need. Clear it in remove_slave_links(), under the same timer->lock that sets it, once the instance is off every list.
--- sound/core/timer.c | 2 ++ 1 file changed, 2 insertions(+)
sound/core/timer.c +2 -0
@@ -417,6 +417,8 @@ static void remove_slave_links(struct snlist_del_init (&slave->ack_list);list_del_init (&slave->active_list); } +/* the close is done; a reopen must not see the mark */ + timeri->flags &= ~SNDRV_TIMER_IFLG_DEAD ; }/*
Greg Kroah-Hartman
maintainerPATCH 258/438 ALSA: ump: fix double free of out_cvts on rawmidi error
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 70c977815af0d997feb2d0c5d284d55689bf7051 upstream.
snd_ump_attach_legacy_rawmidi() allocates the legacy conversion array ump->out_cvts and, on the snd_rawmidi_new() error path, frees it with kfree() but leaves ump->out_cvts pointing at the freed memory. When the endpoint is later torn down, snd_ump_endpoint_free() frees ump->out_cvts a second time, resulting in a double free.
The host snd-usb-audio driver attaches the legacy rawmidi for any USB MIDI 2.0 (UMP) device, so a device that makes snd_rawmidi_new() fail reaches this path on enumeration.
Clear ump->out_cvts after freeing it on the error path so it is not freed again during teardown.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/core/ump.c | 1 + 1 file changed, 1 insertion(+)
sound/core/ump.c +1 -0
@@ -1365,6 +1365,7 @@ int snd_ump_attach_legacy_rawmidi(struct &rmidi);if (err <0 ) {kfree (ump->out_cvts); + ump->out_cvts =NULL ;return err; }
Greg Kroah-Hartman
maintainerPATCH 259/438 ASoC: fsl_asrc: fix m2m_init error path to use goto instead of bare return
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
commit 890b4253134f3a39883af7d5bea67af9c494c56d upstream.
When fsl_asrc_m2m_init() fails in fsl_asrc_probe(), the code did a bare return ret, bypassing pm_runtime_disable() in err_pm_get_sync. Use goto err_pm_get_sync to ensure proper cleanup on failure.
--- sound/soc/fsl/fsl_asrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/fsl/fsl_asrc.c +1 -1
@@ -1419,7 +1419,7 @@ static int fsl_asrc_probe(struct platfor ret =fsl_asrc_m2m_init (asrc);if (ret) {dev_err (&pdev->dev,"failed to init m2m device %d\n" , ret); -return ret; + goto err_pm_get_sync; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 260/438 ASoC: fsl_easrc: fix m2m_init error path to use goto instead of bare return
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
commit a54bc0eef90ea760039c14bb7f3b5db42529f84d upstream.
When fsl_asrc_m2m_init() fails in fsl_easrc_probe(), the code did a bare return ret, bypassing pm_runtime_disable() in err_pm_disable. Use goto err_pm_disable to ensure proper cleanup on failure.
--- sound/soc/fsl/fsl_easrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/fsl/fsl_easrc.c +1 -1
@@ -2269,7 +2269,7 @@ static int fsl_easrc_probe(struct platfo ret =fsl_asrc_m2m_init (easrc);if (ret) {dev_err (&pdev->dev,"failed to init m2m device %d\n" , ret); -return ret; + goto err_pm_disable; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 261/438 ASoC: tas2562: fix DVC coefficient write order
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haidar Lee <[email protected]>
commit 8e957e4907c58e9ca944f98799524f2bbb9cf68a upstream.
The TAS2562 applies the 32-bit digital volume coefficient to the playback path when the last byte, DVC_CFG4 (book 0 page 2 reg 0x0F), is written. tas2562_volume_control_put() wrote DVC_CFG4 first and DVC_CFG1 (the MSB) last, so every volume change latched a value made of the previous coefficient's upper three bytes combined with the new LSB; the remaining bytes only took effect on the next volume change.
In practice the control was unusable: the first setting after power-on always played at roughly 0 dB no matter what value was requested (the chip's default upper bytes were still latched), and most subsequent changes muted the output entirely or produced a distorted, over-unity gain.
Verified on a TAS2562 (ADLINK OSM-520 / MT8189 board) by tracing the I2C writes with ftrace and by writing the same coefficients manually in both byte orders: written MSB-first the register block behaves exactly as the driver expects, LSB-first reproduces the broken behaviour.
Write the bytes MSB first with DVC_CFG4 last so the complete new coefficient is latched atomically.
--- sound/soc/codecs/tas2562.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
sound/soc/codecs/tas2562.c +15 -8
@@ -475,20 +475,27 @@ static int tas2562_volume_control_put(stu32 reg_val; reg_val = float_vol_db_lookup[ucontrol->value.integer.value[0 ]/2 ]; - ret =snd_soc_component_write (component,TAS2562_DVC_CFG4 , - (reg_val &0xff )); -if (ret) -return ret; - ret =snd_soc_component_write (component,TAS2562_DVC_CFG3 , - ((reg_val >>8 ) &0xff )); +/* +* The device applies the 32-bit coefficient to the playback path on +* the write to DVC_CFG4 (the LSB, book 0 page 2 reg 0x0F), so the +* bytes must be written MSB first and DVC_CFG4 last. Writing CFG4 +* first latches a mix of the previous coefficient's upper bytes and +* the new LSB instead of the requested value. +*/ + ret =snd_soc_component_write (component,TAS2562_DVC_CFG1 , + ((reg_val >>24 ) &0xff ));if (ret)return ret; ret =snd_soc_component_write (component,TAS2562_DVC_CFG2 , ((reg_val >>16 ) &0xff ));if (ret)return ret; - ret =snd_soc_component_write (component,TAS2562_DVC_CFG1 , - ((reg_val >>24 ) &0xff )); + ret =snd_soc_component_write (component,TAS2562_DVC_CFG3 , + ((reg_val >>8 ) &0xff )); +if (ret) +return ret; + ret =snd_soc_component_write (component,TAS2562_DVC_CFG4 , + (reg_val &0xff ));if (ret)return ret;
Greg Kroah-Hartman
maintainerPATCH 262/438 ASoC: tas2562: fix broken entries in the volume lookup table
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haidar Lee <[email protected]>
commit bdb0fd6de403fcea7b85dc9d38f0a571583ebe80 upstream.
The float_vol_db_lookup table is supposed to hold round(10^(dB/20) * 2^30) for every 2 dB step from -110 dB to 0 dB, which is 56 entries, but it only has 55: the -90 dB entry duplicates the -92 dB value (0x0000695b) and the -20 dB entry (0x06666666) is missing altogether. As a result every step between -90 dB and -22 dB is off by 2 dB, and the control's maximum raw value of 110 indexes one element past the end of the array.
Replace the duplicated -90 dB entry with the correct value 0x000084a3 and add the missing -20 dB entry, bringing the table to the full 56 entries so index 55 (raw value 110, 0 dB) is in range again.
--- sound/soc/codecs/tas2562.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
sound/soc/codecs/tas2562.c +4 -3
@@ -32,15 +32,16 @@static const unsigned int float_vol_db_lookup[] = {0x00000d43 ,0x000010b2 ,0x00001505 ,0x00001a67 ,0x00002151 ,0x000029f1 ,0x000034cd ,0x00004279 ,0x000053af ,0x0000695b , -0x0000695b ,0x0000a6fa ,0x0000d236 ,0x000108a4 ,0x00014d2a , +0x000084a3 ,0x0000a6fa ,0x0000d236 ,0x000108a4 ,0x00014d2a ,0x0001a36e ,0x00021008 ,0x000298c0 ,0x000344df ,0x00041d8f ,0x00052e5a ,0x000685c8 ,0x00083621 ,0x000a566d ,0x000d03a7 ,0x0010624d ,0x0014a050 ,0x0019f786 ,0x0020b0bc ,0x0029279d ,0x0033cf8d ,0x004139d3 ,0x00521d50 ,0x00676044 ,0x0082248a ,0x00a3d70a ,0x00ce4328 ,0x0103ab3d ,0x0146e75d ,0x019b8c27 ,0x02061b89 ,0x028c423f ,0x03352529 ,0x0409c2b0 ,0x05156d68 , -0x080e9f96 ,0x0a24b062 ,0x0cc509ab ,0x10137987 ,0x143d1362 , -0x197a967f ,0x2013739e ,0x28619ae9 ,0x32d64617 ,0x40000000 +0x06666666 ,0x080e9f96 ,0x0a24b062 ,0x0cc509ab ,0x10137987 , +0x143d1362 ,0x197a967f ,0x2013739e ,0x28619ae9 ,0x32d64617 , +0x40000000 };struct tas2562_data {