7.0.10-rc1 review
Subsystems (6)
Greg Kroah-Hartman
maintainerPATCH 1025/1146 ice: fix infinite recursion in ice_cfg_tx_topo via ice_init_dev_hw
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 70ad216411e030f67b1743774e245601194aee6a ]
On certain E810 configurations where firmware supports Tx scheduler topology switching (tx_sched_topo_comp_mode_en), ice_cfg_tx_topo() may need to apply a new 5-layer or 9-layer topology from the DDP package. If the AQ command to set the topology fails (e.g. due to invalid DDP data or firmware limitations), the global configuration lock must still be cleared via a CORER reset.
Commit 86aae43f21cf ("ice: don't leave device non-functional if Tx scheduler config fails") correctly fixed this by refactoring ice_cfg_tx_topo() to always trigger CORER after acquiring the global lock and re-initialize hardware via ice_init_hw() afterwards.
However, commit 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end of deinit paths") later moved ice_init_dev_hw() into ice_init_hw(), breaking the reinit path introduced by 86aae43f21cf. This creates an infinite recursive call chain:
ice_init_hw()
ice_init_dev_hw()
ice_cfg_tx_topo() # topology change needed
ice_deinit_hw()
ice_init_hw() # reinit after CORER
ice_init_dev_hw() # recurse
ice_cfg_tx_topo()
... # stack overflow
Fix by moving ice_init_dev_hw() back out of ice_init_hw() and calling it explicitly from ice_probe() and ice_devlink_reinit_up(). The third caller, ice_cfg_tx_topo(), intentionally does not need ice_init_dev_hw() during its reinit, it only needs the core HW reinitialization. This breaks the recursion cleanly without adding flags or guards.
The deinit ordering changes from commit 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end of deinit paths") which fixed slow rmmod are preserved, only the init-side placement of ice_init_dev_hw() is reverted.
--- drivers/net/ethernet/intel/ice/devlink/devlink.c | 2 ++ drivers/net/ethernet/intel/ice/ice_common.c | 2 -- drivers/net/ethernet/intel/ice/ice_main.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/intel/ice/devlink/devlink.c +2 -0
@@ -1245,6 +1245,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf)return err; } +ice_init_dev_hw (pf); +/* load MSI-X values */ ice_set_min_max_msix (pf);
drivers/net/ethernet/intel/ice/ice_common.c +0 -2
@@ -1126,8 +1126,6 @@ int ice_init_hw(struct ice_hw *hw)if (status) goto err_unroll_fltr_mgmt_struct; -ice_init_dev_hw (hw->back); -mutex_init (&hw->tnl_lock);ice_init_chk_recipe_reuse_support (hw);
drivers/net/ethernet/intel/ice/ice_main.c +2 -0
@@ -5245,6 +5245,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)return err; } +ice_init_dev_hw (pf); + adapter =ice_adapter_get (pdev);if (IS_ERR (adapter)) { err =PTR_ERR (adapter);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1026/1146 ice: fix missing SMA pin initialization in DPLL subsystem
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 56a643aed0f0af5c29ebb4593d4917b78344dd48 ]
The DPLL SMA/U.FL pin redesign introduced ice_dpll_sw_pin_frequency_get() which gates frequency reporting on the pin's active flag. This flag is determined by ice_dpll_sw_pins_update() from the PCA9575 GPIO expander state. Before the redesign, SMA pins were exposed as direct HW input/output pins and ice_dpll_frequency_get() returned the CGU frequency unconditionally — the PCA9575 state was never consulted.
The PCA9575 powers on with all outputs high, setting ICE_SMA1_DIR_EN, ICE_SMA1_TX_EN, ICE_SMA2_DIR_EN and ICE_SMA2_TX_EN. Nothing in the driver writes the register during initialization, so ice_dpll_sw_pins_update() sees all pins as inactive and ice_dpll_sw_pin_frequency_get() permanently returns 0 Hz for every SW pin.
Fix this by writing a default SMA configuration in ice_dpll_init_info_sw_pins(): clear all SMA bits, then set SMA1 and SMA2 as active inputs (DIR_EN=0) with U.FL1 output and U.FL2 input disabled. Each SMA/U.FL pair shares a physical signal path so only one pin per pair can be active at a time. U.FL pins still report frequency 0 after this fix: U.FL1 (output-only) is disabled by ICE_SMA1_TX_EN which keeps the TX output buffer off, and U.FL2 (input-only) is disabled by ICE_SMA2_UFL2_RX_DIS. They can be activated by changing the corresponding SMA pin direction via dpll netlink.
--- drivers/net/ethernet/intel/ice/ice_dpll.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
drivers/net/ethernet/intel/ice/ice_dpll.c +17 -0
@@ -4014,6 +4014,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)struct ice_dpll_pin *pin;u32 phase_adj_max, caps;int i, ret; +u8 data;if (pf->hw.device_id ==ICE_DEV_ID_E810C_QSFP ) input_idx_offset =ICE_E810_RCLK_PINS_NUM ;
@@ -4073,6 +4074,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) }ice_dpll_phase_range_set (&pin->prop.phase_range, phase_adj_max); } + +/* Initialize the SMA control register to a known-good default state. +* Without this write the PCA9575 GPIO expander retains its power-on +* default (all outputs high) which makes all SW pins appear inactive. +* Set SMA1 and SMA2 as active inputs, disable U.FL1 output and +* U.FL2 input. +*/ + ret =ice_read_sma_ctrl (&pf->hw, &data); +if (ret) +return ret; + data &= ~ICE_ALL_SMA_MASK ; + data |=ICE_SMA1_TX_EN |ICE_SMA2_TX_EN |ICE_SMA2_UFL2_RX_DIS ; + ret =ice_write_sma_ctrl (&pf->hw, data); +if (ret) +return ret; + ret =ice_dpll_pin_state_update (pf, pin,ICE_DPLL_PIN_TYPE_SOFTWARE ,NULL );if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1027/1146 ice: fix SMA and U.FL pin state changes affecting paired pin
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 6f9d8393c9f50fbc68b9c9e99f78ca5a7b43ff44 ]
SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and SMA2/U.FL2) controlled by the PCA9575 GPIO expander. Each pair can only have one active pin at a time: SMA1 output and U.FL1 output share the same CGU output, SMA2 input and U.FL2 input share the same CGU input. The PCA9575 register bits determine which connector in each pair owns the signal path.
The driver does not account for this pairing in two places:
ice_dpll_ufl_pin_state_set() modifies PCA9575 bits and disables the backing CGU pin without checking whether the U.FL pin is currently active. Disconnecting an already inactive U.FL pin flips bits that the paired SMA pin relies on, breaking its connection.
ice_dpll_sma_direction_set() does not propagate direction changes to the paired U.FL pin. For SMA2/U.FL2 the ICE_SMA2_UFL2_RX_DIS bit is never managed, so U.FL2 stays disconnected after SMA2 switches to output. For both pairs the backing CGU pin of the U.FL side is never enabled when a direction change activates it, so userspace sees the pin as disconnected even though the routing is correct.
Fix by guarding the U.FL disconnect path against inactive pins and by updating the paired U.FL pin fully on SMA direction changes: manage ICE_SMA2_UFL2_RX_DIS for the SMA2/U.FL2 pair and enable the backing CGU pin whenever the peer becomes active.
--- drivers/net/ethernet/intel/ice/ice_dpll.c | 50 ++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_dpll.c +49 -1
@@ -1171,6 +1171,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,enum dpll_pin_direction direction, struct netlink_ext_ack *extack) { + struct ice_dplls *d = &p->pf->dplls; +struct ice_dpll_pin *peer;u8 data;int ret;
@@ -1189,8 +1191,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,case ICE_DPLL_PIN_SW_2_IDX :if (direction ==DPLL_PIN_DIRECTION_INPUT ) { data &= ~ICE_SMA2_DIR_EN ; + data |=ICE_SMA2_UFL2_RX_DIS ; }else { - data &= ~ICE_SMA2_TX_EN ; + data &= ~(ICE_SMA2_TX_EN |ICE_SMA2_UFL2_RX_DIS ); data |=ICE_SMA2_DIR_EN ; }break ;
@@ -1202,6 +1205,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, ret =ice_dpll_pin_state_update (p->pf, p,ICE_DPLL_PIN_TYPE_SOFTWARE , extack); +if (ret) +return ret; + +/* When a direction change activates the paired U.FL pin, enable +* its backing CGU pin so the pin reports as connected. Without +* this the U.FL routing is correct but the CGU pin stays disabled +* and userspace sees the pin as disconnected. Do not disable the +* backing pin when U.FL becomes inactive because the SMA pin may +* still be using it. +*/ + peer = &d->ufl[p->idx]; +if (peer->active) { +struct ice_dpll_pin *target; +enum ice_dpll_pin_type type; + +if (peer->output) { + target = peer->output; + type =ICE_DPLL_PIN_TYPE_OUTPUT ; + }else { + target = peer->input; + type =ICE_DPLL_PIN_TYPE_INPUT ; + } + ret =ice_dpll_pin_enable (&p->pf->hw, target, + d->eec.dpll_idx, type, extack); +if (!ret) + ret =ice_dpll_pin_state_update (p->pf, target, + type, extack); + }return ret; }
@@ -1253,6 +1284,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, data &= ~ICE_SMA1_MASK ; enable = true; }else if (state ==DPLL_PIN_STATE_DISCONNECTED ) { +/* Skip if U.FL1 is not active, setting TX_EN +* while DIR_EN is set would also deactivate +* the paired SMA1 output. +*/ +if (data & (ICE_SMA1_DIR_EN |ICE_SMA1_TX_EN )) { + ret =0 ; + goto unlock; + } data |=ICE_SMA1_TX_EN ; enable = false; }else {
@@ -1267,6 +1306,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, data &= ~ICE_SMA2_UFL2_RX_DIS ; enable = true; }else if (state ==DPLL_PIN_STATE_DISCONNECTED ) { +/* Skip if U.FL2 is not active, setting +* UFL2_RX_DIS could also disable the paired +* SMA2 input. +*/ +if (!(data &ICE_SMA2_DIR_EN ) || + (data &ICE_SMA2_UFL2_RX_DIS )) { + ret =0 ; + goto unlock; + } data |=ICE_SMA2_UFL2_RX_DIS ; enable = false; }else {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1028/1146 ice: fix missing dpll notifications for SW pins
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 1a41b58fd4dc80dca16c717e6e77c88b9d4e83a7 ]
The SMA/U.FL pin redesign (commit 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control")) introduced software-controlled pins that wrap backing CGU input/output pins, but never updated the notification and data paths to propagate pin events to these SW wrappers.
The periodic work sends dpll_pin_change_ntf() only for direct CGU input pins. SW pins that wrap these inputs never receive change or phase offset notifications, so userspace consumers such as synce4l monitoring SMA pins via dpll netlink never learn about state transitions or phase offset updates. Similarly, ice_dpll_phase_offset_get() reads the SW pin's own phase_offset field which is never updated; the PPS monitor writes to the backing CGU input's field instead.
Fix by introducing ice_dpll_pin_ntf(), a wrapper around dpll_pin_change_ntf() that also notifies any registered SMA/U.FL pin whose backing CGU input matches. Replace all direct dpll_pin_change_ntf() calls in the periodic notification paths with this wrapper. Fix ice_dpll_phase_offset_get() to return the backing CGU input's phase_offset for input-direction SW pins.
--- drivers/net/ethernet/intel/ice/ice_dpll.c | 47 +++++++++++++++++------ 1 file changed, 36 insertions(+), 11 deletions(-)
drivers/net/ethernet/intel/ice/ice_dpll.c +36 -11
@@ -1963,7 +1963,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv, d->active_input == p->input->pin)) *phase_offset = d->phase_offset *ICE_DPLL_PHASE_OFFSET_FACTOR ; else if (d->phase_offset_monitor_period) - *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; + *phase_offset = (p->input && + p->direction ==DPLL_PIN_DIRECTION_INPUT ? + p->input->phase_offset : + p->phase_offset) *ICE_DPLL_PHASE_OFFSET_FACTOR ; else *phase_offset =0 ;mutex_unlock (&pf->dplls.lock);
@@ -2657,6 +2660,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)return pci_get_dsn (pf->pdev); } +/** +* ice_dpll_pin_ntf - notify pin change including any SW pin wrappers +* @dplls: pointer to dplls struct +* @pin: the dpll_pin that changed +* +* Send a change notification for @pin and for any registered SMA/U.FL pin +* whose backing CGU input matches @pin. +*/ +static void ice_dpll_pin_ntf (struct ice_dplls *dplls,struct dpll_pin *pin) +{ +dpll_pin_change_ntf (pin); +for (int i =0 ; i <ICE_DPLL_PIN_SW_NUM ; i++) { +if (dplls->sma[i].pin && dplls->sma[i].input && + dplls->sma[i].input->pin == pin) +dpll_pin_change_ntf (dplls->sma[i].pin); +if (dplls->ufl[i].pin && dplls->ufl[i].input && + dplls->ufl[i].input->pin == pin) +dpll_pin_change_ntf (dplls->ufl[i].pin); + } +} +/** * ice_dpll_notify_changes - notify dpll subsystem about changes * @d: pointer do dpll
@@ -2665,6 +2689,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)*/ static void ice_dpll_notify_changes (struct ice_dpll *d) { +struct ice_dplls *dplls = &d->pf->dplls;bool pin_notified = false;if (d->prev_dpll_state != d->dpll_state) {
@@ -2673,17 +2698,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) }if (d->prev_input != d->active_input) {if (d->prev_input) -dpll_pin_change_ntf (d->prev_input); +ice_dpll_pin_ntf (dplls, d->prev_input); d->prev_input = d->active_input;if (d->active_input) { -dpll_pin_change_ntf (d->active_input); +ice_dpll_pin_ntf (dplls, d->active_input); pin_notified = true; } }if (d->prev_phase_offset != d->phase_offset) { d->prev_phase_offset = d->phase_offset;if (!pin_notified && d->active_input) -dpll_pin_change_ntf (d->active_input); +ice_dpll_pin_ntf (dplls, d->active_input); } }
@@ -2712,6 +2737,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)/** * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes +* @dplls: pointer to dplls struct * @pins: array of ice_dpll_pin pointers registered within dpll subsystem * @pin_num: number of pins * @phase_offset_ntf_mask: bitmask of pin indexes to notify
@@ -2721,15 +2747,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)* * Context: Must be called while pf->dplls.lock is released. */ -static void ice_dpll_pins_notify_mask (struct ice_dpll_pin *pins, +static void ice_dpll_pins_notify_mask (struct ice_dplls *dplls, +struct ice_dpll_pin *pins,u8 pin_num,u32 phase_offset_ntf_mask) { -int i =0 ; - -for (i =0 ; i < pin_num; i++) -if (phase_offset_ntf_mask & (1 << i)) -dpll_pin_change_ntf (pins[i].pin); +for (int i =0 ; i < pin_num; i++) +if (phase_offset_ntf_mask &BIT (i)) +ice_dpll_pin_ntf (dplls, pins[i].pin); }/**
@@ -2905,7 +2930,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work)ice_dpll_notify_changes (de);ice_dpll_notify_changes (dp);if (phase_offset_ntf) -ice_dpll_pins_notify_mask (d->inputs, d->num_inputs, +ice_dpll_pins_notify_mask (d, d->inputs, d->num_inputs, phase_offset_ntf); resched:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1029/1146 dpll: export __dpll_pin_change_ntf() for use under dpll_lock
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Vecera <[email protected]>
[ Upstream commit 620055cb1036a6125fd912e7a14b47a6572b809b ]
Export __dpll_pin_change_ntf() so that drivers can send pin change notifications from within pin callbacks, which are already called under dpll_lock. Using dpll_pin_change_ntf() in that context would deadlock.
Add lockdep_assert_held() to catch misuse without the lock held.
Stable-dep-of: 9e5dead140af ("ice: add dpll peer notification for paired SMA and U.FL pins")
--- drivers/dpll/dpll_netlink.c | 10 ++++++++++ drivers/dpll/dpll_netlink.h | 2 -- include/linux/dpll.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-)
drivers/dpll/dpll_netlink.c +10 -0
@@ -842,11 +842,21 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin)return dpll_pin_event_send (DPLL_CMD_PIN_DELETE_NTF , pin); } +/** +* __dpll_pin_change_ntf - notify that the pin has been changed +* @pin: registered pin pointer +* +* Context: caller must hold dpll_lock. Suitable for use inside pin +* callbacks which are already invoked under dpll_lock. +* Return: 0 if succeeds, error code otherwise. +*/ int __dpll_pin_change_ntf (struct dpll_pin *pin) { +lockdep_assert_held (&dpll_lock);dpll_pin_notify (pin,DPLL_PIN_CHANGED );return dpll_pin_event_send (DPLL_CMD_PIN_CHANGE_NTF , pin); } +EXPORT_SYMBOL_GPL (__dpll_pin_change_ntf);/** * dpll_pin_change_ntf - notify that the pin has been changed
drivers/dpll/dpll_netlink.h +0 -2
@@ -11,5 +11,3 @@ int dpll_device_delete_ntf(struct dpll_device *dpll);int dpll_pin_create_ntf (struct dpll_pin *pin);int dpll_pin_delete_ntf (struct dpll_pin *pin); - -int __dpll_pin_change_ntf (struct dpll_pin *pin);
include/linux/dpll.h +1 -0
@@ -276,6 +276,7 @@ int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin,int dpll_device_change_ntf (struct dpll_device *dpll); +int __dpll_pin_change_ntf (struct dpll_pin *pin);int dpll_pin_change_ntf (struct dpll_pin *pin);int register_dpll_notifier (struct notifier_block *nb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1030/1146 ice: add dpll peer notification for paired SMA and U.FL pins
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 9e5dead140af10e8b5f975b8f04e46197d48d274 ]
SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and SMA2/U.FL2). When one pin's state changes via a PCA9575 GPIO write, the paired pin's state also changes, but no notification is sent for the peer pin. Userspace consumers monitoring the peer via dpll netlink subscribe never learn about the update.
Add ice_dpll_sw_pin_notify_peer() which sends a change notification for the paired SW pin. Call it from ice_dpll_pin_sma_direction_set(), ice_dpll_sma_pin_state_set(), and ice_dpll_ufl_pin_state_set() after pf->dplls.lock is released. Use __dpll_pin_change_ntf() because dpll_lock is still held by the dpll netlink layer (dpll_pin_pre_doit).
--- drivers/net/ethernet/intel/ice/ice_dpll.c | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+)
drivers/net/ethernet/intel/ice/ice_dpll.c +32 -0
@@ -1154,6 +1154,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, extack, ICE_DPLL_PIN_TYPE_INPUT); } +/** +* ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change +* @d: pointer to dplls struct +* @changed: the SW pin that was explicitly changed (already notified by dpll core) +* +* SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and +* SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO +* expander, the paired pin's state may also change. Send a change +* notification for the peer pin so userspace consumers monitoring the +* peer via dpll netlink learn about the update. +* +* Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is +* released. Uses __dpll_pin_change_ntf() because dpll_lock is +* still held by the dpll netlink layer. +*/ +static void ice_dpll_sw_pin_notify_peer (struct ice_dplls *d, +struct ice_dpll_pin *changed) +{ +struct ice_dpll_pin *peer; + + peer = (changed >= d->sma && changed < d->sma +ICE_DPLL_PIN_SW_NUM ) ? + &d->ufl[changed->idx] : &d->sma[changed->idx]; +if (peer->pin) +__dpll_pin_change_ntf (peer->pin); +} +/** * ice_dpll_sma_direction_set - set direction of SMA pin * @p: pointer to a pin
@@ -1344,6 +1370,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, unlock:mutex_unlock (&pf->dplls.lock); +if (!ret) +ice_dpll_sw_pin_notify_peer (&pf->dplls, p);return ret; }
@@ -1462,6 +1490,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv, unlock:mutex_unlock (&pf->dplls.lock); +if (!ret) +ice_dpll_sw_pin_notify_peer (&pf->dplls, sma);return ret; }
@@ -1657,6 +1687,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv,mutex_lock (&pf->dplls.lock); ret =ice_dpll_sma_direction_set (p, direction, extack);mutex_unlock (&pf->dplls.lock); +if (!ret) +ice_dpll_sw_pin_notify_peer (&pf->dplls, p);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1031/1146 net: tls: fix strparser anchor skb leak on offload RX setup failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit 58689498ca3384851145a754dbb1d8ed1cf9fb54 ]
When tls_set_device_offload_rx() fails at tls_dev_add(), the error path calls tls_sw_free_resources_rx() to clean up the SW context that was initialized by tls_set_sw_offload(). This function calls tls_sw_release_resources_rx() (which stops the strparser via tls_strp_stop()) and tls_sw_free_ctx_rx() (which kfrees the context), but never frees the anchor skb that was allocated by alloc_skb(0) in tls_strp_init().
Note that tls_sw_free_resources_rx() is exclusively used for this "failed to start offload" code path, there's no other caller.
The leak did not exist before commit 84c61fe1a75b ("tls: rx: do not use the standard strparser"), because the standard strparser doesn't try to pre-allocate an skb.
The normal close path in tls_sk_proto_close() handles cleanup by calling tls_sw_strparser_done() (which calls tls_strp_done()) after dropping the socket lock, because tls_strp_done() does cancel_work_sync() and the strparser work handler takes the socket lock.
--- net/tls/tls.h | 1 + net/tls/tls_strp.c | 6 ++++++ net/tls/tls_sw.c | 4 ++++ 3 files changed, 11 insertions(+)
net/tls/tls.h +1 -0
@@ -188,6 +188,7 @@ int tls_strp_dev_init(void);void tls_strp_dev_exit (void );void tls_strp_done (struct tls_strparser *strp); +void __tls_strp_done (struct tls_strparser *strp);void tls_strp_stop (struct tls_strparser *strp);int tls_strp_init (struct tls_strparser *strp,struct sock *sk);void tls_strp_data_ready (struct tls_strparser *strp);
net/tls/tls_strp.c +6 -0
@@ -624,6 +624,12 @@ void tls_strp_done(struct tls_strparser *strp)WARN_ON (!strp->stopped);cancel_work_sync (&strp->work); +__tls_strp_done (strp); +} + +/* For setup error paths where the strparser was initialized but never armed. */ +void __tls_strp_done (struct tls_strparser *strp) +{tls_strp_anchor_free (strp); }
net/tls/tls_sw.c +4 -0
@@ -2625,8 +2625,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx)void tls_sw_free_resources_rx (struct sock *sk) {struct tls_context *tls_ctx =tls_get_ctx (sk); +struct tls_sw_context_rx *ctx; + + ctx =tls_sw_ctx_rx (tls_ctx);tls_sw_release_resources_rx (sk); +__tls_strp_done (&ctx->strp);tls_sw_free_ctx_rx (tls_ctx); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1032/1146 sfc: fix error code in efx_devlink_info_running_versions()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 051ffb001b8a232cfa6e72f38bb5f51c4270a60b ]
Return -EIO if efx_mcdi_rpc() doesn't return enough space.
--- drivers/net/ethernet/sfc/efx_devlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/sfc/efx_devlink.c +1 -1
@@ -531,7 +531,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx,if (rc || outlength <MC_CMD_GET_VERSION_OUT_LEN ) {netif_err (efx, drv, efx->net_dev,"mcdi MC_CMD_GET_VERSION failed\n" ); -return rc; +return rc ?: -EIO ; }/* Handle previous output */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1033/1146 net/sched: cls_flower: revert unintended changes
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
[ Upstream commit 1e01abec856593e02cd69fd95b784c10dd46880c ]
While applying the blamed commit 4ca07b9239bd ("net: mctp i2c: check length before marking flow active"), I unintentionally included unrelated and unacceptable changes.
Revert them.
--- net/sched/cls_flower.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
net/sched/cls_flower.c +1 -3
@@ -560,7 +560,6 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, struct netlink_ext_ack *extack) {struct cls_fl_head *head =fl_head_dereference (tp); -struct fl_flow_mask *mask; *last = false;
@@ -577,12 +576,11 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,list_del_rcu (&f->list);spin_unlock (&tp->lock); - mask = f->mask; + *last =fl_mask_put (head, f->mask);if (!tc_skip_hw (f->flags))fl_hw_destroy_filter (tp, f, rtnl_held, extack);tcf_unbind_filter (tp, &f->res);__fl_put (f); - *last =fl_mask_put (head, mask);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1034/1146 kselftest/arm64: Include <asm/ptrace.h> for user_gcs definition
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan <[email protected]>
[ Upstream commit bb7235e226888607e6aac1288062fcb1ac105589 ]
kselftest includes kernel uAPI headers with option:
-isystem $(top_srcdir)/usr/include
Include <asm/ptrace.h> in libc-gcs.c for the definition of struct user_gcs from the uAPI headers, and remove the redundant definition in gcs-util.h. This fixes a compilation error on systems where the toolchain defines NT_ARM_GCS.
--- tools/testing/selftests/arm64/gcs/gcs-util.h | 6 ------ tools/testing/selftests/arm64/gcs/libc-gcs.c | 1 + 2 files changed, 1 insertion(+), 6 deletions(-)
tools/testing/selftests/arm64/gcs/gcs-util.h +0 -6
@@ -18,12 +18,6 @@#ifndef NT_ARM_GCS #define NT_ARM_GCS 0x410 - -struct user_gcs { -__u64 features_enabled; -__u64 features_locked; -__u64 gcspr_el0; -};#endif /* Shadow Stack/Guarded Control Stack interface */
tools/testing/selftests/arm64/gcs/libc-gcs.c +1 -0
@@ -16,6 +16,7 @@#include <asm/hwcap.h> #include <asm/mman.h> +#include <asm/ptrace.h> #include <linux/compiler.h>
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1035/1146 arm64: Reserve an extra page for early kernel mapping
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhaoyang Huang <[email protected]>
[ Upstream commit 4d8e74ad4585672489da6145b3328d415f50db82 ]
The final part of [data, end) segment may overflow into the next page of init_pg_end[1] which is the gap page before early_init_stack[2]:
[1]
crash_arm64_v9.0.1> vtop ffffffed00601000
VIRTUAL PHYSICALffffffed00601000 83401000
PAGE DIRECTORY: ffffffecffd62000
PGD: ffffffecffd62da0 => 10000000833fb003
PMD: ffffff80033fb018 => 10000000833fe003
PTE: ffffff80033fe008 => 68000083401f03
PAGE: 83401000
PTE PHYSICAL FLAGS 68000083401f03 83401000 (VALID|SHARED|AF|NG|PXN|UXN)
PAGE PHYSICAL MAPPING INDEX CNT FLAGSfffffffec00d0040 83401000 0 0 1 4000 reserved
[2]ffffffed002c8000 (r) __pi__dataffffffed0054e000 (d) __pi___bss_startffffffed005f5000 (b) __pi_init_pg_dirffffffed005fe000 (b) __pi_init_pg_endffffffed005ff000 (B) early_init_stackffffffed00608000 (b) __pi__end
For 4K pages, the early kernel mapping may use 2MB block entries but the kernel segments are only 64KB aligned. Segment boundaries that fall within a 2MB block therefore require a PTE table so that different attributes can be applied on either side of the boundary.
KERNEL_SEGMENT_COUNT still correctly counts the five permanent kernel VMAs registered by declare_kernel_vmas(). However, since commit 5973a62efa34 ("arm64: map [_text, _stext) virtual address range non-executable+read-only"), the early mapper also maps [_text, _stext) separately from [_stext, _etext). This adds one more early-only split and can require one more page-table page than the existing EARLY_SEGMENT_EXTRA_PAGES allowance reserves.
Increase the 4K-page early mapping allowance by one page to cover that additional split.
--- arch/arm64/include/asm/kernel-pgtable.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/arm64/include/asm/kernel-pgtable.h +6 -1
@@ -68,7 +68,12 @@#define KERNEL_SEGMENT_COUNT 5#if SWAPPER_BLOCK_SIZE >SEGMENT_ALIGN -#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 1) +/* +* KERNEL_SEGMENT_COUNT counts the permanent kernel VMAs. The early mapping +* has one additional split, [_text, _stext). Reserve one more page for the +* SWAPPER_BLOCK_SIZE-unaligned boundaries. +*/ +#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 2)/* * The initial ID map consists of the kernel image, mapped as two separate * segments, and may appear misaligned wrt the swapper block size. This means
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1036/1146 futex: Drop CLONE_THREAD requirement for private default hash alloc
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Davidlohr Bueso <[email protected]>
[ Upstream commit ee9dce44362b2d8132c32964656ab6dff7dfbc6a ]
Currently need_futex_hash_allocate_default() depends on strict pthread semantics, abusing CLONE_THREAD. This breaks the non-concurrency assumptions when doing the mm->futex_ref pcpu allocations, leading to bugs[0] when sharing the mm in other ways; ie:
BUG: KASAN: slab-use-after-free in futex_hash_put
... where the +1 bias can end up on a percpu counter that mm->futex_ref no longer points at.
Loosen the check to cover any CLONE_VM clone, except vfork(). Excluding vfork keeps the existing paths untouched (no overhead), and we can't race in the first place: either the parent is suspended and the child runs alone, or mm->futex_ref is already allocated from an earlier CLONE_VM.
--- kernel/fork.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
kernel/fork.c +5 -7
@@ -1949,9 +1949,11 @@ static void rv_task_fork(struct task_struct *p)static bool need_futex_hash_allocate_default (u64 clone_flags) { -if ((clone_flags & (CLONE_THREAD |CLONE_VM )) != (CLONE_THREAD |CLONE_VM )) -return false; -return true; +/* +* Allocate a default futex hash for any sibling that will +* share the parent's mm, except vfork. +*/ +return (clone_flags & (CLONE_VM |CLONE_VFORK )) ==CLONE_VM ; }/*
@@ -2338,10 +2340,6 @@ __latent_entropy struct task_struct *copy_process(if (retval) goto bad_fork_cancel_cgroup; -/* -* Allocate a default futex hash for the user process once the first -* thread spawns. -*/ if (need_futex_hash_allocate_default (clone_flags)) { retval =futex_hash_allocate_default ();if (retval)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1037/1146 PCI: Initialize temporary device in new_id_store()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samiullah Khawaja <[email protected]>
[ Upstream commit f45a49a2380a47332817b7248c61a0ebbc6f0d00 ]
When setting new_id of a PCI device driver using sysfs a lockdep splat occurs. This is because new_id_store() builds a temporary pci_dev for pci_match_device(), which calls device_match_driver_override(). That depends on the driver_override.lock added by cb3d1049f4ea ("driver core:
generalize driver_override in struct device").
The new driver_override.lock was not initialized in the temporary pci_dev, resulting in this lockdep splat.
Initialize the temporary pci_dev to fix this.
Repro:
Build with CONFIG_LOCKDEP=y, boot with QEMU, and add a new ID:
# echo "8086 10f5" > /sys/bus/pci/drivers/e1000e/new_id
INFO: trying to register non-static key.
The code is fine but needs lockdep annotation, or maybe you didn't initialize this object before use? turning off the locking correctness validator.
CPU: 2 UID: 0 PID: 177 Comm: liveupdate-iomm Not tainted 7.0.0+ #9 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x5d/0x80 register_lock_class+0x77e/0x790 lock_acquire+0xbf/0x2e0 pci_match_device+0x24/0x180 new_id_store+0x189/0x1d0 kernfs_fop_write_iter+0x14f/0x210 vfs_write+0x263/0x5e0 ksys_write+0x79/0xf0 do_syscall_64+0x117/0xf80
--- drivers/pci/pci-driver.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/pci/pci-driver.c +8 -1
@@ -179,6 +179,11 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,return NULL ; } +static void _pci_free_device (struct device *dev) +{ +kfree (to_pci_dev (dev)); +} +/** * new_id_store - sysfs frontend to pci_add_dynid() * @driver: target device driver
@@ -214,11 +219,13 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf, pdev->subsystem_vendor = subvendor; pdev->subsystem_device = subdevice; pdev->class = class; + pdev->dev.release = _pci_free_device; +device_initialize (&pdev->dev);if (pci_match_device (pdrv, pdev)) retval = -EEXIST ; -kfree (pdev); +put_device (&pdev->dev);if (retval)return retval;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1038/1146 workqueue: fix devm_alloc_workqueue() va_list misuse
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 0de4cb473aed57ee4ba7e0551ad27bddc19fc519 ]
devm_alloc_workqueue() built a va_list and passed it as a single positional argument to the variadic alloc_workqueue() macro:
va_start(args, max_active); wq = alloc_workqueue(fmt, flags, max_active, args); va_end(args);
C does not allow forwarding a va_list through a ... parameter. alloc_workqueue() expands to alloc_workqueue_noprof(), which runs its own va_start() over its ... params, so the inner vsnprintf(wq->name, sizeof(wq->name), fmt, args) in __alloc_workqueue() received the outer va_list object as the first variadic slot rather than the caller's actual format arguments.
Add a new static helper alloc_workqueue_va() that wraps __alloc_workqueue() and runs wq_init_lockdep() on success, and fold both alloc_workqueue_noprof() and devm_alloc_workqueue_noprof() onto it as suggested by Tejun.
The wq_init_lockdep() step is required on the devm path too, otherwise __flush_workqueue()'s on-stack COMPLETION_INITIALIZER_ONSTACK_MAP would NULL-deref wq->lockdep_map.
No caller changes are required. devm_alloc_ordered_workqueue() is a macro forwarding to devm_alloc_workqueue() and inherits the fix. Two in-tree callers actively trigger the broken path on every probe:
drivers/power/supply/mt6370-charger.c:889
drivers/power/supply/max77705_charger.c:649
both of which use devm_alloc_ordered_workqueue(dev, "%s", 0, dev_name(dev)).
A standalone reproducer module is available at[1].
--- include/linux/workqueue.h | 6 ++++-- kernel/workqueue.c | 28 +++++++++++++++++++--------- 2 files changed, 23 insertions(+), 11 deletions(-)
include/linux/workqueue.h +4 -2
@@ -529,8 +529,10 @@ alloc_workqueue_noprof(const char *fmt, unsigned int flags, int max_active, ...)* Pointer to the allocated workqueue on success, %NULL on failure. */ __printf(2, 5) struct workqueue_struct * -devm_alloc_workqueue (struct device *dev,const char *fmt,unsigned int flags, -int max_active, ...); +devm_alloc_workqueue_noprof (struct device *dev,const char *fmt, +unsigned int flags,int max_active, ...); +#define devm_alloc_workqueue (...) \ + alloc_hooks(devm_alloc_workqueue_noprof(__VA_ARGS__))#ifdef CONFIG_LOCKDEP /**
kernel/workqueue.c +19 -9
@@ -5885,6 +5885,20 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,return NULL ; } +static struct workqueue_struct *alloc_workqueue_va (const char *fmt, +unsigned int flags, +int max_active, +va_list args) +{ +struct workqueue_struct *wq; + + wq =__alloc_workqueue (fmt, flags, max_active, args); +if (wq) +wq_init_lockdep (wq); + +return wq; +} + __printf(1, 4) struct workqueue_struct *alloc_workqueue_noprof(const char *fmt, unsigned int flags,
@@ -5894,12 +5908,8 @@ struct workqueue_struct *alloc_workqueue_noprof(const char *fmt,va_list args;va_start (args, max_active); - wq =__alloc_workqueue (fmt, flags, max_active, args); + wq =alloc_workqueue_va (fmt, flags, max_active, args);va_end (args); -if (!wq) -return NULL ; - -wq_init_lockdep (wq);return wq; }
@@ -5911,15 +5921,15 @@ static void devm_workqueue_release(void *res) } __printf(2, 5) struct workqueue_struct * -devm_alloc_workqueue (struct device *dev,const char *fmt,unsigned int flags, -int max_active, ...) +devm_alloc_workqueue_noprof (struct device *dev,const char *fmt, +unsigned int flags,int max_active, ...) {struct workqueue_struct *wq;va_list args;int ret;va_start (args, max_active); - wq =alloc_workqueue (fmt, flags, max_active, args); + wq =alloc_workqueue_va (fmt, flags, max_active, args);va_end (args);if (!wq)return NULL ;
@@ -5930,7 +5940,7 @@ devm_alloc_workqueue(struct device *dev, const char *fmt, unsigned int flags,return wq; } -EXPORT_SYMBOL_GPL (devm_alloc_workqueue); +EXPORT_SYMBOL_GPL (devm_alloc_workqueue_noprof);#ifdef CONFIG_LOCKDEP __printf (1 ,5 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1039/1146 net/sched: sch_pie: annotate more data-races in pie_dump_stats()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 6d4106e8df94c0c52cf3ca6a6a0d01567fb3844e ]
My prior patch missed few READ_ONCE()/WRITE_ONCE() annotations.
--- net/sched/sch_pie.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
net/sched/sch_pie.c +6 -8
@@ -219,16 +219,14 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params,* packet timestamp. */ if (!params->dq_rate_estimator) { - vars->qdelay = now -pie_get_enqueue_time (skb); +WRITE_ONCE (vars->qdelay, + backlog ? now -pie_get_enqueue_time (skb) :0 );if (vars->dq_tstamp !=DTIME_INVALID ) dtime = now - vars->dq_tstamp; vars->dq_tstamp = now; -if (backlog ==0 ) - vars->qdelay =0 ; -if (dtime ==0 )return ;
@@ -376,7 +374,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,if (qdelay > (PSCHED_NS2TICKS (250 *NSEC_PER_MSEC ))) delta +=MAX_PROB / (100 /2 ); - vars->prob += delta; +WRITE_ONCE (vars->prob, vars->prob + delta);if (delta >0 ) {/* prevent overflow */
@@ -401,7 +399,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,if (qdelay ==0 && qdelay_old ==0 && update_prob)/* Reduce drop probability to 98.4% */ - vars->prob -= vars->prob /64 ; +WRITE_ONCE (vars->prob, vars->prob - vars->prob /64 );WRITE_ONCE (vars->qdelay, qdelay); vars->backlog_old = backlog;
@@ -501,7 +499,7 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) {struct pie_sched_data *q =qdisc_priv (sch);struct tc_pie_xstats st = { - .prob = q->vars.prob <<BITS_PER_BYTE , + .prob =READ_ONCE (q->vars.prob) <<BITS_PER_BYTE , .delay = ((u32 )PSCHED_TICKS2NS (READ_ONCE (q->vars.qdelay))) /NSEC_PER_USEC , .packets_in =READ_ONCE (q->stats.packets_in),
@@ -512,7 +510,7 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) };/* avg_dq_rate is only valid if dq_rate_estimator is enabled */ - st.dq_rate_estimating = q->params.dq_rate_estimator; + st.dq_rate_estimating =READ_ONCE (q->params.dq_rate_estimator);/* unscale and return dq_rate in bytes per sec */ if (st.dq_rate_estimating)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1040/1146 sched/fair: Fix wakeup_preempt_fair() for not waking up task
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Guittot <[email protected]>
[ Upstream commit 9f6d929ee2c6f0266edb564bcd2bd47fd6e884a8 ]
Make sure to only call pick_next_entity() on an non-empty cfs_rq.
The assumption that p is always enqueued and not delayed, is only true for wakeup. If p was moved while delayed, pick_next_entity() will dequeue it and the cfs might become empty. Test if there are still queued tasks before trying again to determine if p could be the next one to be picked.
There are at least 2 cases:
When cfs becomes idle, it tries to pull tasks but if those pulled tasks are delayed, they will be dequeued when attached to cfs. attach_tasks() -> attach_task() -> wakeup_preempt(rq, p, 0);
A misfit task running on cfs A triggers a load balance to be pulled on a better cpu, the load balance on cfs B starts an active load balance to pulled the running misfit task. If there is a delayed dequeue task on cfs A, it can be pulled instead of the previously running misfit task. attach_one_task() -> attach_task() -> wakeup_preempt(rq, p, 0);
--- kernel/sched/fair.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/sched/fair.c +3 -2
@@ -8922,9 +8922,10 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f/* * Because p is enqueued, nse being null can only mean that we -* dequeued a delayed task. +* dequeued a delayed task. If there are still entities queued in +* cfs, check if the next one will be p. */ -if (!nse) +if (!nse && cfs_rq->nr_queued) goto pick;if (sched_feat (RUN_TO_PARITY ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1041/1146 crypto: af_alg - Cap AEAD AD length to 0x80000000
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Herbert Xu <[email protected]>
commit e4c06479d7059888adf2f22bc1ebcf053bf691a2 upstream.
In order to prevent arithmetic overflows when checking the TX buffer size, cap the associated data length to 0x80000000.
--- crypto/af_alg.c | 2 ++ 1 file changed, 2 insertions(+)
crypto/af_alg.c +2 -0
@@ -586,6 +586,8 @@ static int af_alg_cmsg_send(struct msghdif (cmsg->cmsg_len <CMSG_LEN (sizeof (u32)))return -EINVAL ; con->aead_assoclen = *(u32 *)CMSG_DATA (cmsg); +if (con->aead_assoclen >=0x80000000u ) +return -EINVAL ;break ;default :
Greg Kroah-Hartman
maintainerPATCH 1042/1146 i40e: Cleanup PTP pins on probe failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Vollrath <[email protected]>
commit 678b713ece1e853f11e670a84cb887c35e1381b7 upstream.
PTP pin structs are allocated early in probe, but never cleaned up.
Fix this by calling i40e_ptp_free_pins in the error path.
To support this, i40e_ptp_free_pins is added to the header and pin_config is correctly nullified after being freed.
This has been an issue since i40e_ptp_alloc_pins was introduced.
--- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + drivers/net/ethernet/intel/i40e/i40e_ptp.c | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/i40e/i40e.h +1 -0
@@ -1318,6 +1318,7 @@ void i40e_ptp_restore_hw_time(struct i40void i40e_ptp_init (struct i40e_pf *pf);void i40e_ptp_stop (struct i40e_pf *pf);int i40e_ptp_alloc_pins (struct i40e_pf *pf); +void i40e_ptp_free_pins (struct i40e_pf *pf);int i40e_update_adq_vsi_queues (struct i40e_vsi *vsi,int vsi_offset);int i40e_is_vsi_uplink_mode_veb (struct i40e_vsi *vsi);int i40e_get_partition_bw_setting (struct i40e_pf *pf);
drivers/net/ethernet/intel/i40e/i40e_main.c +1 -0
@@ -16111,6 +16111,7 @@ err_vsis:i40e_clear_interrupt_scheme (pf);kfree (pf->vsi); err_switch_setup: +i40e_ptp_free_pins (pf);i40e_reset_interrupt_capability (pf);timer_shutdown_sync (&pf->service_timer); err_mac_addr:
drivers/net/ethernet/intel/i40e/i40e_ptp.c +2 -1
@@ -940,12 +940,13 @@ int i40e_ptp_hwtstamp_get(struct net_dev* * Release memory allocated for PTP pins. **/ -static void i40e_ptp_free_pins (struct i40e_pf *pf) +void i40e_ptp_free_pins (struct i40e_pf *pf) {if (i40e_is_ptp_pin_dev (&pf->hw)) {kfree (pf->ptp_pins);kfree (pf->ptp_caps.pin_config); pf->ptp_pins =NULL ; + pf->ptp_caps.pin_config =NULL ; } }
Greg Kroah-Hartman
maintainerPATCH 1043/1146 workqueue: Fix wq->cpu_pwq leak in alloc_and_link_pwqs() WQ_UNBOUND path
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
commit 0143033dc22cdff912cfc13419f5db92fea3b4cb upstream.
For WQ_UNBOUND workqueues, alloc_and_link_pwqs() allocates wq->cpu_pwq via alloc_percpu() and then calls apply_workqueue_attrs_locked(). On failure it returns the error directly, bypassing the enomem: label which holds the only free_percpu(wq->cpu_pwq) in this function.
The caller's error path kfree()s wq without touching wq->cpu_pwq, leaking one percpu pointer table (nr_cpu_ids * sizeof(void *) bytes) per failed call.
If kmemleak is enabled, we can see:
unreferenced object (percpu) 0xc0fffa5b121048 (size 8):
comm "insmod", pid 776, jiffies 4294682844
backtrace (crc 0):
pcpu_alloc_noprof+0x665/0xac0
__alloc_workqueue+0x33f/0xa20
alloc_workqueue_noprof+0x60/0x100Route the error through the existing enomem: cleanup and any error before this one.
--- kernel/workqueue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/workqueue.c +3 -1
@@ -5629,7 +5629,9 @@ static int alloc_and_link_pwqs(struct wo ret =apply_workqueue_attrs_locked (wq, unbound_std_wq_attrs[highpri]); } -return ret; +if (ret) + goto enomem; +return 0 ; enomem:if (wq->cpu_pwq) {
Greg Kroah-Hartman
maintainerPATCH 1044/1146 net: ena: PHC: Fix potential use-after-free in get_timestamp
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arthur Kiyanovski <[email protected]>
commit e42c755582f0960e684298762f0ab927b3778376 upstream.
Move the phc->active check and resp pointer assignment to after acquiring the spinlock. Previously, phc->active was checked without holding the lock, and resp was cached from ena_dev->phc.virt_addr before the lock was acquired.
If ena_com_phc_destroy() runs between the lockless active check and the lock acquisition, it sets active=false, releases the lock, frees the DMA memory, and sets virt_addr=NULL. The get_timestamp path would then read a NULL virt_addr and dereference it.
With both the active check and the pointer read under the lock, destroy cannot free the memory while get_timestamp is using it.
--- drivers/net/ethernet/amazon/ena/ena_com.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/ethernet/amazon/ena/ena_com.c +5 -2
@@ -1782,20 +1782,23 @@ void ena_com_phc_destroy(struct ena_com_int ena_com_phc_get_timestamp (struct ena_com_dev *ena_dev,u64 *timestamp) { -volatile struct ena_admin_phc_resp *resp = ena_dev->phc.virt_addr;const ktime_t zero_system_time =ktime_set (0 ,0 );struct ena_com_phc_info *phc = &ena_dev->phc; +volatile struct ena_admin_phc_resp *resp;ktime_t expire_time;ktime_t block_time;unsigned long flags =0 ;int ret =0 ; +spin_lock_irqsave (&phc->lock, flags); +if (!phc->active) { +spin_unlock_irqrestore (&phc->lock, flags);netdev_err (ena_dev->net_device,"PHC feature is not active in the device\n" );return -EOPNOTSUPP ; } -spin_lock_irqsave (&phc->lock, flags); + resp = ena_dev->phc.virt_addr;/* Check if PHC is in blocked state */ if (unlikely (ktime_compare (phc->system_time, zero_system_time))) {
Greg Kroah-Hartman
maintainerPATCH 1045/1146 cgroup/cpuset: Reset DL migration state on can_attach() failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guopeng Zhang <[email protected]>
commit 4a39eda5fdd867fc39f3c039714dd432cee00268 upstream.
cpuset_can_attach() accumulates temporary SCHED_DEADLINE migration state in the destination cpuset while walking the taskset.
If a later task_can_attach() or security_task_setscheduler() check fails, cgroup_migrate_execute() treats cpuset as the failing subsystem and does not call cpuset_cancel_attach() for it. The partially accumulated state is then left behind and can be consumed by a later attach, corrupting cpuset DL task accounting and pending DL bandwidth accounting.
Reset the pending DL migration state from the common error exit when ret is non-zero. Successful can_attach() keeps the state for cpuset_attach() or cpuset_cancel_attach().
--- kernel/cgroup/cpuset.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
kernel/cgroup/cpuset.c +4 -4
@@ -3050,16 +3050,13 @@ static int cpuset_can_attach(struct cgroint cpu =cpumask_any_and (cpu_active_mask, cs->effective_cpus);if (unlikely (cpu >= nr_cpu_ids)) { -reset_migrate_dl_data (cs); ret = -EINVAL ; goto out_unlock; } ret =dl_bw_alloc (cpu, cs->sum_migrate_dl_bw); -if (ret) { -reset_migrate_dl_data (cs); +if (ret) goto out_unlock; - } cs->dl_bw_cpu = cpu; }
@@ -3070,7 +3067,10 @@ out_success:* changes which zero cpus/mems_allowed. */ cs->attach_in_progress++; + out_unlock: +if (ret) +reset_migrate_dl_data (cs);mutex_unlock (&cpuset_mutex);return ret; }
Greg Kroah-Hartman
maintainerPATCH 1046/1146 netfilter: nf_conntrack_sip: get helper before allocating expectation
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Xiasong <[email protected]>
commit eb6317739b1ea3ab28791e1f91b24781905fa815 upstream.
process_register_request() allocates an expectation and then checks whether a conntrack helper is available. If helper lookup fails, the function returns early and the allocated expectation is left behind.
Reorder the code to fetch and validate helper before calling nf_ct_expect_alloc(). This keeps the logic simpler and removes the leak path while preserving existing behavior.
--- net/netfilter/nf_conntrack_sip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/netfilter/nf_conntrack_sip.c +4 -4
@@ -1367,6 +1367,10 @@ static int process_register_request(stru goto store_cseq; } + helper =rcu_dereference (nfct_help (ct)->helper); +if (!helper) +return NF_DROP ; + exp =nf_ct_expect_alloc (ct);if (!exp) {nf_ct_helper_log (skb, ct,"cannot alloc expectation" );
@@ -1377,10 +1381,6 @@ static int process_register_request(struif (sip_direct_signalling) saddr = &ct->tuplehash[!dir].tuple.src.u3; - helper =rcu_dereference (nfct_help (ct)->helper); -if (!helper) -return NF_DROP ; -nf_ct_expect_init (exp,SIP_EXPECT_SIGNALLING ,nf_ct_l3num (ct), saddr, &daddr, proto,NULL , &port); exp->timeout.expires = sip_timeout *HZ ;
Greg Kroah-Hartman
maintainerPATCH 1047/1146 audit: fix incorrect inheritable capability in CAPSET records
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergio Correia <[email protected]>
commit e4a640475e43f406fdfd56d370b1f34b0cbbc18d upstream.
__audit_log_capset() records the effective capability set into the inheritable field due to a copy-paste error. Every CAPSET audit record therefore reports cap_pi (process inheritable) with the value of cap_effective instead of cap_inheritable.
This silently corrupts audit data used for compliance and forensic
analysis: an attacker who modifies inheritable capabilities to prepare for a privilege-escalating exec would have the change masked in the audit trail.
The bug has been present since the original introduction of CAPSET audit records in 2008.
--- kernel/auditsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/auditsc.c +1 -1
@@ -2786,7 +2786,7 @@ void __audit_log_capset(const struct cre context->capset.pid =task_tgid_nr (current); context->capset.cap.effective = new->cap_effective; - context->capset.cap.inheritable = new->cap_effective; + context->capset.cap.inheritable = new->cap_inheritable; context->capset.cap.permitted = new->cap_permitted; context->capset.cap.ambient = new->cap_ambient; context->type =AUDIT_CAPSET ;
Greg Kroah-Hartman
maintainerPATCH 1048/1146 net: ena: PHC: Check return code before setting timestamp output
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arthur Kiyanovski <[email protected]>
commit 24a08d7d6218d60c033015cf4870b6096446e734 upstream.
ena_phc_gettimex64() is setting the output parameter regardless of whether ena_com_phc_get_timestamp() succeeded or failed.
When ena_com_phc_get_timestamp() returns an error, the timestamp parameter may contain uninitialized stack memory (e.g., when PHC is disabled or in blocked state) or invalid hardware values. Passing these to userspace via the PTP ioctl is both a security issue (information leak) and a correctness bug.
Fix by checking the return code after releasing the lock and only setting the output timestamp on success.
--- drivers/net/ethernet/amazon/ena/ena_phc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/amazon/ena/ena_phc.c +4 -1
@@ -46,9 +46,12 @@ static int ena_phc_gettimex64(struct ptpspin_unlock_irqrestore (&phc_info->lock, flags); +if (rc) +return rc; + *ts =ns_to_timespec64 (timestamp_nsec); -return rc; +return 0 ; } static int ena_phc_settime64(struct ptp_clock_info *clock_info,
Greg Kroah-Hartman
maintainerPATCH 1049/1146 cgroup/dmem: Return -ENOMEM on failed pool preallocation
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guopeng Zhang <[email protected]>
commit 796ad622040f7f955ccc3973085e953415920496 upstream.
get_cg_pool_unlocked() handles allocation failures under dmemcg_lock by dropping the lock, preallocating a pool with GFP_KERNEL, and retrying the locked lookup and creation path.
If the fallback allocation fails too, pool remains NULL. Since the loop condition is while (!pool), the function can keep retrying instead of propagating the allocation failure to the caller.
Set pool to ERR_PTR(-ENOMEM) when the fallback allocation fails so the loop exits through the existing common return path. The callers already handle ERR_PTR() from get_cg_pool_unlocked(), so this restores the expected error path.
--- kernel/cgroup/dmem.c | 1 + 1 file changed, 1 insertion(+)
kernel/cgroup/dmem.c +1 -0
@@ -602,6 +602,7 @@ get_cg_pool_unlocked(struct dmemcg_state pool =NULL ;continue ; } + pool =ERR_PTR (-ENOMEM ); } }
Greg Kroah-Hartman
maintainerPATCH 1050/1146 idpf: fix double free and use-after-free in aux device error paths
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit 6c77b9510829a424d1b74409b7db9456e3522871 upstream.
When auxiliary_device_add() fails in idpf_plug_vport_aux_dev() or idpf_plug_core_aux_dev(), the err_aux_dev_add label calls auxiliary_device_uninit() and falls through to err_aux_dev_init. The uninit call will trigger put_device(), which invokes the release callback (idpf_vport_adev_release / idpf_core_adev_release) that frees iadev. The fall-through then reads adev->id from the freed iadev for ida_free() and double-frees iadev with kfree().
Free the IDA slot and clear the back-pointer before uninit, while adev is still valid, then return immediately.
Commit 65637c3a1811 ("idpf: fix UAF in RDMA core aux dev deinitialization") fixed the same use-after-free in the matching unplug path in this file but missed both probe error paths.
--- drivers/net/ethernet/intel/idpf/idpf_idc.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/ethernet/intel/idpf/idpf_idc.c +6 -0
@@ -90,7 +90,10 @@ static int idpf_plug_vport_aux_dev(strucreturn 0 ; err_aux_dev_add: +ida_free (&idpf_idc_ida, adev->id); + vdev_info->adev =NULL ;auxiliary_device_uninit (adev); +return ret; err_aux_dev_init:ida_free (&idpf_idc_ida, adev->id); err_ida_alloc:
@@ -228,7 +231,10 @@ static int idpf_plug_core_aux_dev(structreturn 0 ; err_aux_dev_add: +ida_free (&idpf_idc_ida, adev->id); + cdev_info->adev =NULL ;auxiliary_device_uninit (adev); +return ret; err_aux_dev_init:ida_free (&idpf_idc_ida, adev->id); err_ida_alloc:
Greg Kroah-Hartman
maintainerPATCH 1051/1146 cgroup/cpuset: Reserve DL bandwidth only for root-domain moves
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guopeng Zhang <[email protected]>
commit 5dd74441cbf42c22e874450eb6a6bbb19390a216 upstream.
cpuset_can_attach() currently adds the bandwidth of all migrating SCHED_DEADLINE tasks to sum_migrate_dl_bw. If the source and destination cpuset effective CPU masks do not overlap, the whole sum is then reserved in the destination root domain.
set_cpus_allowed_dl(), however, subtracts bandwidth from the source root domain only when the affinity change really moves the task between root domains. A DL task can move between cpusets that are still in the same root domain, so including that task in sum_migrate_dl_bw can reserve destination bandwidth without a matching source-side subtraction.
Share the root-domain move test with set_cpus_allowed_dl(). Keep nr_migrate_dl_tasks counting all migrating deadline tasks for cpuset DL task accounting, but add to sum_migrate_dl_bw only for tasks that need a root-domain bandwidth move. Keep using the destination cpuset effective CPU mask and leave the broader can_attach()/attach() transaction model unchanged.
--- include/linux/sched/deadline.h | 9 +++++++++ kernel/cgroup/cpuset-internal.h | 1 + kernel/cgroup/cpuset.c | 33 ++++++++++++++++++--------------- kernel/sched/deadline.c | 13 ++++++++++--- 4 files changed, 38 insertions(+), 18 deletions(-)
include/linux/sched/deadline.h +9 -0
@@ -33,6 +33,15 @@ struct root_domain;extern void dl_add_task_root_domain (struct task_struct *p);extern void dl_clear_root_domain (struct root_domain *rd);extern void dl_clear_root_domain_cpu (int cpu); +/* +* Return whether moving DL task @p to @new_mask requires moving DL +* bandwidth accounting between root domains. This helper is specific to +* DL bandwidth move accounting semantics and is shared by +* cpuset_can_attach() and set_cpus_allowed_dl() so both paths use the +* same source root-domain test. +*/ +extern bool dl_task_needs_bw_move (struct task_struct *p, +const struct cpumask *new_mask);extern u64 dl_cookie;extern bool dl_bw_visited (int cpu,u64 cookie);
kernel/cgroup/cpuset-internal.h +1 -0
@@ -167,6 +167,7 @@ struct cpuset {*/ int nr_deadline_tasks;int nr_migrate_dl_tasks; +/* DL bandwidth that needs destination reservation for this attach. */ u64 sum_migrate_dl_bw;/* * CPU used for temporary DL bandwidth allocation during attach;
kernel/cgroup/cpuset.c +18 -15
@@ -2993,7 +2993,7 @@ static int cpuset_can_attach(struct cgrostruct cpuset *cs, *oldcs;struct task_struct *task;bool setsched_check; -int ret; +int cpu, ret;/* used later by cpuset_attach() */ cpuset_attach_old_cs =task_cs (cgroup_taskset_first (tset, &css));
@@ -3038,28 +3038,31 @@ static int cpuset_can_attach(struct cgro }if (dl_task (task)) { +/* +* Count all migrating DL tasks for cpuset task accounting. +* Only tasks that need a root-domain bandwidth move +* contribute to sum_migrate_dl_bw. +*/ cs->nr_migrate_dl_tasks++; - cs->sum_migrate_dl_bw += task->dl.dl_bw; +if (dl_task_needs_bw_move (task, cs->effective_cpus)) + cs->sum_migrate_dl_bw += task->dl.dl_bw; } } -if (!cs->nr_migrate_dl_tasks) +if (!cs->sum_migrate_dl_bw) goto out_success; -if (!cpumask_intersects (oldcs->effective_cpus, cs->effective_cpus)) { -int cpu =cpumask_any_and (cpu_active_mask, cs->effective_cpus); - -if (unlikely (cpu >= nr_cpu_ids)) { - ret = -EINVAL ; - goto out_unlock; - } + cpu =cpumask_any_and (cpu_active_mask, cs->effective_cpus); +if (unlikely (cpu >= nr_cpu_ids)) { + ret = -EINVAL ; + goto out_unlock; + } - ret =dl_bw_alloc (cpu, cs->sum_migrate_dl_bw); -if (ret) - goto out_unlock; + ret =dl_bw_alloc (cpu, cs->sum_migrate_dl_bw); +if (ret) + goto out_unlock; - cs->dl_bw_cpu = cpu; - } + cs->dl_bw_cpu = cpu; out_success:/*
kernel/sched/deadline.c +10 -3
@@ -3106,20 +3106,18 @@ static void task_woken_dl(struct rq *rq,static void set_cpus_allowed_dl (struct task_struct *p,struct affinity_context *ctx) { -struct root_domain *src_rd;struct rq *rq;WARN_ON_ONCE (!dl_task (p)); rq =task_rq (p); - src_rd = rq->rd;/* * Migrating a SCHED_DEADLINE task between exclusive * cpusets (different root_domains) entails a bandwidth * update. We already made space for us in the destination * domain (see cpuset_can_attach()). */ -if (!cpumask_intersects (src_rd->span, ctx->new_mask)) { +if (dl_task_needs_bw_move (p, ctx->new_mask)) {struct dl_bw *src_dl_b; src_dl_b =dl_bw_of (cpu_of (rq));
@@ -3136,6 +3134,15 @@ static void set_cpus_allowed_dl(struct tset_cpus_allowed_common (p, ctx); } +bool dl_task_needs_bw_move (struct task_struct *p, +const struct cpumask *new_mask) +{ +if (!dl_task (p)) +return false; + +return !cpumask_intersects (task_rq (p)->rd->span, new_mask); +} +/* Assumes rq->lock is held */ static void rq_online_dl (struct rq *rq) {
Greg Kroah-Hartman
maintainerPATCH 1052/1146 Revert "ACPI: CPPC: Adjust debug messages in amd_set_max_freq_ratio() to warn"
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit db5dadb562cabb6da49959b473ed0d9645b6f2da upstream.
Some older systems don't support CPPC in the firmware and this just makes noise for them when booting. Drop back to debug.
This reverts commit 21fb59ab4b9767085f4fe1edbdbe3177fbb9ec97.
--- arch/x86/kernel/acpi/cppc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/acpi/cppc.c +3 -3
@@ -88,19 +88,19 @@ static void amd_set_max_freq_ratio(void) rc =cppc_get_perf_caps (0 , &perf_caps);if (rc) { -pr_warn ("Could not retrieve perf counters (%d)\n" , rc); +pr_debug ("Could not retrieve perf counters (%d)\n" , rc);return ; } rc =amd_get_boost_ratio_numerator (0 , &numerator);if (rc) { -pr_warn ("Could not retrieve highest performance (%d)\n" , rc); +pr_debug ("Could not retrieve highest performance (%d)\n" , rc);return ; } nominal_perf = perf_caps.nominal_perf;if (!nominal_perf) { -pr_warn ("Could not retrieve nominal performance\n" ); +pr_debug ("Could not retrieve nominal performance\n" );return ; }
Greg Kroah-Hartman
maintainerPATCH 1053/1146 netfilter: nft_ct: fix missing expect put in obj eval
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Xiasong <[email protected]>
commit 19f94b6fee75b3ef7fbc06f3745b9a771a8a19a4 upstream.
nft_ct_expect_obj_eval() allocates an expectation and may call nf_ct_expect_related(), but never drops its local reference.
Add nf_ct_expect_put(exp) before return to balance allocation.
--- net/netfilter/nft_ct.c | 2 ++ 1 file changed, 2 insertions(+)
net/netfilter/nft_ct.c +2 -0
@@ -1381,6 +1381,8 @@ static void nft_ct_expect_obj_eval(strucif (nf_ct_expect_related (exp,0 ) !=0 ) regs->verdict.code =NF_DROP ; + +nf_ct_expect_put (exp); }static const struct nla_policy nft_ct_expect_policy[NFTA_CT_EXPECT_MAX +1 ] = {
Greg Kroah-Hartman
maintainerPATCH 1054/1146 net: atlantic: preserve PCI wake-from-D3 on shutdown when WOL enabled
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zoran Ilievski <[email protected]>
commit 2c308cf34284420963607d677d576a2b4124d8bd upstream.
The shutdown handler aq_pci_shutdown() unconditionally calls pci_wake_from_d3(pdev, false), clearing the PCI PME_En bit even when wake-on-LAN has been configured. While aq_nic_shutdown() correctly programs the NIC firmware via aq_nic_set_power() to listen for magic packets, the PCI subsystem will not propagate the resulting PME wake event from D3, so the system never wakes after poweroff.
WOL from suspend (S3) is unaffected because aq_suspend_common() does not touch pci_wake_from_d3() and relies on the PM core's wake configuration via device_may_wakeup().
This affects all atlantic-supported NICs (AQC107/108/111/112/113); users have reported that WOL works if the atlantic driver is never loaded, but breaks once it has run its shutdown path.
Pass the configured WOL state to pci_wake_from_d3() instead of a literal false, so the PCI PME_En bit is preserved when the user has armed WOL via ethtool.
--- drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +1 -1
@@ -371,7 +371,7 @@ static void aq_pci_shutdown(struct pci_dpci_disable_device (pdev);if (system_state ==SYSTEM_POWER_OFF ) { -pci_wake_from_d3 (pdev, false); +pci_wake_from_d3 (pdev, self->aq_hw->aq_nic_cfg->wol);pci_set_power_state (pdev, PCI_D3hot); } }
Greg Kroah-Hartman
maintainerPATCH 1055/1146 audit: enforce AUDIT_LOCKED for AUDIT_TRIM and AUDIT_MAKE_EQUIV
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergio Correia <[email protected]>
commit f9e1c1324b4d98d591a6f7568fdebf5cf456dfc2 upstream.
AUDIT_ADD_RULE and AUDIT_DEL_RULE correctly check for AUDIT_LOCKED and return -EPERM, but AUDIT_TRIM and AUDIT_MAKE_EQUIV do not. This allows a process with CAP_AUDIT_CONTROL to modify directory tree watches and equivalence mappings even when the audit configuration has been locked, undermining the purpose of the lock.
Add AUDIT_LOCKED checks to both commands.
--- kernel/audit.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/audit.c +4 -0
@@ -1466,6 +1466,8 @@ static int audit_receive_msg(struct sk_b err =audit_list_rules_send (skb, seq);break ;case AUDIT_TRIM : +if (audit_enabled ==AUDIT_LOCKED ) +return -EPERM ;audit_trim_trees ();audit_log_common_recv_msg (audit_context (), &ab,AUDIT_CONFIG_CHANGE );
@@ -1478,6 +1480,8 @@ static int audit_receive_msg(struct sk_bsize_t msglen = data_len;char *old, *new; +if (audit_enabled ==AUDIT_LOCKED ) +return -EPERM ; err = -EINVAL ;if (msglen <2 *sizeof (u32))break ;
Greg Kroah-Hartman
maintainerPATCH 1056/1146 cgroup/cpuset: Return only actually allocated CPUs during partition invalidation
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: sunshaojie <[email protected]>
commit 345f40166694e60db6d5cf02233814bb27ac5dec upstream.
In update_parent_effective_cpumask() with partcmd_invalidate, the CPUs to return to the parent are computed as:
adding = cpumask_and(tmp->addmask, xcpus, parent->effective_xcpus);
where xcpus = user_xcpus(cs) which returns cs->exclusive_cpus (if set) or cs->cpus_allowed. When exclusive_cpus is not set, user_xcpus(cs) can contain CPUs that were never actually granted to the partition due to sibling exclusion in compute_excpus(). Consequently, the invalidation may return CPUs to the parent that remain in use by sibling partitions, causing overlapping effective_cpus and triggering the WARN_ON_ONCE(1) in generate_sched_domains().
Use cs->effective_xcpus instead, which reflects the CPUs actually granted to this partition.
Reproducer (on a 4-CPU machine):
cd /sys/fs/cgroup
mkdir a1 b1
# a1 becomes partition root with CPUs 0-1
echo "0-1" > a1/cpuset.cpus
echo "root" > a1/cpuset.cpus.partition
# b1 becomes partition root with CPUs 1-2, but sibling exclusion # reduces its effective_xcpus to CPU 2 only
echo "1-2" > b1/cpuset.cpus
echo "root" > b1/cpuset.cpus.partition
# b1 changes cpus_allowed to 0-1 -> partition invalidation echo "0-1" > b1/cpuset.cpus
# Expected: CPUs 2-3 (only CPU 2 returned from b1)
# Actual: CPUs 1-3 (CPU 0-1 returned, overlapping with a1)
cat cpuset.cpus.effective
dmesg will also show a WARNING from generate_sched_domains() reporting overlapping partition root effective_cpus.
--- kernel/cgroup/cpuset.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/cgroup/cpuset.c +2 -1
@@ -1718,7 +1718,8 @@ static int update_parent_effective_cpuma*/ if (is_partition_valid (parent)) adding =cpumask_and (tmp->addmask, - xcpus, parent->effective_xcpus); + cs->effective_xcpus, + parent->effective_xcpus);if (old_prs >0 ) new_prs = -old_prs;
Greg Kroah-Hartman
maintainerPATCH 1057/1146 KVM: x86: Swap the dst and src operand for MOVNTDQA
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 3098c076c83ea2913245cb915cdcba98eb24214c upstream.
Swap the MOVNTDQA operands, as MOVNTDQA does NOT in fact have "the same characteristics as 0F E7 (MOVNTDQ)"; MOVNTDQA loads from memory and stores to registers, while MOVNTDQ loads from registers and stores to memory.
Per the SDM:
MOVNTDQ - Move packed integer values in xmm1 to m128 using non-temporal
hint.
MOVNTDQA - Move double quadword from m128 to xmm1 using non-temporal hint
if WC memory type.
Message-ID: <[email protected]>
--- arch/x86/kvm/emulate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/emulate.c +1 -1
@@ -4469,7 +4469,7 @@ static const struct opcode opcode_map_0fX16 (N ),X16 (N ),/* 0x20 - 0x2f */ X8 (N ), -X2 (N ),GP (SrcReg | DstMem | ModRM | Mov | Aligned, &pfx_0f_e7_0f_38_2a),N ,N ,N ,N ,N , +X2 (N ),GP (SrcMem | DstReg | ModRM | Mov | Aligned, &pfx_0f_e7_0f_38_2a),N ,N ,N ,N ,N ,/* 0x30 - 0x7f */ X16 (N ),X16 (N ),X16 (N ),X16 (N ),X16 (N ), /* 0x80 - 0xef */
Greg Kroah-Hartman
maintainerPATCH 1058/1146 KVM: Reject wrapped offset in kvm_reset_dirty_gfn()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aaron Sacks <[email protected]>
commit 577a8d3bae0531f0e5ccfac919cd8192f920a804 upstream.
kvm_reset_dirty_gfn() guards the gfn range with
if (!memslot || (offset + __fls(mask)) >= memslot->npages) return;
but offset is u64 and the addition is unchecked. The check can be silently bypassed by a u64 wrap.
The dirty ring backing those entries is MAP_SHARED at KVM_DIRTY_LOG_PAGE_OFFSET of the vcpu fd, so the VMM can rewrite the slot and offset fields of any entry between when the kernel pushes them and when KVM_RESET_DIRTY_RINGS consumes them. On reset, kvm_dirty_ring_reset() re-reads the values via READ_ONCE() and feeds them straight back into this check; only the flags handshake is treated as the handover, the slot/offset payload is taken on trust.
Crafting two entries
entry[i].offset = 0xffffffffffffffc1 entry[i+1].offset = 0
makes the coalescing loop in kvm_dirty_ring_reset() compute
delta = (s64)(0 - 0xffffffffffffffc1) = 63
which falls in [0, BITS_PER_LONG), so it folds entry[i+1] into the existing mask by setting bit 63. The trailing kvm_reset_dirty_gfn() call then sees offset = 0xffffffffffffffc1 and __fls(mask) = 63; the sum is 0 in u64 and the bounds check passes.
That offset propagates into kvm_arch_mmu_enable_log_dirty_pt_masked() unchanged. On the legacy MMU path -- kvm_memslots_have_rmaps() == true, i.e. shadow paging, any VM that has allocated shadow roots, or a write-tracked slot -- it reaches gfn_to_rmap(), which indexes slot->arch.rmap[0][] with a near-U64_MAX gfn. That is an out-of-bounds load of a kvm_rmap_head, followed by a conditional clear of PT_WRITABLE_MASK in whatever the loaded pointer points at. The path is reachable from any process holding /dev/kvm.
Range-check offset on its own first, so the addition cannot wrap. memslot->npages is bounded well below U64_MAX, so once offset < npages holds, offset + __fls(mask) (with __fls(mask) < BITS_PER_LONG) stays in range.
--- virt/kvm/dirty_ring.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
virt/kvm/dirty_ring.c +2 -1
@@ -63,7 +63,8 @@ static void kvm_reset_dirty_gfn(struct k memslot =id_to_memslot (__kvm_memslots (kvm, as_id), id); -if (!memslot || (offset +__fls (mask)) >= memslot->npages) +if (!memslot || offset >= memslot->npages || + offset +__fls (mask) >= memslot->npages)return ;KVM_MMU_LOCK (kvm);
Greg Kroah-Hartman
maintainerPATCH 1059/1146 KVM: s390: pci: fix GAIT table indexing due to double-scaling pointer arithmetic
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junrui Luo <[email protected]>
commit 16d990a15491cf76cd6eef0846e1b4100e63261a upstream.
kvm_s390_pci_aif_enable(), kvm_s390_pci_aif_disable(), and aen_host_forward() index the GAIT by manually multiplying the index with sizeof(struct zpci_gaite).
Since aift->gait is already a struct zpci_gaite pointer, this double-scales the offset, accessing element aisb*16 instead of aisb.
This causes out-of-bounds accesses when aisb >= 32 (with ZPCI_NR_DEVICES=512)
Fix by removing the erroneous sizeof multiplication.
--- arch/s390/kvm/interrupt.c | 3 +-- arch/s390/kvm/pci.c | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-)
arch/s390/kvm/interrupt.c +1 -2
@@ -3307,8 +3307,7 @@ static void aen_host_forward(unsigned lostruct zpci_gaite *gaite;struct kvm *kvm; - gaite = (struct zpci_gaite *)aift->gait + - (si *sizeof (struct zpci_gaite )); + gaite = aift->gait + si;if (gaite->count ==0 )return ;if (gaite->aisb !=0 )
arch/s390/kvm/pci.c +2 -4
@@ -290,8 +290,7 @@ static int kvm_s390_pci_aif_enable(struc phys_to_virt(fib->fmt0.aibv));spin_lock_irq (&aift->gait_lock); - gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb * -sizeof (struct zpci_gaite )); + gaite = aift->gait + zdev->aisb;/* If assist not requested, host will get all alerts */ if (assist)
@@ -357,8 +356,7 @@ static int kvm_s390_pci_aif_disable(struif (zdev->kzdev->fib.fmt0.aibv ==0 ) goto out;spin_lock_irq (&aift->gait_lock); - gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb * -sizeof (struct zpci_gaite )); + gaite = aift->gait + zdev->aisb; isc = gaite->gisc; gaite->count--;if (gaite->count ==0 ) {
Greg Kroah-Hartman
maintainerPATCH 1060/1146 KVM: x86: Fix Xen hypercall tracepoint argument assignment
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qiang Ma <[email protected]>
commit 2b72f1674e427c56e3772c5ccf785fdda2138820 upstream.
TRACE_EVENT(kvm_xen_hypercall) stores a5 in __entry->a4 instead of __entry->a5.
That overwrites the recorded a4 argument and leaves a5 unset in the trace entry. Fix the typo so both arguments are captured correctly.
--- arch/x86/kvm/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/trace.h +1 -1
@@ -154,7 +154,7 @@ TRACE_EVENT(kvm_xen_hypercall, __entry->a2 = a2; __entry->a3 = a3; __entry->a4 = a4; - __entry->a4 = a5; + __entry->a5 = a5; ), TP_printk("cpl %d nr 0x%lx a0 0x%lx a1 0x%lx a2 0x%lx a3 0x%lx a4 0x%lx a5 %lx",
Greg Kroah-Hartman
maintainerPATCH 1061/1146 HID: pass the buffer size to hid_report_raw_event
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Tissoires <[email protected]>
[ Upstream commit 2c85c61d1332e1e16f020d76951baf167dcb6f7a ]
commit 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing bogus memset()") enforced the provided data to be at least the size of the declared buffer in the report descriptor to prevent a buffer overflow. However, we can try to be smarter by providing both the buffer size and the data size, meaning that hid_report_raw_event() can make better decision whether we should plaining reject the buffer (buffer overflow attempt) or if we can safely memset it to 0 and pass it to the rest of the stack.
Stable-dep-of: 206342541fc8 ("HID: core: introduce hid_safe_input_report()")
--- drivers/hid/bpf/hid_bpf_dispatch.c | 6 +++-- drivers/hid/hid-core.c | 42 ++++++++++++++++++++---------- drivers/hid/hid-gfrm.c | 4 +-- drivers/hid/hid-logitech-hidpp.c | 2 +- drivers/hid/hid-multitouch.c | 2 +- drivers/hid/hid-primax.c | 2 +- drivers/hid/hid-vivaldi-common.c | 2 +- drivers/hid/wacom_sys.c | 6 ++--- drivers/staging/greybus/hid.c | 2 +- include/linux/hid.h | 4 +-- include/linux/hid_bpf.h | 14 ++++++---- 11 files changed, 53 insertions(+), 33 deletions(-)
drivers/hid/bpf/hid_bpf_dispatch.c +4 -2
@@ -24,7 +24,8 @@ EXPORT_SYMBOL(hid_ops);u8 *dispatch_hid_bpf_device_event (struct hid_device *hdev,enum hid_report_type type,u8 *data, -u32 *size,int interrupt,u64 source,bool from_bpf) +size_t *buf_size,u32 *size,int interrupt,u64 source, +bool from_bpf) {struct hid_bpf_ctx_kern ctx_kern = { .ctx = {
@@ -74,6 +75,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type *size = ret; } + *buf_size = ctx_kern.ctx.allocated_size;return ctx_kern.data; }EXPORT_SYMBOL_GPL (dispatch_hid_bpf_device_event);
@@ -505,7 +507,7 @@ __hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *bif (ret)return ret; -return hid_ops->hid_input_report (ctx->hid, type, buf, size,0 , (u64 )(long )ctx, true, +return hid_ops->hid_input_report (ctx->hid, type, buf, size, size,0 , (u64 )(long )ctx, true, lock_already_taken); }
drivers/hid/hid-core.c +28 -14
106 lines not on this page · raw message
drivers/hid/hid-gfrm.c +2 -2
@@ -66,7 +66,7 @@ static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report,switch (data[1 ]) {case GFRM100_SEARCH_KEY_DOWN : ret =hid_report_raw_event (hdev,HID_INPUT_REPORT , search_key_dn, -sizeof (search_key_dn),1 ); +sizeof (search_key_dn),sizeof (search_key_dn),1 );break ;case GFRM100_SEARCH_KEY_AUDIO_DATA :
@@ -74,7 +74,7 @@ static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report,case GFRM100_SEARCH_KEY_UP : ret =hid_report_raw_event (hdev,HID_INPUT_REPORT , search_key_up, -sizeof (search_key_up),1 ); +sizeof (search_key_up),sizeof (search_key_up),1 );break ;default :
drivers/hid/hid-logitech-hidpp.c +1 -1
@@ -3665,7 +3665,7 @@ static int hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp,memcpy (&consumer_report[1 ], &data[3 ],4 );/* We are called from atomic context */ hid_report_raw_event (hidpp->hid_dev,HID_INPUT_REPORT , - consumer_report,5 ,1 ); + consumer_report,sizeof (consumer_report),5 ,1 );return 1 ; }
drivers/hid/hid-multitouch.c +1 -1
@@ -533,7 +533,7 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) } ret =hid_report_raw_event (hdev,HID_FEATURE_REPORT , buf, - size,0 ); + size, size,0 );if (ret)dev_warn (&hdev->dev,"failed to report feature\n" ); }
drivers/hid/hid-primax.c +1 -1
@@ -44,7 +44,7 @@ static int px_raw_event(struct hid_device *hid, struct hid_report *report, data[0 ] |= (1 << (data[idx] -0xE0 )); data[idx] =0 ; } -hid_report_raw_event (hid,HID_INPUT_REPORT , data, size,0 ); +hid_report_raw_event (hid,HID_INPUT_REPORT , data, size, size,0 );return 1 ;default :/* unknown report */
drivers/hid/hid-vivaldi-common.c +1 -1
@@ -85,7 +85,7 @@ void vivaldi_feature_mapping(struct hid_device *hdev, } ret =hid_report_raw_event (hdev,HID_FEATURE_REPORT , report_data, - report_len,0 ); + report_len, report_len,0 );if (ret) {dev_warn (&hdev->dev,"failed to report feature %d\n" , field->report->id);
drivers/hid/wacom_sys.c +3 -3
@@ -90,7 +90,7 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,kfree (buf);continue ; } - err =hid_report_raw_event (hdev,HID_INPUT_REPORT , buf, size, false); + err =hid_report_raw_event (hdev,HID_INPUT_REPORT , buf, size, size, false);if (err) {hid_warn (hdev,"%s: unable to flush event due to error %d\n" , __func__, err);
@@ -334,7 +334,7 @@ static void wacom_feature_mapping(struct hid_device *hdev, data, n, WAC_CMD_RETRIES);if (ret == n && features->type ==HID_GENERIC ) { ret =hid_report_raw_event (hdev, -HID_FEATURE_REPORT , data, n,0 ); +HID_FEATURE_REPORT , data, n, n,0 ); }else if (ret ==2 && features->type !=HID_GENERIC ) { features->touch_max = data[1 ]; }else {
@@ -395,7 +395,7 @@ static void wacom_feature_mapping(struct hid_device *hdev, data, n, WAC_CMD_RETRIES);if (ret == n) { ret =hid_report_raw_event (hdev,HID_FEATURE_REPORT , - data, n,0 ); + data, n, n,0 ); }else {hid_warn (hdev,"%s: could not retrieve sensor offsets\n" , __func__);
drivers/staging/greybus/hid.c +1 -1
@@ -201,7 +201,7 @@ static void gb_hid_init_report(struct gb_hid *ghid, struct hid_report *report)* we just need to setup the input fields, so using * hid_report_raw_event is safe. */ -hid_report_raw_event (ghid->hid, report->type, ghid->inbuf, size,1 ); +hid_report_raw_event (ghid->hid, report->type, ghid->inbuf, ghid->bufsize, size,1 ); }static void gb_hid_init_reports (struct gb_hid *ghid)
include/linux/hid.h +2 -2
@@ -1266,8 +1266,8 @@ static inline u32 hid_report_len(struct hid_report *report)return DIV_ROUND_UP (report->size,8 ) + (report->id >0 ); } -int hid_report_raw_event (struct hid_device *hid,enum hid_report_type type,u8 *data,u32 size, -int interrupt); +int hid_report_raw_event (struct hid_device *hid,enum hid_report_type type,u8 *data, +size_t bufsize,u32 size,int interrupt);/* HID quirks API */ unsigned long hid_lookup_quirk (const struct hid_device *hdev);
include/linux/hid_bpf.h +9 -5
@@ -72,8 +72,8 @@ struct hid_ops {int (*hid_hw_output_report)(struct hid_device *hdev,__u8 *buf,size_t len,u64 source,bool from_bpf);int (*hid_input_report)(struct hid_device *hid,enum hid_report_type type, -u8 *data,u32 size,int interrupt,u64 source,bool from_bpf, -bool lock_already_taken); +u8 *data,size_t bufsize,u32 size,int interrupt,u64 source, +bool from_bpf,bool lock_already_taken);struct module *owner;const struct bus_type *bus_type; };
@@ -200,7 +200,8 @@ struct hid_bpf {#ifdef CONFIG_HID_BPF u8 *dispatch_hid_bpf_device_event (struct hid_device *hid,enum hid_report_type type,u8 *data, -u32 *size,int interrupt,u64 source,bool from_bpf); +size_t *buf_size,u32 *size,int interrupt,u64 source, +bool from_bpf); int dispatch_hid_bpf_raw_requests(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, u32 size, enum hid_report_type rtype,
@@ -215,8 +216,11 @@ int hid_bpf_device_init(struct hid_device *hid);const u8 *call_hid_bpf_rdesc_fixup (struct hid_device *hdev,const u8 *rdesc,unsigned int *size);#else /* CONFIG_HID_BPF */ static inline u8 *dispatch_hid_bpf_device_event (struct hid_device *hid,enum hid_report_type type, -u8 *data,u32 *size,int interrupt, -u64 source,bool from_bpf) {return data; } +u8 *data,size_t *buf_size,u32 *size, +int interrupt,u64 source,bool from_bpf) +{ +return data; +} static inline int dispatch_hid_bpf_raw_requests(struct hid_device *hdev, unsigned char reportnum, u8 *buf, u32 size, enum hid_report_type rtype,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1062/1146 HID: core: introduce hid_safe_input_report()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Tissoires <[email protected]>
[ Upstream commit 206342541fc887ae919774a43942dc883161fece ]
hid_input_report() is used in too many places to have a commit that doesn't cross subsystem borders. Instead of changing the API, introduce a new one when things matters in the transport layers:
- usbhid
- i2chid
This effectively revert to the old behavior for those two transport layers.
--- drivers/hid/hid-core.c | 25 +++++++++++++++++++++++++ drivers/hid/i2c-hid/i2c-hid-core.c | 7 ++++--- drivers/hid/usbhid/hid-core.c | 11 ++++++----- include/linux/hid.h | 2 ++ 4 files changed, 37 insertions(+), 8 deletions(-)
drivers/hid/hid-core.c +25 -0
@@ -2177,6 +2177,7 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,* @interrupt: distinguish between interrupt and control transfers * * This is data entry for lower layers. +* Legacy, please use hid_safe_input_report() instead. */ int hid_input_report (struct hid_device *hid,enum hid_report_type type,u8 *data,u32 size,int interrupt)
@@ -2187,6 +2188,30 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data }EXPORT_SYMBOL_GPL (hid_input_report); +/** +* hid_safe_input_report - report data from lower layer (usb, bt...) +* +* @hid: hid device +* @type: HID report type (HID_*_REPORT) +* @data: report contents +* @bufsize: allocated size of the data buffer +* @size: useful size of data parameter +* @interrupt: distinguish between interrupt and control transfers +* +* This is data entry for lower layers. +* Please use this function instead of the non safe version because we provide +* here the size of the buffer, allowing hid-core to make smarter decisions +* regarding the incoming buffer. +*/ +int hid_safe_input_report (struct hid_device *hid,enum hid_report_type type,u8 *data, +size_t bufsize,u32 size,int interrupt) +{ +return __hid_input_report (hid, type, data, bufsize, size, interrupt,0 , + false,/* from_bpf */ + false/* lock_already_taken */ ); +} +EXPORT_SYMBOL_GPL (hid_safe_input_report); +bool hid_match_one_id (const struct hid_device *hdev,const struct hid_device_id *id) {
drivers/hid/i2c-hid/i2c-hid-core.c +4 -3
@@ -574,9 +574,10 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)if (ihid->hid->group !=HID_GROUP_RMI )pm_wakeup_event (&ihid->client->dev,0 ); -hid_input_report (ihid->hid,HID_INPUT_REPORT , - ihid->inbuf +sizeof (__le16), - ret_size -sizeof (__le16),1 ); +hid_safe_input_report (ihid->hid,HID_INPUT_REPORT , + ihid->inbuf +sizeof (__le16), + ihid->bufsize -sizeof (__le16), + ret_size -sizeof (__le16),1 ); }return ;
drivers/hid/usbhid/hid-core.c +6 -5
@@ -283,9 +283,9 @@ static void hid_irq_in(struct urb *urb)break ;usbhid_mark_busy (usbhid);if (!test_bit (HID_RESUME_RUNNING , &usbhid->iofl)) { -hid_input_report (urb->context,HID_INPUT_REPORT , - urb->transfer_buffer, - urb->actual_length,1 ); +hid_safe_input_report (urb->context,HID_INPUT_REPORT , + urb->transfer_buffer, urb->transfer_buffer_length, + urb->actual_length,1 );/* * autosuspend refused while keys are pressed * because most keyboards don't wake up when
@@ -482,9 +482,10 @@ static void hid_ctrl(struct urb *urb)switch (status) {case 0 :/* success */ if (usbhid->ctrl[usbhid->ctrltail].dir ==USB_DIR_IN ) -hid_input_report (urb->context, +hid_safe_input_report (urb->context, usbhid->ctrl[usbhid->ctrltail].report->type, - urb->transfer_buffer, urb->actual_length,0 ); + urb->transfer_buffer, urb->transfer_buffer_length, + urb->actual_length,0 );break ;case -ESHUTDOWN :/* unplug */ unplug =1 ;
include/linux/hid.h +2 -0
@@ -998,6 +998,8 @@ struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_tyint hid_set_field (struct hid_field *,unsigned ,__s32 );int hid_input_report (struct hid_device *hid,enum hid_report_type type,u8 *data,u32 size,int interrupt); +int hid_safe_input_report (struct hid_device *hid,enum hid_report_type type,u8 *data, +size_t bufsize,u32 size,int interrupt);struct hid_field *hidinput_get_led_field (struct hid_device *hid);unsigned int hidinput_count_leds (struct hid_device *hid);__s32 hidinput_calc_abs_res (const struct hid_field *field,__u16 code);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1063/1146 rseq: Revert to historical performance killing behaviour
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit b9eac6a9d93c952c4b7775a24d5c7a1bbf4c3c00 upstream.
The recent RSEQ optimization work broke the TCMalloc abuse of the RSEQ ABI as it not longer unconditionally updates the CPU, node, mm_cid fields, which are documented as read only for user space. Due to the observed behavior of the kernel it was possible for TCMalloc to overwrite the cpu_id_start field for their own purposes and rely on the kernel to update it unconditionally after each context switch and before signal delivery.
The RSEQ ABI only guarantees that these fields are updated when the data changes, i.e. the task is migrated or the MMCID of the task changes due to switching from or to per CPU ownership mode.
The optimization work eliminated the unconditional updates and reduced them to the documented ABI guarantees, which results in a massive performance win for syscall, scheduling heavy work loads, which in turn breaks the TCMalloc expectations.
There have been several options discussed to restore the TCMalloc functionality while preserving the optimization benefits. They all end up in a series of hard to maintain workarounds, which in the worst case introduce overhead for everyone, e.g. in the scheduler.
The requirements of TCMalloc and the optimization work are diametral and the required work arounds are a maintainence burden. They end up as fragile constructs, which are blocking further optimization work and are pretty much guaranteed to cause more subtle issues down the road.
The optimization work heavily depends on the generic entry code, which is not used by all architectures yet. So the rework preserved the original mechanism moslty unmodified to keep the support for architectures, which handle rseq in their own exit to user space loop. That code is currently optimized out by the compiler on architectures which use the generic entry code.
This allows to revert back to the original behaviour by replacing the compile time constant conditions with a runtime condition where required, which disables the optimization and the dependend time slice extension feature until the run-time condition can be enabled in the RSEQ registration code on a per task basis again.
The following changes are required to restore the original behavior, which makes TCMalloc work again:
1) Replace the compile time constant conditionals with runtime conditionals where appropriate to prevent the compiler from optimizing the legacy mode out
2) Enforce unconditional update of IDs on context switch for the non-optimized v1 mode
3) Enforce update of IDs in the pre signal delivery path for the non-optimized v1 mode
4) Enforce update of IDs in the membarrier(RSEQ) IPI for the non-optimized v1 mode
5) Make time slice and future extensions depend on optimized v2 mode
This brings back the full performance problems, but preserves the v2 optimization code and for generic entry code using architectures also the TIF_RSEQ optimization which avoids a full evaluation of the exit to user mode loop in many cases.
--- include/linux/rseq.h | 35 ++++++++++++++++++++++----------- include/linux/rseq_entry.h | 39 +++++++++++++++++++++++++++---------- include/linux/rseq_types.h | 9 ++++++++- kernel/rseq.c | 40 +++++++++++++++++++++++++++++++------- kernel/sched/membarrier.c | 11 ++++++++++- 5 files changed, 104 insertions(+), 30 deletions(-)
include/linux/rseq.h +24 -11
@@ -9,6 +9,11 @@void __rseq_handle_slowpath (struct pt_regs *regs); +static __always_inline bool rseq_v2(struct task_struct *t) +{ +return IS_ENABLED (CONFIG_GENERIC_IRQ_ENTRY ) &&likely (t->rseq.event.has_rseq >1 ); +} +/* Invoked from resume_user_mode_work() */ static inline void rseq_handle_slowpath (struct pt_regs *regs) {
@@ -16,8 +21,7 @@ static inline void rseq_handle_slowpath(struct pt_regs *regs)if (current->rseq.event.slowpath)__rseq_handle_slowpath (regs); }else { -/* '&' is intentional to spare one conditional branch */ -if (current->rseq.event.sched_switch & current->rseq.event.has_rseq) +if (current->rseq.event.sched_switch && current->rseq.event.has_rseq)__rseq_handle_slowpath (regs); } }
@@ -30,9 +34,9 @@ void __rseq_signal_deliver(int sig, struct pt_regs *regs);*/ static inline void rseq_signal_deliver (struct ksignal *ksig,struct pt_regs *regs) { -if (IS_ENABLED (CONFIG_GENERIC_IRQ_ENTRY )) { -/* '&' is intentional to spare one conditional branch */ -if (current->rseq.event.has_rseq & current->rseq.event.user_irq) +if (rseq_v2 (current)) { +/* has_rseq is implied in rseq_v2() */ +if (current->rseq.event.user_irq)__rseq_signal_deliver (ksig->sig, regs); }else {if (current->rseq.event.has_rseq)
@@ -50,15 +54,22 @@ static __always_inline void rseq_sched_switch_event(struct task_struct *t) {struct rseq_event *ev = &t->rseq.event; -if (IS_ENABLED (CONFIG_GENERIC_IRQ_ENTRY )) { +/* +* Only apply the user_irq optimization for RSEQ ABI V2 registrations. +* Legacy users like TCMalloc rely on the original ABI V1 behaviour +* which updates IDs on every context swtich. +*/ +if (rseq_v2 (t)) {/* -* Avoid a boat load of conditionals by using simple logic -* to determine whether NOTIFY_RESUME needs to be raised. +* Avoid a boat load of conditionals by using simple logic to +* determine whether TIF_NOTIFY_RESUME or TIF_RSEQ needs to be +* raised. * -* It's required when the CPU or MM CID has changed or -* the entry was from user space. +* It's required when the CPU or MM CID has changed or the entry +* was via interrupt from user space. ev->has_rseq does not have +* to be evaluated here because rseq_v2() implies has_rseq. */ -bool raise = (ev->user_irq | ev->ids_changed) & ev->has_rseq; +bool raise = ev->user_irq | ev->ids_changed;if (raise) { ev->sched_switch = true;
@@ -66,6 +77,7 @@ static __always_inline void rseq_sched_switch_event(struct task_struct *t) } }else {if (ev->has_rseq) { + t->rseq.event.ids_changed = true; t->rseq.event.sched_switch = true;rseq_raise_notify_resume (t); }
@@ -161,6 +173,7 @@ static inline unsigned int rseq_alloc_align(void) }#else /* CONFIG_RSEQ */ +static inline bool rseq_v2 (struct task_struct *t) {return false; }static inline void rseq_handle_slowpath (struct pt_regs *regs) { }static inline void rseq_signal_deliver (struct ksignal *ksig,struct pt_regs *regs) { }static inline void rseq_sched_switch_event (struct task_struct *t) { }
include/linux/rseq_entry.h +29 -10
@@ -110,6 +110,20 @@ static __always_inline void rseq_slice_clear_grant(struct task_struct *t) t->rseq.slice.state.granted = false; } +/* +* Open coded, so it can be invoked within a user access region. +* +* This clears the user space state of the time slice extensions field only when +* the task has registered the optimized RSEQ_ABI V2. Some legacy registrations, +* e.g. TCMalloc, have conflicting non-ABI fields in struct RSEQ, which would be +* overwritten by an unconditional write. +*/ +#define rseq_slice_clear_user (rseq, efault) \ +do { \ + if (rseq_slice_extension_enabled()) \ + unsafe_put_user(0U, &rseq->slice_ctrl.all, efault); \ +} while (0) + static __always_inline bool rseq_grant_slice_extension(bool work_pending) {struct task_struct *curr = current;
@@ -220,6 +234,7 @@ static __always_inline bool rseq_slice_extension_enabled(void) { return false; } static __always_inline bool rseq_arm_slice_extension_timer(void) { return false; } static __always_inline void rseq_slice_clear_grant(struct task_struct *t) { } static __always_inline bool rseq_grant_slice_extension(bool work_pending) { return false; } +#define rseq_slice_clear_user (rseq, efault) do { } while (0)#endif /* !CONFIG_RSEQ_SLICE_EXTENSION */ bool rseq_debug_update_user_cs (struct task_struct *t,struct pt_regs *regs,unsigned long csaddr);
@@ -507,11 +522,9 @@ bool rseq_set_ids_get_csaddr(struct task_struct *t, struct rseq_ids *ids,if (csaddr)unsafe_get_user (*csaddr, &rseq->rseq_cs, efault); -/* Open coded, so it's in the same user access region */ -if (rseq_slice_extension_enabled ()) { -/* Unconditionally clear it, no point in conditionals */ -unsafe_put_user (0U , &rseq->slice_ctrl.all, efault); - } +/* RSEQ ABI V2 only operations */ +if (rseq_v2 (t)) +rseq_slice_clear_user (rseq, efault); }rseq_slice_clear_grant (t);
@@ -602,6 +615,14 @@ static __always_inline bool rseq_exit_user_update(struct pt_regs *regs, struct t* interrupts disabled */ guard (pagefault)(); +/* +* This optimization is only valid when the task registered for the +* optimized RSEQ_ABI_V2 variant. Some legacy users rely on the original +* RSEQ implementation behaviour which unconditionally updated the IDs. +* rseq_sched_switch_event() ensures that legacy registrations always +* have both sched_switch and ids_changed set, which is compatible with +* the historical TIF_NOTIFY_RESUME behaviour. +*/ if (likely (!t->rseq.event.ids_changed)) {struct rseq __user *rseq = t->rseq.usrptr;/*
@@ -613,11 +634,9 @@ static __always_inline bool rseq_exit_user_update(struct pt_regs *regs, struct t scoped_user_rw_access(rseq, efault) {unsafe_get_user (csaddr, &rseq->rseq_cs, efault); -/* Open coded, so it's in the same user access region */ -if (rseq_slice_extension_enabled ()) { -/* Unconditionally clear it, no point in conditionals */ -unsafe_put_user (0U , &rseq->slice_ctrl.all, efault); - } +/* RSEQ ABI V2 only operations */ +if (rseq_v2 (t)) +rseq_slice_clear_user (rseq, efault); }rseq_slice_clear_grant (t);
include/linux/rseq_types.h +8 -1
@@ -9,6 +9,12 @@#ifdef CONFIG_RSEQ struct rseq ; +/* +* rseq_event::has_rseq contains the ABI version number so preserving it +* in AND operations requires a mask. +*/ +#define RSEQ_HAS_RSEQ_VERSION_MASK 0xff +/** * struct rseq_event - Storage for rseq related event management * @all: Compound to initialize and clear the data efficiently
@@ -17,7 +23,8 @@ struct rseq;* exit to user * @ids_changed: Indicator that IDs need to be updated * @user_irq: True on interrupt entry from user mode -* @has_rseq: True if the task has a rseq pointer installed +* @has_rseq: Greater than 0 if the task has a rseq pointer installed. +* Contains the RSEQ version number * @error: Compound error code for the slow path to analyze * @fatal: User space data corrupted or invalid * @slowpath: Indicator that slow path processing via TIF_NOTIFY_RESUME
kernel/rseq.c +33 -7
@@ -253,11 +253,14 @@ static bool rseq_handle_cs(struct task_struct *t, struct pt_regs *regs)static void rseq_slowpath_update_usr (struct pt_regs *regs) {/* -* Preserve rseq state and user_irq state. The generic entry code -* clears user_irq on the way out, the non-generic entry -* architectures are not having user_irq. +* Preserve has_rseq and user_irq state. The generic entry code clears +* user_irq on the way out, the non-generic entry architectures are not +* setting user_irq. */ -const struct rseq_event evt_mask = { .has_rseq = true, .user_irq = true, }; +const struct rseq_event evt_mask = { + .has_rseq =RSEQ_HAS_RSEQ_VERSION_MASK , + .user_irq = true, + };struct task_struct *t = current;struct rseq_ids ids;u32 node_id;
@@ -330,8 +333,9 @@ void __rseq_handle_slowpath(struct pt_regs *regs)void __rseq_signal_deliver (int sig,struct pt_regs *regs) {rseq_stat_inc (rseq_stats.signal); +/* -* Don't update IDs, they are handled on exit to user if +* Don't update IDs yet, they are handled on exit to user if * necessary. The important thing is to abort a critical section of * the interrupted context as after this point the instruction * pointer in @regs points to the signal handler.
@@ -344,6 +348,13 @@ void __rseq_signal_deliver(int sig, struct pt_regs *regs) current->rseq.event.error =0 ;force_sigsegv (sig); } + +/* +* In legacy mode, force the update of IDs before returning to user +* space to stay compatible. +*/ +if (!rseq_v2 (current)) +rseq_force_update (); }/*
@@ -408,6 +419,7 @@ static bool rseq_reset_ids(void) SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32, sig) {u32 rseqfl =0 ; +u8 version =1 ;if (flags &RSEQ_FLAG_UNREGISTER ) {if (flags & ~RSEQ_FLAG_UNREGISTER )
@@ -461,7 +473,11 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32if (!access_ok (rseq, rseq_len))return -EFAULT ; -if (IS_ENABLED (CONFIG_RSEQ_SLICE_EXTENSION )) { +/* +* The version check effectivly disables time slice extensions until the +* RSEQ ABI V2 registration are implemented. +*/ +if (IS_ENABLED (CONFIG_RSEQ_SLICE_EXTENSION ) && version >1 ) {if (rseq_slice_extension_enabled ()) { rseqfl |=RSEQ_CS_FLAG_SLICE_EXT_AVAILABLE ;if (flags &RSEQ_FLAG_SLICE_EXT_DEFAULT_ON )
@@ -484,7 +500,15 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32unsafe_put_user (RSEQ_CPU_ID_UNINITIALIZED , &rseq->cpu_id, efault);unsafe_put_user (0U , &rseq->node_id, efault);unsafe_put_user (0U , &rseq->mm_cid, efault); -unsafe_put_user (0U , &rseq->slice_ctrl.all, efault); + +/* +* All fields past mm_cid are only valid for non-legacy v2 +* registrations. +*/ +if (version >1 ) { +if (IS_ENABLED (CONFIG_RSEQ_SLICE_EXTENSION )) +unsafe_put_user (0U , &rseq->slice_ctrl.all, efault); + } }/*
@@ -712,6 +736,8 @@ int rseq_slice_extension_prctl(unsigned long arg2, unsigned long arg3)return -ENOTSUPP ;if (!current->rseq.usrptr)return -ENXIO ; +if (!rseq_v2 (current)) +return -ENOTSUPP ;/* No change? */ if (enable == !!current->rseq.slice.state.enabled)
kernel/sched/membarrier.c +10 -1
@@ -199,7 +199,16 @@ static void ipi_rseq(void *info)* is negligible. */ smp_mb (); -rseq_sched_switch_event (current); +/* +* Legacy mode requires that IDs are written and the critical section is +* evaluated. V2 optimized mode handles the critical section and IDs are +* only updated if they change as a consequence of preemption after +* return from this IPI. +*/ +if (rseq_v2 (current)) +rseq_sched_switch_event (current); +else +rseq_force_update (); }static void ipi_sync_rq_state (void *info)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1064/1146 rseq: Implement read only ABI enforcement for optimized RSEQ V2 mode
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit 82f572449cfe75f12ea985986da60e11f308f77d upstream.
The optimized RSEQ V2 mode requires that user space adheres to the ABI specification and does not modify the read-only fields cpu_id_start, cpu_id, node_id and mm_cid behind the kernel's back.
While the kernel does not rely on these fields, the adherence to this is a fundamental prerequisite to allow multiple entities, e.g. libraries, in an application to utilize the full potential of RSEQ without stepping on each other toes.
Validate this adherence on every update of these fields. If the kernel detects that user space modified the fields, the application is force terminated.
--- include/linux/rseq_entry.h | 83 ++++++++++++++------------------------ include/linux/rseq_types.h | 4 +- kernel/rseq.c | 5 +-- 3 files changed, 35 insertions(+), 57 deletions(-)
include/linux/rseq_entry.h +30 -53
@@ -238,7 +238,6 @@ static __always_inline bool rseq_grant_slice_extension(bool work_pending) { retu#endif /* !CONFIG_RSEQ_SLICE_EXTENSION */ bool rseq_debug_update_user_cs (struct task_struct *t,struct pt_regs *regs,unsigned long csaddr); -bool rseq_debug_validate_ids (struct task_struct *t); static __always_inline void rseq_note_user_irq_entry(void) {
@@ -358,43 +357,6 @@ bool rseq_debug_update_user_cs(struct task_struct *t, struct pt_regs *regs, return false; } -/* -* On debug kernels validate that user space did not mess with it if the -* debug branch is enabled. -*/ -bool rseq_debug_validate_ids (struct task_struct *t) -{ -struct rseq __user *rseq = t->rseq.usrptr; -u32 cpu_id, uval, node_id; - -/* -* On the first exit after registering the rseq region CPU ID is -* RSEQ_CPU_ID_UNINITIALIZED and node_id in user space is 0! -*/ - node_id = t->rseq.ids.cpu_id !=RSEQ_CPU_ID_UNINITIALIZED ? -cpu_to_node (t->rseq.ids.cpu_id) :0 ; - - scoped_user_read_access(rseq, efault) { -unsafe_get_user (cpu_id, &rseq->cpu_id_start, efault); -if (cpu_id != t->rseq.ids.cpu_id) - goto die; -unsafe_get_user (uval, &rseq->cpu_id, efault); -if (uval != cpu_id) - goto die; -unsafe_get_user (uval, &rseq->node_id, efault); -if (uval != node_id) - goto die; -unsafe_get_user (uval, &rseq->mm_cid, efault); -if (uval != t->rseq.ids.mm_cid) - goto die; - } -return true; -die: - t->rseq.event.fatal = true; -efault: -return false; -} -#endif /* RSEQ_BUILD_SLOW_PATH */ /*
@@ -504,20 +466,32 @@ rseq_update_user_cs(struct task_struct *t, struct pt_regs *regs, unsigned long c* faults in task context are fatal too. */ static rseq_inline -bool rseq_set_ids_get_csaddr(struct task_struct *t, struct rseq_ids *ids, -u32 node_id,u64 *csaddr) +bool rseq_set_ids_get_csaddr(struct task_struct *t, struct rseq_ids *ids, u64 *csaddr) {struct rseq __user *rseq = t->rseq.usrptr; -if (static_branch_unlikely (&rseq_debug_enabled)) { -if (!rseq_debug_validate_ids (t)) -return false; - } - scoped_user_rw_access(rseq, efault) { +/* Validate the R/O fields for debug and optimized mode */ +if (static_branch_unlikely (&rseq_debug_enabled) ||rseq_v2 (t)) { +u32 cpu_id, uval; + +unsafe_get_user (cpu_id, &rseq->cpu_id_start, efault); +if (cpu_id != t->rseq.ids.cpu_id) + goto die; +unsafe_get_user (uval, &rseq->cpu_id, efault); +if (uval != cpu_id) + goto die; +unsafe_get_user (uval, &rseq->node_id, efault); +if (uval != t->rseq.ids.node_id) + goto die; +unsafe_get_user (uval, &rseq->mm_cid, efault); +if (uval != t->rseq.ids.mm_cid) + goto die; + } +unsafe_put_user (ids->cpu_id, &rseq->cpu_id_start, efault);unsafe_put_user (ids->cpu_id, &rseq->cpu_id, efault); -unsafe_put_user (node_id, &rseq->node_id, efault); +unsafe_put_user (ids->node_id, &rseq->node_id, efault);unsafe_put_user (ids->mm_cid, &rseq->mm_cid, efault);if (csaddr)unsafe_get_user (*csaddr, &rseq->rseq_cs, efault);
@@ -529,10 +503,13 @@ bool rseq_set_ids_get_csaddr(struct task_struct *t, struct rseq_ids *ids,rseq_slice_clear_grant (t);/* Cache the new values */ - t->rseq.ids.cpu_cid = ids->cpu_cid; + t->rseq.ids = *ids;rseq_stat_inc (rseq_stats.ids);rseq_trace_update (t, ids);return true; + +die: + t->rseq.event.fatal = true; efault:return false; }
@@ -542,11 +519,11 @@ bool rseq_set_ids_get_csaddr(struct task_struct *t, struct rseq_ids *ids,* is in a critical section. */ static rseq_inline bool rseq_update_usr(struct task_struct *t, struct pt_regs *regs, -struct rseq_ids *ids,u32 node_id) +struct rseq_ids *ids) {u64 csaddr; -if (!rseq_set_ids_get_csaddr (t, ids, node_id, &csaddr)) +if (!rseq_set_ids_get_csaddr (t, ids, &csaddr))return false;/*
@@ -649,12 +626,12 @@ static __always_inline bool rseq_exit_user_update(struct pt_regs *regs, struct t }struct rseq_ids ids = { - .cpu_id =task_cpu (t), - .mm_cid =task_mm_cid (t), + .cpu_id =task_cpu (t), + .mm_cid =task_mm_cid (t), + .node_id =cpu_to_node (ids.cpu_id), }; -u32 node_id =cpu_to_node (ids.cpu_id); -return rseq_update_usr (t, regs, &ids, node_id); +return rseq_update_usr (t, regs, &ids); efault:return false; }
include/linux/rseq_types.h +3 -1
@@ -66,8 +66,9 @@ struct rseq_event {* compiler emit a single compare on 64-bit * @cpu_id: The CPU ID which was written last to user space * @mm_cid: The MM CID which was written last to user space +* @node_id: The node ID which was written last to user space * -* @cpu_id and @mm_cid are updated when the data is written to user space. +* @cpu_id, @mm_cid and @node_id are updated when the data is written to user space. */ struct rseq_ids { union {
@@ -77,6 +78,7 @@ struct rseq_ids {u32 mm_cid; }; }; +u32 node_id; };/**
kernel/rseq.c +2 -3
@@ -263,7 +263,6 @@ static void rseq_slowpath_update_usr(struct pt_regs *regs) };struct task_struct *t = current;struct rseq_ids ids; -u32 node_id;bool event;if (unlikely (t->flags &PF_EXITING ))
@@ -299,9 +298,9 @@ static void rseq_slowpath_update_usr(struct pt_regs *regs)if (!event)return ; - node_id =cpu_to_node (ids.cpu_id); + ids.node_id =cpu_to_node (ids.cpu_id); -if (unlikely (!rseq_update_usr (t, regs, &ids, node_id))) { +if (unlikely (!rseq_update_usr (t, regs, &ids))) {/* * Clear the errors just in case this might survive magically, but * leave the rest intact.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1065/1146 rseq: Reenable performance optimizations conditionally
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit 99428157dcf32fdac97355aa1cc1364dbc9e073c upstream.
Due to the incompatibility with TCMalloc the RSEQ optimizations and extended features (time slice extensions) have been disabled and made run-time conditional.
The original RSEQ implementation, which TCMalloc depends on, registers a 32 byte region (ORIG_RSEG_SIZE). This region has a 32 byte alignment requirement.
The extension safe newer variant exposes the kernel RSEQ feature size via getauxval(AT_RSEQ_FEATURE_SIZE) and the alignment requirement via getauxval(AT_RSEQ_ALIGN). The alignment requirement is that the registered RSEQ region is aligned to the next power of two of the feature size. The kernel currently has a feature size of 33 bytes, which means the alignment requirement is 64 bytes.
The TCMalloc RSEQ region is embedded into a cache line aligned data structure starting at offset 32 bytes so that bytes 28-31 and the cpu_id_start field at bytes 32-35 form a 64-bit little endian pointer with the top-most bit (63 set) to check whether the kernel has overwritten cpu_id_start with an actual CPU id value, which is guaranteed to not have the top most bit set.
As this is part of their performance tuned magic, it's a pretty safe assumption, that TCMalloc won't use a larger RSEQ size.
This allows the kernel to declare that registrations with a size greater than the original size of 32 bytes, which is the cases since time slice extensions got introduced, as RSEQ ABI v2 with the following differences to the original behaviour:
1) Unconditional updates of the user read only fields (CPU, node, MMCID) are removed. Those fields are only updated on registration, task migration and MMCID changes.
2) Unconditional evaluation of the criticial section pointer is removed. It's only evaluated when user space was interrupted and was scheduled out or before delivering a signal in the interrupted context.
3) The read/only requirement of the ID fields is enforced. When the kernel detects that userspace manipulated the fields, the process is terminated. This ensures that multiple entities (libraries) can utilize RSEQ without interfering.
4) Todays extended RSEQ feature (time slice extensions) and future extensions are only enabled in the v2 enabled mode.
Registrations with the original size of 32 bytes operate in backwards compatible legacy mode without performance improvements and extended features.
Unfortunately that also affects users of older GLIBC versions which register the original size of 32 bytes and do not evaluate the kernel required size in the auxiliary vector AT_RSEQ_FEATURE_SIZE.
That's the result of the lack of enforcement in the original implementation and the unwillingness of a single entity to cooperate with the larger ecosystem for many years.
Implement the required registration changes by restructuring the spaghetti code and adding the size/version check. Also add documentation about the differences of legacy and optimized RSEQ V2 mode.
Thanks to Mathieu for pointing out the ORIG_RSEQ_SIZE constraints!
--- Documentation/userspace-api/rseq.rst | 94 ++++++++++++++++- kernel/rseq.c | 144 ++++++++++++++++----------- 2 files changed, 178 insertions(+), 60 deletions(-)
Documentation/userspace-api/rseq.rst +93 -1
@@ -24,6 +24,97 @@ Quick access to CPU number, node ID Allows to implement per CPU data efficiently. Documentation is in code and selftests. :( +Optimized RSEQ V2 +----------------- + +On architectures which utilize the generic entry code and generic TIF bits +the kernel supports runtime optimizations for RSEQ, which also enable +enhanced features like scheduler time slice extensions. + +To enable them a task has to register the RSEQ region with at least the +length advertised by getauxval(AT_RSEQ_FEATURE_SIZE). + +If existing binaries register with RSEQ_ORIG_SIZE (32 bytes), the kernel +keeps the legacy low performance mode enabled to fulfil the expectations +of existing users regarding the original RSEQ implementation behaviour. + +The following table documents the ABI and behavioral guarantees of the +legacy and the optimized V2 mode. + +.. list-table:: RSEQ modes + :header-rows: 1 + + * - Nr + - What + + - Legacy + - Optimized V2 + + * - 1 + - The cpu_id_start, cpu_id, node_id and mm_cid fields (User mode read + only) + .. Legacy + - Updated by the kernel unconditionally after each context switch and + before signal delivery + .. Optimized V2 + - Updated by the kernel if and only if they change, i.e. if the task + is migrated or mm_cid changes + + * - 2 + - The rseq_cs critical section field + .. Legacy + - Evaluated and handled unconditionally after each context switch and + before signal delivery + .. Optimized V2 + - Evaluated and handled conditionally only when user space was + interrupted and was scheduled out or before delivering a signal in + the interrupted context. + + * - 3 + - Read only fields + .. Legacy + - No strict enforcement except in debug mode + .. Optimized V2 + - Strict enforcement + + * - 4 + - membarrier(...RSEQ) + .. Legacy + - All running threads of the process are interrupted and the ID fields + are rewritten and eventually active critical sections are aborted + before they return to user space. All threads which are scheduled + out whether voluntary or not are covered by #1/#2 above. + .. Optimized V2 + - All running threads of the process are interrupted and eventually + active critical sections are aborted before these threads return to + user space. The ID fields are only updated if changed as a + consequence of the interrupt. All threads which are scheduled out + whether voluntary or not are covered by #1/#2 above. + + * - 5 + - Time slice extensions + .. Legacy + - Not supported + .. Optimized V2 + - Supported + +The legacy mode is obviously less performant as it does unconditional +updates and critical section checks even if not strictly required by the +ABI contract. That can't be changed anymore as some users depend on that +observed behavior, which in turn enables them to violate the ABI and +overwrite the cpu_id_start field for their own purposes. This is obviously +discouraged as it renders RSEQ incompatible with the intended usage and +breaks the expectation of other libraries in the same application. + +The ABI compliant optimized v2 mode, which respects the read only fields, +does not require unconditional updates and therefore is way more +performant. The kernel validates the read only fields for compliance. If +user space modifies them, the process is killed. Compliant usage allows +multiple libraries in the same application to benefit from the RSEQ +functionality without disturbing each other. The ABI compliant optimized v2 +mode also enables extended RSEQ features like time slice extensions. + + Scheduler time slice extensions -------------------------------
@@ -37,7 +128,8 @@ The prerequisites for this functionality are: * Enabled at boot time (default is enabled) - * A rseq userspace pointer has been registered for the thread + * A rseq userspace pointer has been registered for the thread in + optimized V2 mode The thread has to enable the functionality via prctl(2)::
kernel/rseq.c +85 -59
172 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1066/1146 HID: core: Fix size_t specifier in hid_report_raw_event()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Chancellor <[email protected]>
[ Upstream commit 4d3a2a466b8d68d852a1f3bbf11204b718428dc4 ]
When building for 32-bit platforms, for which 'size_t' is 'unsigned int', there are warnings around using the incorrect format specifier to print bsize in hid_report_raw_event():
drivers/hid/hid-core.c:2054:29: error: format specifies type 'long' but the argument has type 'size_t' (aka 'unsigned int') [-Werror,-Wformat]
2053 | hid_warn_ratelimited(hid, "Event data for report %d is incorrect (%d vs %ld)\n",
| ~~~
| %zu
2054 | report->id, csize, bsize);
| ^~~~~
drivers/hid/hid-core.c:2076:29: error: format specifies type 'long' but the argument has type 'size_t' (aka 'unsigned int') [-Werror,-Wformat]
2075 | hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %ld)\n",
| ~~~
| %zu
2076 | report->id, rsize, bsize);
| ^~~~~Use the proper 'size_t' format specifier, '%zu', to clear up the warnings.
--- drivers/hid/hid-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hid/hid-core.c +2 -2
@@ -2046,7 +2046,7 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *return 0 ;if (unlikely (bsize < csize)) { -hid_warn_ratelimited (hid,"Event data for report %d is incorrect (%d vs %ld)\n" , +hid_warn_ratelimited (hid,"Event data for report %d is incorrect (%d vs %zu)\n" , report->id, csize, bsize);return -EINVAL ; }
@@ -2068,7 +2068,7 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 * rsize = max_buffer_size;if (bsize < rsize) { -hid_warn_ratelimited (hid,"Event data for report %d was too short (%d vs %ld)\n" , +hid_warn_ratelimited (hid,"Event data for report %d was too short (%d vs %zu)\n" , report->id, rsize, bsize);return -EINVAL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1067/1146 ata: libata-scsi: fix requeue of deferred ATA PASS-THROUGH commands
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Igor Pylypiv <[email protected]>
[ Upstream commit 8ebf408e7d463eee02c348a3c8277b95587b710d ]
Commit 0ea84089dbf6 ("ata: libata-scsi: avoid Non-NCQ command starvation") introduced ata_scsi_requeue_deferred_qc() to handle commands deferred during resets or NCQ failures. This deferral logic completed commands with DID_SOFT_ERROR to trigger a retry in the SCSI mid-layer.
However, DID_SOFT_ERROR is subject to scsi_cmd_retry_allowed() checks. ATA PASS-THROUGH commands sent via SG_IO ioctl have scmd->allowed set to zero. This causes the mid-layer to fail the command immediately instead of retrying, even though the command was never actually issued to the hardware.
Switch to DID_REQUEUE to ensure these commands are inserted back into the request queue regardless of retry limits.
--- drivers/ata/libata-scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/ata/libata-scsi.c +2 -2
@@ -1692,7 +1692,7 @@ void ata_scsi_requeue_deferred_qc(struct ata_port *ap)/* * If we have a deferred qc when a reset occurs or NCQ commands fail, * do not try to be smart about what to do with this deferred command -* and simply retry it by completing it with DID_SOFT_ERROR. +* and simply requeue it by completing it with DID_REQUEUE. */ if (!qc)return ;
@@ -1701,7 +1701,7 @@ void ata_scsi_requeue_deferred_qc(struct ata_port *ap) ap->deferred_qc =NULL ;cancel_work (&ap->deferred_qc_work);ata_qc_free (qc); - scmd->result = (DID_SOFT_ERROR <<16 ); + scmd->result = (DID_REQUEUE <<16 );scsi_done (scmd); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1068/1146 media: staging: imx: configure src_mux in csi_start
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Tretter <[email protected]>
[ Upstream commit ebeec2b000a90cd8aae86d1931ff5ef23af8284e ]
After media_pipeline_start() was called, the media graph is assumed to be validated. It won't be validated again if a second stream starts.
The imx-media-csi driver, however, changes hardware configuration in the link_validate() callback. This can result in started streams with misconfigured hardware.
In the concrete example, the ipu2_csi1 is driven by a parallel video input. After the media pipeline has been started with this configuration, a second stream is configured to use ipu1_csi0 with MIPI-CSI input from imx6-mipi-csi2. This may require the reconfiguration of ipu1_csi0 with ipu_set_csi_src_mux(). Since the media pipeline is already running, link_validate won't be called, and the ipu1_csi0 won't be reconfigured. The resulting video is broken, because the ipu1_csi0 is misconfigured, but no error is reported.
Move ipu_set_csi_src_mux from csi_link_validate to csi_start to ensure that input to ipu1_csi0 is configured correctly when starting the stream. This is a local reconfiguration in ipu1_csi0 and is possible while the media pipeline is running.
Since csi_start() is called with priv->lock already locked, csi_set_src() must not lock priv->lock again. Thus, the mutex_lock() is dropped.
--- drivers/staging/media/imx/imx-media-csi.c | 44 ++++++++++++----------- 1 file changed, 24 insertions(+), 20 deletions(-)
drivers/staging/media/imx/imx-media-csi.c +24 -20
@@ -744,6 +744,28 @@ static int csi_setup(struct csi_priv *priv,return 0 ; } +static void csi_set_src (struct csi_priv *priv, +struct v4l2_mbus_config *mbus_cfg) +{ +bool is_csi2; + + is_csi2 = !is_parallel_bus (mbus_cfg); +if (is_csi2) { +/* +* NOTE! It seems the virtual channels from the mipi csi-2 +* receiver are used only for routing by the video mux's, +* or for hard-wired routing to the CSI's. Once the stream +* enters the CSI's however, they are treated internally +* in the IPU as virtual channel 0. +*/ +ipu_csi_set_mipi_datatype (priv->csi,0 , + &priv->format_mbus[CSI_SINK_PAD ]); + } + +/* select either parallel or MIPI-CSI2 as input to CSI */ +ipu_set_csi_src_mux (priv->ipu, priv->csi_id, is_csi2); +} +static int csi_start (struct csi_priv *priv) {struct v4l2_mbus_config mbus_cfg = { .type =0 };
@@ -760,6 +782,8 @@ static int csi_start(struct csi_priv *priv) input_fi = &priv->frame_interval[CSI_SINK_PAD ]; output_fi = &priv->frame_interval[priv->active_output_pad]; +csi_set_src (priv, &mbus_cfg); +/* start upstream */ ret =v4l2_subdev_call (priv->src_sd, video, s_stream,1 ); ret = (ret && ret != -ENOIOCTLCMD ) ? ret :0 ;
@@ -1130,7 +1154,6 @@ static int csi_link_validate(struct v4l2_subdev *sd, {struct csi_priv *priv =v4l2_get_subdevdata (sd);struct v4l2_mbus_config mbus_cfg = { .type =0 }; -bool is_csi2;int ret; ret = v4l2_subdev_link_validate_default(sd, link,
@@ -1145,25 +1168,6 @@ static int csi_link_validate(struct v4l2_subdev *sd,return ret; } -mutex_lock (&priv->lock); - - is_csi2 = !is_parallel_bus (&mbus_cfg); -if (is_csi2) { -/* -* NOTE! It seems the virtual channels from the mipi csi-2 -* receiver are used only for routing by the video mux's, -* or for hard-wired routing to the CSI's. Once the stream -* enters the CSI's however, they are treated internally -* in the IPU as virtual channel 0. -*/ -ipu_csi_set_mipi_datatype (priv->csi,0 , - &priv->format_mbus[CSI_SINK_PAD ]); - } - -/* select either parallel or MIPI-CSI2 as input to CSI */ -ipu_set_csi_src_mux (priv->ipu, priv->csi_id, is_csi2); - -mutex_unlock (&priv->lock);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1069/1146 Bluetooth: btmtk: accept too short WMT FUNC_CTRL events
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
commit e3ac0d9f1a205f33a43fba3b79ef74d2f604c78b upstream.
MT7925 (USB ID 0e8d:e025) on fw version 20260106153314 sends WMT FUNC_CTRL events that are missing the status field.
Prior to commit 006b9943b982 ("Bluetooth: btmtk: validate WMT event SKB length before struct access") the status was read from out-of-bounds of SKB data, which usually would result to success with BTMTK_WMT_ON_UNDONE, although I don't know the intent here. The bounds check added in that commit returns with error instead, producing "Bluetooth: hci0: Failed to send wmt func ctrl (-22)" and makes the device unusable.
Fix the regression by interpreting too short packet as status BTMTK_WMT_ON_UNDONE, which makes the device work normally again.
--- drivers/bluetooth/btmtk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/bluetooth/btmtk.c +2 -2
@@ -678,8 +678,8 @@ static int btmtk_usb_hci_wmt_sync(structcase BTMTK_WMT_FUNC_CTRL :if (!skb_pull_data (data->evt_skb,sizeof (wmt_evt_funcc->status))) { - err = -EINVAL ; - goto err_free_skb; + status =BTMTK_WMT_ON_UNDONE ; +break ; } wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
Greg Kroah-Hartman
maintainerPATCH 1070/1146 nvme-apple: Reset q->sq_tail during queue init
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nick Chan <[email protected]>
commit a6ab75639e23169a741b0b2e12191fd8acb32c73 upstream.
Fixes a "duplicate tag error for tag 0" firmware crash during controller reset while setting up a queue on Apple A11 / T8015 caused by stale entries in the submission queue due to an invalid sq_tail offset after reset.
--- drivers/nvme/host/apple.c | 1 + 1 file changed, 1 insertion(+)
drivers/nvme/host/apple.c +1 -0
@@ -1009,6 +1009,7 @@ static void apple_nvme_init_queue(structunsigned int depth =apple_nvme_queue_depth (q);struct apple_nvme *anv =queue_to_apple_nvme (q); + q->sq_tail =0 ; q->cq_head =0 ; q->cq_phase =1 ;if (anv->hw->has_lsq_nvmmu)
Greg Kroah-Hartman
maintainerPATCH 1071/1146 smb/client: fix possible infinite loop and oob read in symlink_data()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ye Bin <[email protected]>
commit 7d9a7f1f96cd617ee9e75bb22217c709038e26b8 upstream.
On 32-bit architectures, the infinite loop is as follows:
len = p->ErrorDataLength == 0xfffffff8
u8 *next = p->ErrorContextData + len
next == p
On 32-bit architectures, the out-of-bounds read is as follows:
len = p->ErrorDataLength == 0xfffffff0
u8 *next = p->ErrorContextData + len
next == (u8 *)p - 8
--- fs/smb/client/smb2file.c | 3 +++ 1 file changed, 3 insertions(+)
fs/smb/client/smb2file.c +3 -0
@@ -49,6 +49,9 @@ static struct smb2_symlink_err_rsp *syml __func__, le32_to_cpu(p->ErrorId)); len =ALIGN (le32_to_cpu (p->ErrorDataLength),8 ); +if (len > end - ((u8 *)p +sizeof (*p))) +return ERR_PTR (-EINVAL ); + p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len); } } else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) &&
Greg Kroah-Hartman
maintainerPATCH 1072/1146 drm/loongson: Use managed KMS polling
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 0a9c56dd387605d17dabeedd9fdd2c4c1d0bab7b upstream.
lsdc_pci_probe() initializes KMS polling before setting up vblank support, requesting the IRQ and registering the DRM device. If any of those later steps fails, probe returns without finalizing polling. The driver also never finalizes polling on regular removal.
Use drmm_kms_helper_poll_init() so polling is tied to the DRM device lifetime and automatically finalized on probe failure and device removal.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/gpu/drm/loongson/lsdc_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/loongson/lsdc_drv.c +1 -1
@@ -292,7 +292,7 @@ static int lsdc_pci_probe(struct pci_devvga_client_register (pdev, lsdc_vga_set_decode); -drm_kms_helper_poll_init (ddev); +drmm_kms_helper_poll_init (ddev);if (loongson_vblank) { ret =drm_vblank_init (ddev, descp->num_of_crtc);
Greg Kroah-Hartman
maintainerPATCH 1073/1146 drm: Replace old pointer to new idr
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <[email protected]>
commit dc366607c41c45fd0ae6f3db090f31dd611b644a upstream.
Commit 5e28b7b94408 introduced a logical error by failing to replace the newly generated IDR pointer to old id's pointer at the correct location within the "change handle" logic; this resulted in the issue reported by syzbot [1].
Specifically, the new IDR object pointer is intended to replace the original id's pointer during the normal execution flow.
Additionally, an unnecessary conditional check for the ret exit path has been removed.
[1]
!RB_EMPTY_ROOT(&prime_fpriv->dmabufs)
WARNING: drivers/gpu/drm/drm_prime.c:224 at drm_prime_destroy_file_private+0x48/0x60 drivers/gpu/drm/drm_prime.c:224, CPU#0: syz.0.17/5833 Call Trace: drm_file_free.part.0+0x7e6/0xcc0 drivers/gpu/drm/drm_file.c:269 drm_file_free drivers/gpu/drm/drm_file.c:237 [inline] drm_close_helper.isra.0+0x186/0x200 drivers/gpu/drm/drm_file.c:290 drm_release+0x1ab/0x360 drivers/gpu/drm/drm_file.c:438
--- drivers/gpu/drm/drm_gem.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/gpu/drm/drm_gem.c +2 -5
@@ -1049,17 +1049,12 @@ int drm_gem_change_handle_ioctl(struct dspin_unlock (&file_priv->table_lock); -if (ret <0 ) - goto out_unlock; -if (obj->dma_buf) { ret =drm_prime_add_buf_handle (&file_priv->prime, obj->dma_buf, handle);if (ret <0 ) {spin_lock (&file_priv->table_lock);idr_remove (&file_priv->object_idr, handle); - idrobj =idr_replace (&file_priv->object_idr, obj, handle); -WARN_ON (idrobj !=NULL );spin_unlock (&file_priv->table_lock); goto out_unlock; }
@@ -1071,7 +1066,9 @@ int drm_gem_change_handle_ioctl(struct dspin_lock (&file_priv->table_lock);idr_remove (&file_priv->object_idr, args->handle); + idrobj =idr_replace (&file_priv->object_idr, obj, handle);spin_unlock (&file_priv->table_lock); +WARN_ON (idrobj !=NULL ); out_unlock:mutex_unlock (&file_priv->prime.lock);
Greg Kroah-Hartman
maintainerPATCH 1074/1146 drm/bridge: imx8qxp-pxl2dpi: avoid ERR_PTR with device_node cleanup
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 53597deca0e38c30e6cd4ba2114fa42d2bcd85bb upstream.
imx8qxp_pxl2dpi_get_available_ep_from_port() returns ERR_PTR() on errors. imx8qxp_pxl2dpi_find_next_bridge() stores its return value in a __free(device_node) variable before checking IS_ERR(). When the function returns on the error path, the cleanup action calls of_node_put() on the ERR_PTR() value.
Do not let a device_node cleanup variable hold error pointers. Change imx8qxp_pxl2dpi_get_available_ep_from_port() to return an int and pass the endpoint node through an output argument. Initialize the output argument to NULL so callers hold either NULL on error paths or a valid device_node pointer on successful path.
--- drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 40 +++++++++++++++------------ 1 file changed, 23 insertions(+), 17 deletions(-)
drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c +23 -17
@@ -222,52 +222,58 @@ static const struct drm_bridge_funcs imx imx8qxp_pxl2dpi_bridge_atomic_get_output_bus_fmts, }; -static struct device_node * +static int imx8qxp_pxl2dpi_get_available_ep_from_port (struct imx8qxp_pxl2dpi *p2d, -u32 port_id) +u32 port_id, +struct device_node **ep) { -struct device_node *port, *ep; +struct device_node *port; +int ret =0 ;int ep_cnt; + *ep =NULL ; + port =of_graph_get_port_by_id (p2d->dev->of_node, port_id);if (!port) {DRM_DEV_ERROR (p2d->dev,"failed to get port@%u\n" , port_id); -return ERR_PTR (-ENODEV ); +return -ENODEV ; } ep_cnt =of_get_available_child_count (port);if (ep_cnt ==0 ) {DRM_DEV_ERROR (p2d->dev,"no available endpoints of port@%u\n" , port_id); - ep =ERR_PTR (-ENODEV ); + ret = -ENODEV ; goto out; }else if (ep_cnt >1 ) {DRM_DEV_ERROR (p2d->dev,"invalid available endpoints of port@%u\n" , port_id); - ep =ERR_PTR (-EINVAL ); + ret = -EINVAL ; goto out; } - ep =of_get_next_available_child (port,NULL ); -if (!ep) { + *ep =of_get_next_available_child (port,NULL ); +if (!*ep) {DRM_DEV_ERROR (p2d->dev,"failed to get available endpoint of port@%u\n" , port_id); - ep =ERR_PTR (-ENODEV ); + ret = -ENODEV ; goto out; } out:of_node_put (port); -return ep; +return ret; }static int imx8qxp_pxl2dpi_find_next_bridge (struct imx8qxp_pxl2dpi *p2d) { - struct device_node *ep __free(device_node) = -imx8qxp_pxl2dpi_get_available_ep_from_port (p2d,1 ); -if (IS_ERR (ep)) -return PTR_ERR (ep); + struct device_node *ep __free(device_node) = NULL; +int ret; + + ret =imx8qxp_pxl2dpi_get_available_ep_from_port (p2d,1 , &ep); +if (ret) +return ret; struct device_node *remote __free(device_node) = of_graph_get_remote_port_parent(ep);if (!remote || !of_device_is_available (remote)) {
@@ -291,9 +297,9 @@ static int imx8qxp_pxl2dpi_set_pixel_linstruct of_endpoint endpoint;int ret; - ep =imx8qxp_pxl2dpi_get_available_ep_from_port (p2d,0 ); -if (IS_ERR (ep)) -return PTR_ERR (ep); + ret =imx8qxp_pxl2dpi_get_available_ep_from_port (p2d,0 , &ep); +if (ret) +return ret; ret =of_graph_parse_endpoint (ep, &endpoint);if (ret) {
Greg Kroah-Hartman
maintainerPATCH 1075/1146 drm/i915/dp: Fix VSC dynamic range signaling for RGB formats
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chaitanya Kumar Borah <[email protected]>
commit 1ae15b6c7965d137eef21f2cc7d367b29cb88369 upstream.
For RGB, set dynamic_range to CTA or VESA based on crtc_state->limited_color_range so sinks apply correct quantization. YCbCr remains limited (CTA) range. (DP v1.4, Table 5-1)
v2:
- Added Reported-by and Tested-by tags
v3:
- Add back YCbCr comment(Suraj)
--- drivers/gpu/drm/i915/display/intel_dp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/display/intel_dp.c +7 -2
@@ -2981,8 +2981,13 @@ static void intel_dp_compute_vsc_colorimdrm_WARN_ON (display->drm, vsc->bpc ==6 && vsc->pixelformat !=DP_PIXELFORMAT_RGB ); -/* all YCbCr are always limited range */ - vsc->dynamic_range =DP_DYNAMIC_RANGE_CTA ; +/* All YCbCr formats are always limited range. */ +if (vsc->pixelformat ==DP_PIXELFORMAT_RGB ) + vsc->dynamic_range = crtc_state->limited_color_range ? +DP_DYNAMIC_RANGE_CTA :DP_DYNAMIC_RANGE_VESA ; +else + vsc->dynamic_range =DP_DYNAMIC_RANGE_CTA ; + vsc->content_type =DP_CONTENT_TYPE_NOT_DEFINED ; }
Greg Kroah-Hartman
maintainerPATCH 1076/1146 drm/amd/display: Wrap DCN32 phantom-plane allocation in DC_RUN_WITH_PREEMPTION_ENABLED
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Gavrilov <[email protected]>
commit 183182235f6d53bac62c6c39014738a54a68dfa6 upstream.
[Why]dcn32_validate_bandwidth() wraps dcn32_internal_validate_bw() with DC_FP_START()/DC_FP_END(). In x86 non-RT, DC_FP_START takes fpregs_lock(), which disables local softirqs.
The DML1 path through dcn32_enable_phantom_plane() calls kvzalloc() to allocate ~335 KiB for dc_plane_state. This triggers the vmalloc path, which calls BUG_ON(in_interrupt()) because it's invoked within the FPU-enabled (softirq disabled) region, leading to a kernel crash.
[How]
Wrap the dc_state_create_phantom_plane() call with the DC_RUN_WITH_PREEMPTION_ENABLED() macro to allow preemption during this memory allocation.
--- drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +7 -1
@@ -92,9 +92,14 @@#include "dml/dcn32/dcn32_fpu.h" #include "dc_state_priv.h" +#include "dc_fpu.h" #include "dml2_0/dml2_wrapper.h" +#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED ) +#define DC_RUN_WITH_PREEMPTION_ENABLED (code) code +#endif +#define DC_LOGGER_INIT (logger)enum dcn32_clk_src_array_id {
@@ -1684,7 +1689,8 @@ static void dcn32_enable_phantom_plane(sif (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state) phantom_plane = prev_phantom_plane;else - phantom_plane =dc_state_create_phantom_plane (dc, context, curr_pipe->plane_state); +DC_RUN_WITH_PREEMPTION_ENABLED (phantom_plane = +dc_state_create_phantom_plane (dc, context, curr_pipe->plane_state));if (!phantom_plane)continue ;
Greg Kroah-Hartman
maintainerPATCH 1077/1146 drm/ttm: Fix ttm_bo_swapout() infinite LRU walk on swapout failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Hellström <[email protected]>
commit b2ed01e7ad3de80333e9b962a44024b094bc0b2b upstream.
When ttm_tt_swapout() fails, the current code calls ttm_resource_add_bulk_move() followed by ttm_resource_move_to_lru_tail() to restore the resource's bulk_move membership.
However, ttm_resource_move_to_lru_tail() places the resource at the tail of the LRU list which, relative to the walk cursor's hitch node (placed immediately after the resource when it was yielded), puts the resource *in front of the* the hitch. The next list_for_each_entry_continue() from the hitch finds the same resource again, causing an infinite loop.
Fix by deferring del_bulk_move to the success path only.
On the success path, TTM_TT_FLAG_SWAPPED has just been set by ttm_tt_swapout() but the resource is still tracked in the bulk_move range, so ttm_resource_del_bulk_move()'s !ttm_resource_unevictable() guard would incorrectly skip the removal. Introduce ttm_resource_del_bulk_move_unevictable() which bypasses that guard.
--- drivers/gpu/drm/ttm/ttm_bo.c | 16 ++++++---------- drivers/gpu/drm/ttm/ttm_resource.c | 13 +++++++++++++ include/drm/ttm/ttm_resource.h | 2 ++ 3 files changed, 21 insertions(+), 10 deletions(-)
drivers/gpu/drm/ttm/ttm_bo.c +6 -10
@@ -1178,17 +1178,13 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *w bdev->funcs->swap_notify (bo);if (ttm_tt_is_populated (tt)) { -spin_lock (&bdev->lru_lock); -ttm_resource_del_bulk_move (bo->resource, bo); -spin_unlock (&bdev->lru_lock); - ret =ttm_tt_swapout (bdev, tt, swapout_walk->gfp_flags); - -spin_lock (&bdev->lru_lock); -if (ret) -ttm_resource_add_bulk_move (bo->resource, bo); -ttm_resource_move_to_lru_tail (bo->resource); -spin_unlock (&bdev->lru_lock); +if (!ret) { +spin_lock (&bdev->lru_lock); +ttm_resource_del_bulk_move_unevictable (bo->resource, bo); +ttm_resource_move_to_lru_tail (bo->resource); +spin_unlock (&bdev->lru_lock); + } } out:
drivers/gpu/drm/ttm/ttm_resource.c +13 -0
@@ -292,6 +292,19 @@ void ttm_resource_del_bulk_move(struct tttm_lru_bulk_move_del (bo->bulk_move, res); } +/* +* Remove a resource from its bulk_move, bypassing the unevictable check. +* Use only when the resource is known to still be tracked in the range despite +* the BO having just become unevictable; asserts that this is the case. +*/ +void ttm_resource_del_bulk_move_unevictable (struct ttm_resource *res, +struct ttm_buffer_object *bo) +{ +WARN_ON_ONCE (!ttm_resource_unevictable (res, bo)); +if (bo->bulk_move) +ttm_lru_bulk_move_del (bo->bulk_move, res); +} +/* Move a resource to the LRU or bulk tail */ void ttm_resource_move_to_lru_tail (struct ttm_resource *res) {
include/drm/ttm/ttm_resource.h +2 -0
@@ -448,6 +448,8 @@ void ttm_resource_add_bulk_move(struct t struct ttm_buffer_object *bo);void ttm_resource_del_bulk_move (struct ttm_resource *res,struct ttm_buffer_object *bo); +void ttm_resource_del_bulk_move_unevictable (struct ttm_resource *res, +struct ttm_buffer_object *bo);void ttm_resource_move_to_lru_tail (struct ttm_resource *res); void ttm_resource_init(struct ttm_buffer_object *bo,
Greg Kroah-Hartman
maintainerPATCH 1078/1146 platform/x86: intel: Move debugfs register before creating devices
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Pandruvada <[email protected]>
commit ad3bff944c0f4f2e913298a9664391af32f87491 upstream.
It is possible that the driver handling device is enumerated before registering debugfs. If the driver wants to access debugfs by calling tpmi_get_debugfs_dir(), this will return error in this case.
Hence register debugfs before creating devices.
--- drivers/platform/x86/intel/vsec_tpmi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/platform/x86/intel/vsec_tpmi.c +6 -4
@@ -813,10 +813,6 @@ static int intel_vsec_tpmi_init(struct aauxiliary_set_drvdata (auxdev, tpmi_info); - ret =tpmi_create_devices (tpmi_info); -if (ret) -return ret; -/* * Allow debugfs when security policy allows. Everything this debugfs * interface provides, can also be done via /dev/mem access. If
@@ -826,6 +822,12 @@ static int intel_vsec_tpmi_init(struct aif (!security_locked_down (LOCKDOWN_DEV_MEM ) &&capable (CAP_SYS_RAWIO ))tpmi_dbgfs_register (tpmi_info); + ret =tpmi_create_devices (tpmi_info); +if (ret) { +debugfs_remove_recursive (tpmi_info->dbgfs_dir); +return ret; + } +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 1079/1146 platform/x86: lenovo-wmi-helpers: Move gamezone enums to wmi-helpers
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Derek J. Clark <[email protected]>
commit 7e27896e16a1c450085c3fe020eeb1b223880f37 upstream.
In a later patch in the series the thermal mode enum will be accessed across three separate drivers (wmi-capdata, wmi-gamezonem and wmi-other). An additional patch in the series will also add a function prototype that needs to reference this enum in wmi-helpers.h. To avoid having all these drivers begin to import each others headers, and to avoid declaring an opaque enum to hande the second case, move the thermal mode enum to helpers where it can be safely accessed by everything that needs it from a single import.
While at it, since the gamezone_events_type enum is the only remaining item in the header, move that as well and remove the gamezone header entirely.
--- drivers/platform/x86/lenovo/wmi-events.c | 2 +- drivers/platform/x86/lenovo/wmi-gamezone.c | 1 - drivers/platform/x86/lenovo/wmi-gamezone.h | 20 -------------------- drivers/platform/x86/lenovo/wmi-helpers.h | 13 +++++++++++++ drivers/platform/x86/lenovo/wmi-other.c | 1 - 5 files changed, 14 insertions(+), 23 deletions(-) delete mode 100644 drivers/platform/x86/lenovo/wmi-gamezone.h
drivers/platform/x86/lenovo/wmi-events.c +1 -1
@@ -17,7 +17,7 @@#include <linux/wmi.h> #include "wmi-events.h" -#include "wmi-gamezone.h" +#include "wmi-helpers.h" #define THERMAL_MODE_EVENT_GUID "D320289E-8FEA-41E0-86F9-911D83151B5F"
drivers/platform/x86/lenovo/wmi-gamezone.c +0 -1
@@ -21,7 +21,6 @@#include <linux/wmi.h> #include "wmi-events.h" -#include "wmi-gamezone.h" #include "wmi-helpers.h" #include "wmi-other.h"
drivers/platform/x86/lenovo/wmi-gamezone.h deleted +0 -20
@@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/* Copyright (C) 2025 Derek J. Clark <[email protected]> */ - -#ifndef _LENOVO_WMI_GAMEZONE_H_ -#define _LENOVO_WMI_GAMEZONE_H_ - -enum gamezone_events_type { -LWMI_GZ_GET_THERMAL_MODE =1 , -}; - -enum thermal_mode { -LWMI_GZ_THERMAL_MODE_QUIET =0x01 , -LWMI_GZ_THERMAL_MODE_BALANCED =0x02 , -LWMI_GZ_THERMAL_MODE_PERFORMANCE =0x03 , -LWMI_GZ_THERMAL_MODE_EXTREME =0xE0 ,/* Ver 6+ */ -LWMI_GZ_THERMAL_MODE_CUSTOM =0xFF , -}; - -#endif /* !_LENOVO_WMI_GAMEZONE_H_ */
drivers/platform/x86/lenovo/wmi-helpers.h +13 -0
@@ -14,6 +14,19 @@ struct wmi_method_args_32 {u32 arg1; }; +enum lwmi_event_type { +LWMI_GZ_GET_THERMAL_MODE =0x01 , +}; + +enum thermal_mode { +LWMI_GZ_THERMAL_MODE_NONE =0x00 , +LWMI_GZ_THERMAL_MODE_QUIET =0x01 , +LWMI_GZ_THERMAL_MODE_BALANCED =0x02 , +LWMI_GZ_THERMAL_MODE_PERFORMANCE =0x03 , +LWMI_GZ_THERMAL_MODE_EXTREME =0xE0 ,/* Ver 6+ */ +LWMI_GZ_THERMAL_MODE_CUSTOM =0xFF , +}; +int lwmi_dev_evaluate_int (struct wmi_device *wdev,u8 instance,u32 method_id,unsigned char *buf,size_t size,u32 *retval);
drivers/platform/x86/lenovo/wmi-other.c +0 -1
@@ -47,7 +47,6 @@#include "wmi-capdata.h" #include "wmi-events.h" -#include "wmi-gamezone.h" #include "wmi-helpers.h" #include "wmi-other.h" #include "../firmware_attributes_class.h"
Greg Kroah-Hartman
maintainerPATCH 1080/1146 platform/x86: lenovo-wmi-helpers: Fix memory leak in lwmi_dev_evaluate_int()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rong Zhang <[email protected]>
commit 0c3887a134f191723b53e2a47e501b534c8723ee upstream.
lwmi_dev_evaluate_int() leaks output.pointer when retval == NULL (found by sashiko.dev [1]).
Fix it by moving ret_obj = output.pointer' outside of the if (retval)' block so that it is always freed by the __free cleanup callback.
No functional change intended.
--- drivers/platform/x86/lenovo/wmi-helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/platform/x86/lenovo/wmi-helpers.c +2 -2
@@ -46,7 +46,6 @@ int lwmi_dev_evaluate_int(struct wmi_dev unsigned char *buf, size_t size, u32 *retval) { struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *ret_obj __free(kfree) = NULL;struct acpi_buffer input = { size, buf };acpi_status status;
@@ -55,8 +54,9 @@ int lwmi_dev_evaluate_int(struct wmi_devif (ACPI_FAILURE (status))return -EIO ; + union acpi_object *ret_obj __free(kfree) = output.pointer; +if (retval) { - ret_obj = output.pointer;if (!ret_obj)return -ENODATA ;
Greg Kroah-Hartman
maintainerPATCH 1081/1146 platform/x86: lenovo-wmi-other: Balance IDA id allocation and free
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rong Zhang <[email protected]>
commit 55a279ae819adaea99a94c609f31970b70e0ec0c upstream.
Currently, the IDA id is only freed on wmi-other device removal or failure to create firmware-attributes device, kset, or attributes. It leaks IDA ids if the wmi-other device is bound multiple times, as the unbind callback never frees the previously allocated IDA id. Additionally, if the wmi-other device has failed to create a firmware-attributes device before it gets removed, the wmi-device removal callback double frees the same IDA id.
These bugs were found by sashiko.dev [1].
Fix them by moving ida_free() into lwmi_om_fw_attr_remove() so it is balanced with ida_alloc() in lwmi_om_fw_attr_add(). With them fixed, properly set and utilize the validity of priv->ida_id to balance firmware-attributes registration and removal, without relying on propagating the registration error to the component framework, which is more reliable and aligns with the hwmon device registration and removal sequences.
No functional change intended.
--- drivers/platform/x86/lenovo/wmi-other.c | 36 ++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 15 deletions(-)
drivers/platform/x86/lenovo/wmi-other.c +21 -15
@@ -956,17 +956,17 @@ static struct capdata01_attr_group cd01_/** * lwmi_om_fw_attr_add() - Register all firmware_attributes_class members * @priv: The Other Mode driver data. -* -* Return: Either 0, or an error code. */ -static int lwmi_om_fw_attr_add (struct lwmi_om_priv *priv) +static void lwmi_om_fw_attr_add (struct lwmi_om_priv *priv) {unsigned int i;int err; - priv->ida_id =ida_alloc (&lwmi_om_ida,GFP_KERNEL ); -if (priv->ida_id <0 ) -return priv->ida_id; + err =ida_alloc (&lwmi_om_ida,GFP_KERNEL ); +if (err <0 ) + goto err_no_ida; + + priv->ida_id = err; priv->fw_attr_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), NULL, "%s-%u",
@@ -992,7 +992,7 @@ static int lwmi_om_fw_attr_add(struct lw cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; } -return 0 ; +return ; err_remove_groups:while (i--)
@@ -1006,7 +1006,12 @@ err_destroy_classdev: err_free_ida:ida_free (&lwmi_om_ida, priv->ida_id); -return err; + +err_no_ida: + priv->ida_id = -EIDRM ; + +dev_warn (&priv->wdev->dev, +"failed to register firmware-attributes device: %d\n" , err); }/**
@@ -1015,12 +1020,17 @@ err_free_ida:*/ static void lwmi_om_fw_attr_remove (struct lwmi_om_priv *priv) { +if (priv->ida_id <0 ) +return ; +for (unsigned int i =0 ; i <ARRAY_SIZE (cd01_attr_groups) -1 ; i++)sysfs_remove_group (&priv->fw_attr_kset->kobj, cd01_attr_groups[i].attr_group);kset_unregister (priv->fw_attr_kset);device_unregister (priv->fw_attr_dev); +ida_free (&lwmi_om_ida, priv->ida_id); + priv->ida_id = -EIDRM ; }/* ======== Self (master: lenovo-wmi-other) ======== */
@@ -1062,7 +1072,9 @@ static int lwmi_om_master_bind(struct delwmi_om_fan_info_collect_cd00 (priv); -return lwmi_om_fw_attr_add (priv); +lwmi_om_fw_attr_add (priv); + +return 0 ; }/**
@@ -1114,13 +1126,7 @@ static int lwmi_other_probe(struct wmi_dstatic void lwmi_other_remove (struct wmi_device *wdev) { -struct lwmi_om_priv *priv =dev_get_drvdata (&wdev->dev); -component_master_del (&wdev->dev, &lwmi_om_master_ops); - -/* No IDA to free if the driver is never bound to its components. */ -if (priv->ida_id >=0 ) -ida_free (&lwmi_om_ida, priv->ida_id); }static const struct wmi_device_id lwmi_other_id_table[] = {
Greg Kroah-Hartman
maintainerPATCH 1082/1146 platform/x86: lenovo-wmi-other: Balance component bind and unbind
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rong Zhang <[email protected]>
commit 2fe2504abcfa4f82a4208e8d0c21ec0f22baca43 upstream.
When lwmi_om_master_bind() fails, the master device's components are left bound, with the aggregate device destroyed due to the failure (found by sashiko.dev [1]).
Balance calls to component_bind_all() and component_unbind_all() when an error is propagated to the component framework.
No functional change intended.
--- drivers/platform/x86/lenovo/wmi-other.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/platform/x86/lenovo/wmi-other.c +4 -1
@@ -1067,8 +1067,11 @@ static int lwmi_om_master_bind(struct de priv->cd00_list = binder.cd00_list; priv->cd01_list = binder.cd01_list; -if (!priv->cd00_list || !priv->cd01_list) +if (!priv->cd00_list || !priv->cd01_list) { +component_unbind_all (dev,NULL ); +return -ENODEV ; + }lwmi_om_fan_info_collect_cd00 (priv);
Greg Kroah-Hartman
maintainerPATCH 1083/1146 platform/x86: lenovo-wmi-other: Zero initialize WMI arguments
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Derek J. Clark <[email protected]>
commit 816fbd5dacee977ca56bab79bf97f71f2f7ac24e upstream.
Adds explicit initialization of wmi_method_args_32 declarations with zero values to prevent uninitialized data from being sent to the device BIOS when passed.
No functional change intended.
--- drivers/platform/x86/lenovo/wmi-gamezone.c | 2 +- drivers/platform/x86/lenovo/wmi-other.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/platform/x86/lenovo/wmi-gamezone.c +1 -1
@@ -200,7 +200,7 @@ static int lwmi_gz_profile_set(struct de enum platform_profile_option profile) {struct lwmi_gz_priv *priv =dev_get_drvdata (dev); -struct wmi_method_args_32 args; +struct wmi_method_args_32 args = {};enum thermal_mode mode;int ret;
drivers/platform/x86/lenovo/wmi-other.c +3 -3
@@ -165,7 +165,7 @@ MODULE_PARM_DESC(relax_fan_constraint,*/ static int lwmi_om_fan_get_set (struct lwmi_om_priv *priv,int channel,u32 *val,bool set) { -struct wmi_method_args_32 args; +struct wmi_method_args_32 args = {};u32 method_id, retval;int err;
@@ -772,7 +772,7 @@ static ssize_t attr_current_value_store( struct tunable_attr_01 *tunable_attr) {struct lwmi_om_priv *priv =dev_get_drvdata (tunable_attr->dev); -struct wmi_method_args_32 args; +struct wmi_method_args_32 args = {};struct capdata01 capdata;enum thermal_mode mode;u32 attribute_id;
@@ -835,7 +835,7 @@ static ssize_t attr_current_value_show(s struct tunable_attr_01 *tunable_attr) {struct lwmi_om_priv *priv =dev_get_drvdata (tunable_attr->dev); -struct wmi_method_args_32 args; +struct wmi_method_args_32 args = {};enum thermal_mode mode;u32 attribute_id;int retval;
Greg Kroah-Hartman
maintainerPATCH 1084/1146 platform/x86: lenovo-wmi-other: Fix tunable_attr_01 struct members
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Derek J. Clark <[email protected]>
commit 71f3843e0f81e3c097a088c1121154bb9a44da0a upstream.
In struct tunable_attr_01 the capdata pointer is unused and the size of the id members is u32 when it should be u8. Fix these prior to adding additional members.
No functional change intended.
--- drivers/platform/x86/lenovo/wmi-other.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/platform/x86/lenovo/wmi-other.c +3 -4
@@ -545,11 +545,10 @@ out:/* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */ struct tunable_attr_01 { -struct capdata01 *capdata;struct device *dev; -u32 feature_id; -u32 device_id; -u32 type_id; +u8 feature_id; +u8 device_id; +u8 type_id; };static struct tunable_attr_01 ppt_pl1_spl = {
Greg Kroah-Hartman
maintainerPATCH 1085/1146 platform/x86: lenovo-wmi-other: Add Attribute ID helper functions
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Derek J. Clark <[email protected]>
commit 30a4ad208a7f7bdb790cd31d368595890045334f upstream.
Adds lwmi_attr_id() function. In the same vein as LWMI_ATTR_ID_FAN_RPM(), but as a generic, to de-duplicate attribute_id assignment boilerplate.
Adds tunable_attr_01_id() function that breaks out the members of a tunable_attr_01 struct and passes them to lwmi_attr_id().
No functional change intended.
--- drivers/platform/x86/lenovo/wmi-capdata.c | 8 ++-- drivers/platform/x86/lenovo/wmi-capdata.h | 20 ++++++++++++ drivers/platform/x86/lenovo/wmi-other.c | 49 ++++++++++++------------------ 3 files changed, 44 insertions(+), 33 deletions(-)
drivers/platform/x86/lenovo/wmi-capdata.c +4 -4
@@ -27,7 +27,6 @@#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt#include <linux/acpi.h> -#include <linux/bitfield.h> #include <linux/bug.h> #include <linux/cleanup.h> #include <linux/component.h>
@@ -48,6 +47,7 @@#include <linux/wmi.h> #include "wmi-capdata.h" +#include "wmi-helpers.h" #define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E"#define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"
@@ -58,9 +58,9 @@#define LWMI_FEATURE_ID_FAN_TEST 0x05 -#define LWMI_ATTR_ID_FAN_TEST \ - (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ - FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_TEST)) +#define LWMI_ATTR_ID_FAN_TEST \ + lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_TEST, \ + LWMI_GZ_THERMAL_MODE_NONE, LWMI_TYPE_ID_NONE)enum lwmi_cd_type {LENOVO_CAPABILITY_DATA_00 ,
drivers/platform/x86/lenovo/wmi-capdata.h +20 -0
@@ -6,6 +6,7 @@#define _LENOVO_WMI_CAPDATA_H_#include <linux/bits.h> +#include <linux/bitfield.h> #include <linux/types.h> #define LWMI_SUPP_VALID BIT(0)
@@ -19,6 +20,8 @@#define LWMI_DEVICE_ID_FAN 0x04 +#define LWMI_TYPE_ID_NONE 0x00 +struct component_match ;struct device ;struct cd_list ;
@@ -57,6 +60,23 @@ struct lwmi_cd_binder {cd_list_cb_t cd_fan_list_cb; }; +/** +* lwmi_attr_id() - Formats a capability data attribute ID +* @dev_id: The u8 corresponding to the device ID. +* @feat_id: The u8 corresponding to the feature ID on the device. +* @mode_id: The u8 corresponding to the wmi-gamezone mode for set/get. +* @type_id: The u8 corresponding to the sub-device. +* +* Return: encoded capability data attribute ID. +*/ +static inline u32 lwmi_attr_id (u8 dev_id,u8 feat_id,u8 mode_id,u8 type_id) +{ +return (FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , dev_id) | +FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , feat_id) | +FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode_id) | +FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , type_id)); +} +void lwmi_cd_match_add_all (struct device *master,struct component_match **matchptr);int lwmi_cd00_get_data (struct cd_list *list,u32 attribute_id,struct capdata00 *output);int lwmi_cd01_get_data (struct cd_list *list,u32 attribute_id,struct capdata01 *output);
drivers/platform/x86/lenovo/wmi-other.c +20 -29
106 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 1086/1146 platform/x86: lenovo-wmi-other: Limit adding attributes to supported devices
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Derek J. Clark <[email protected]>
commit 03bb5147da083cb91e5c8c2599fcb2f8fd05cb8f upstream.
Adds lwmi_is_attr_01_supported, and only creates the attribute subfolder if the attribute is supported by the hardware. Due to some poorly implemented BIOS this is a multi-step sequence of events. This is because:
- Some BIOS support getting the capability data from custom mode (0xff), while others only support it in no-mode (0x00).
- Some BIOS support get/set for the current value from custom mode (0xff), while others only support it in no-mode (0x00).
- Some BIOS report capability data for a method that is not fully implemented.
- Some BIOS have methods fully implemented, but no complimentary capability data.
To ensure we only expose fully implemented methods with corresponding capability data, we check each outcome before reporting that an attribute can be supported.
Checking for lwmi_is_attr_01_supported during remove is not done to ensure that we don't attempt to call cd01 or send WMI events if one of the interfaces being removed was the cause of the driver unloading.
--- drivers/platform/x86/lenovo/wmi-other.c | 92 ++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 4 deletions(-)
drivers/platform/x86/lenovo/wmi-other.c +88 -4
@@ -546,6 +546,8 @@ struct tunable_attr_01 {u8 feature_id;u8 device_id;u8 type_id; +u8 cd_mode_id;/* mode arg for searching capdata */ +u8 cv_mode_id;/* mode arg for set/get current_value */ };/**
@@ -723,7 +725,7 @@ static ssize_t attr_capdata01_show(strucu32 attribute_id;int value, ret; - attribute_id =tunable_attr_01_id (tunable_attr,LWMI_GZ_THERMAL_MODE_CUSTOM ); + attribute_id =tunable_attr_01_id (tunable_attr, tunable_attr->cd_mode_id); ret =lwmi_cd01_get_data (priv->cd01_list, attribute_id, &capdata);if (ret)
@@ -788,7 +790,7 @@ static ssize_t attr_current_value_store(if (mode !=LWMI_GZ_THERMAL_MODE_CUSTOM )return -EBUSY ; - args.arg0 =tunable_attr_01_id (tunable_attr, mode); + args.arg0 =tunable_attr_01_id (tunable_attr, tunable_attr->cd_mode_id); ret =lwmi_cd01_get_data (priv->cd01_list, args.arg0, &capdata);if (ret)
@@ -801,6 +803,7 @@ static ssize_t attr_current_value_store(if (value < capdata.min_value || value > capdata.max_value)return -EINVAL ; + args.arg0 =tunable_attr_01_id (tunable_attr, tunable_attr->cv_mode_id); args.arg1 = value; ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,
@@ -841,6 +844,10 @@ static ssize_t attr_current_value_show(sif (ret)return ret; +/* If "no-mode" is the supported mode, ensure we never send current mode */ +if (tunable_attr->cv_mode_id ==LWMI_GZ_THERMAL_MODE_NONE ) + mode = tunable_attr->cv_mode_id; + args.arg0 =tunable_attr_01_id (tunable_attr, mode); ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET,
@@ -852,6 +859,81 @@ static ssize_t attr_current_value_show(sreturn sysfs_emit (buf,"%d\n" , retval); } +/** +* lwmi_attr_01_is_supported() - Determine if the given attribute is supported. +* @tunable_attr: The attribute to verify. +* +* For an attribute to be supported it must have a functional get/set method, +* as well as associated capability data stored in the capdata01 table. +* +* First check if the attribute has a corresponding data table under custom mode +* (0xff), then under no mode (0x00). If either of those passes, check if the +* supported field of the capdata struct is > 0. If it is supported, store the +* successful mode in the cd_mode_id field of tunable_attr. +* +* If the attribute capdata shows it is supported, attempt to determine the mode +* for the current value property get/set methods using a similar pattern to the +* capdata table check. If the value returned by either mode is 0 or an error, +* assume that mode is not supported. Otherwise, store the successful mode in the +* cv_mode_id field of tunable_attr. +* +* If any of the above checks fail then the attribute is not fully supported. +* +* Return: true if capdata and set/get modes are found, otherwise false. +*/ +static bool lwmi_attr_01_is_supported (struct tunable_attr_01 *tunable_attr) +{ +u8 modes[2 ] = {LWMI_GZ_THERMAL_MODE_CUSTOM ,LWMI_GZ_THERMAL_MODE_NONE }; +struct lwmi_om_priv *priv =dev_get_drvdata (tunable_attr->dev); +struct wmi_method_args_32 args = {}; +bool cd_mode_found = false; +bool cv_mode_found = false; +struct capdata01 capdata; +int retval, ret, i; + +/* Determine tunable_attr->cd_mode_id */ +for (i =0 ; i <ARRAY_SIZE (modes); i++) { + args.arg0 =tunable_attr_01_id (tunable_attr, modes[i]); + + ret =lwmi_cd01_get_data (priv->cd01_list, args.arg0, &capdata); +if (ret || !capdata.supported) +continue ; + + tunable_attr->cd_mode_id = modes[i]; + cd_mode_found = true; +break ; + } + +if (!cd_mode_found) +return cd_mode_found; + +dev_dbg (tunable_attr->dev, +"cd_mode_id: %#010x\n" , args.arg0); + +/* Determine tunable_attr->cv_mode_id, returns 1 if supported */ +for (i =0 ; i <ARRAY_SIZE (modes); i++) { + args.arg0 =tunable_attr_01_id (tunable_attr, modes[i]); + + ret =lwmi_dev_evaluate_int (priv->wdev,0x0 ,LWMI_FEATURE_VALUE_GET , + (u8 *)&args,sizeof (args), + &retval); +if (ret || !retval) +continue ; + + tunable_attr->cv_mode_id = modes[i]; + cv_mode_found = true; +break ; + } + +if (!cv_mode_found) +return cv_mode_found; + +dev_dbg (tunable_attr->dev,"cv_mode_id: %#010x, attribute support level: %#010x\n" , + args.arg0, capdata.supported); + +return capdata.supported >0 ; +} +/* Lenovo WMI Other Mode Attribute macros */ #define __LWMI_ATTR_RO (_func, _name) \ { \
@@ -975,12 +1057,14 @@ static void lwmi_om_fw_attr_add(struct l }for (i =0 ; i <ARRAY_SIZE (cd01_attr_groups) -1 ; i++) { + cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; +if (!lwmi_attr_01_is_supported (cd01_attr_groups[i].tunable_attr)) +continue ; + err =sysfs_create_group (&priv->fw_attr_kset->kobj, cd01_attr_groups[i].attr_group);if (err) goto err_remove_groups; - - cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; }return ;
Greg Kroah-Hartman
maintainerPATCH 1087/1146 accel/rocket: Fix prep_bo ioctl leaking positive return from dma_resv_wait_timeout()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gyeyoung Baek <[email protected]>
commit 74570e12b4705ea11dcdfbfbd0a0b0fdaeff3059 upstream.
dma_resv_wait_timeout() returns a positive 'remaining jiffies' value on success, 0 on timeout, and -errno on failure.
rocket_ioctl_prep_bo() returns this 'long' result from an int-typed ioctl handler, so positive values reach userspace as bogus errors. Explicitly set ret to 0 on the success path.
--- drivers/accel/rocket/rocket_gem.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/accel/rocket/rocket_gem.c +2 -0
@@ -145,6 +145,8 @@ int rocket_ioctl_prep_bo(struct drm_devi ret =dma_resv_wait_timeout (gem_obj->resv,DMA_RESV_USAGE_WRITE , true, timeout);if (!ret) ret = timeout ? -ETIMEDOUT : -EBUSY ; +else if (ret >0 ) + ret =0 ; shmem_obj = &to_rocket_bo (gem_obj)->base;
Greg Kroah-Hartman
maintainerPATCH 1088/1146 ALSA: hda/realtek: Add mute LED quirk for HP Pavilion Laptop 16-ag0xxx
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrien Burnett <[email protected]>
commit 7d1051ad68df3d584b5f24bfa1fb19f3a24db278 upstream.
Add a SND_PCI_QUIRK entry for the HP Pavilion Laptop 16-ag0xxx (subsystem 0x103c:0x8cbc, Realtek ALC245). The ALC245_FIXUP_HP_X360_MUTE_LEDS fixup is already used by the neighbouring HP Pavilion Aero Laptop 13-bg0xxx (0x103c:0x8cbd); it chains the master-mute COEF handler with the GPIO mic-mute LED handler, which is what this machine needs.
Tested on the affected hardware: both the mute and mic-mute key LEDs respond correctly to the keyboard hotkeys after this change.
--- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+)
sound/hda/codecs/realtek/alc269.c +1 -0
@@ -7146,6 +7146,7 @@ static const struct hda_quirk alc269_fixSND_PCI_QUIRK (0x103c ,0x8ca4 ,"HP ZBook Fury" ,ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED ),SND_PCI_QUIRK (0x103c ,0x8ca7 ,"HP ZBook Fury" ,ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED ),SND_PCI_QUIRK (0x103c ,0x8caf ,"HP Elite mt645 G8 Mobile Thin Client" ,ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF ), +SND_PCI_QUIRK (0x103c ,0x8cbc ,"HP Pavilion Laptop 16-ag0xxx" ,ALC245_FIXUP_HP_X360_MUTE_LEDS ),SND_PCI_QUIRK (0x103c ,0x8cbd ,"HP Pavilion Aero Laptop 13-bg0xxx" ,ALC245_FIXUP_HP_X360_MUTE_LEDS ),SND_PCI_QUIRK (0x103c ,0x8cdd ,"HP Spectre" ,ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX ), SND_PCI_QUIRK(0x103c, 0x8cde, "HP OmniBook Ultra Flip Laptop 14t", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
Greg Kroah-Hartman
maintainerPATCH 1089/1146 ALSA: hda/realtek: Add quirk for Samsung Galaxy Book5 360 headphone
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Markus Kramer <[email protected]>
commit fd87b510f5f543125ecf51e7c706a9f4bc3352be upstream.
The Samsung Galaxy Book5 360 (NP750QHA, PCI subsystem ID 0x144d:0xc902) has severe audio distortion on the 3.5mm headphone jack. Applying ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET corrects the output path configuration, consistent with fixes already applied to other Samsung Galaxy Book models using the same ALC256 codec.
--- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+)
sound/hda/codecs/realtek/alc269.c +1 -0
@@ -7448,6 +7448,7 @@ static const struct hda_quirk alc269_fixSND_PCI_QUIRK (0x144d ,0xc870 ,"Samsung Galaxy Book2 Pro (NP950XED)" ,ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS ),SND_PCI_QUIRK (0x144d ,0xc872 ,"Samsung Galaxy Book2 Pro (NP950XEE)" ,ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS ),SND_PCI_QUIRK (0x144d ,0xc886 ,"Samsung Galaxy Book3 Pro (NP964XFG)" ,ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS ), +SND_PCI_QUIRK (0x144d ,0xc902 ,"Samsung Galaxy Book5 360 (NP750QHA)" ,ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET ),SND_PCI_QUIRK (0x144d ,0xc1ca ,"Samsung Galaxy Book3 Pro 360 (NP960QFG)" ,ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS ),SND_PCI_QUIRK (0x144d ,0xc1cb ,"Samsung Galaxy Book3 Pro 360 (NP965QFG)" ,ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS ), SND_PCI_QUIRK(0x144d, 0xc1cc, "Samsung Galaxy Book3 Ultra (NT960XFH)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
Greg Kroah-Hartman
maintainerPATCH 1090/1146 ALSA: usb-audio: Bound MIDI 2.0 endpoint descriptor scans
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cássio Gabriel <[email protected]>
commit 918be519c7876329e1b6e2ea1c59f0b75e792dca upstream.
The USB MIDI 2.0 endpoint parser has the same descriptor walking pattern as the legacy MIDI parser. It validates bLength against bNumGrpTrmBlock before reading baAssoGrpTrmBlkID[], but not against the remaining bytes in the endpoint-extra scan.
A malformed device can therefore make later baAssoGrpTrmBlkID[] reads consume bytes past the walked descriptor.
Reject zero-length and overlong descriptors while walking endpoint extras.
--- sound/usb/midi2.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
sound/usb/midi2.c +7 -5
@@ -496,15 +496,17 @@ static void *find_usb_ms_endpoint_descriwhile (extralen >3 ) {struct usb_ms_endpoint_descriptor *ms_ep = (struct usb_ms_endpoint_descriptor *)extra; +int length = ms_ep->bLength; -if (ms_ep->bLength >3 && +if (!length || length > extralen) +break ; + +if (length >3 && ms_ep->bDescriptorType ==USB_DT_CS_ENDPOINT && ms_ep->bDescriptorSubtype == subtype)return ms_ep; -if (!extra[0 ]) -break ; - extralen -= extra[0 ]; - extra += extra[0 ]; + extralen -= length; + extra += length; }return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 1091/1146 ALSA: usb-audio: Bound MIDI endpoint descriptor scans
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cássio Gabriel <[email protected]>
commit d6854daa67be623860f4e1873fd3d3c275aba4ed upstream.
snd_usbmidi_get_ms_info() validates the internal MIDIStreaming endpoint descriptor size before using baAssocJackID[], but the descriptor walker can still return a class-specific endpoint descriptor whose bLength exceeds the remaining bytes in the endpoint-extra scan.
That leaves later flexible-array reads bounded by bLength, but not by the remaining bytes in the endpoint-extra scan.
Stop walking when bLength is zero or
extends past the remaining endpoint-extra scan.
--- sound/usb/midi.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
sound/usb/midi.c +7 -5
@@ -1947,15 +1947,17 @@ static struct usb_ms_endpoint_descriptorwhile (extralen >3 ) {struct usb_ms_endpoint_descriptor *ms_ep = (struct usb_ms_endpoint_descriptor *)extra; +int length = ms_ep->bLength; -if (ms_ep->bLength >3 && +if (!length || length > extralen) +break ; + +if (length >3 && ms_ep->bDescriptorType ==USB_DT_CS_ENDPOINT && ms_ep->bDescriptorSubtype ==UAC_MS_GENERAL )return ms_ep; -if (!extra[0 ]) -break ; - extralen -= extra[0 ]; - extra += extra[0 ]; + extralen -= length; + extra += length; }return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 1092/1146 ALSA: usb-audio: qcom: Check offload mapping failures
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cássio Gabriel <[email protected]>
commit 814b2c9b30e56074e11fc0a6e5419b3fee0639bc upstream.
uaudio_transfer_buffer_setup() calls dma_get_sgtable() and then passes the sg_table to uaudio_iommu_map_xfer_buf() without checking whether sg table construction succeeded. If dma_get_sgtable() fails, the sg_table contents are not valid.
uaudio_iommu_map_pa() also ignores iommu_map() failures for the event and transfer rings and still returns the allocated IOVA to the QMI response. That can expose an unmapped IOVA to the audio DSP. For transfer rings, the failed mapping also leaves the IOVA allocator state marked in use.
Check both operations. Free the coherent transfer buffer when sg table construction fails, free the sg table when transfer-buffer IOMMU mapping fails, and release the transfer-ring IOVA if iommu_map() fails. Also return the existing event-ring IOVA when the event ring is already mapped, matching the pre-split helper behavior.
--- sound/usb/qcom/qc_audio_offload.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-)
sound/usb/qcom/qc_audio_offload.c +25 -6
@@ -565,6 +565,7 @@ static unsigned long uaudio_iommu_map_paunsigned long iova =0 ;bool map = true;int prot =uaudio_iommu_map_prot (dma_coherent); +int ret;switch (mtype) {case MEM_EVENT_RING :
@@ -582,10 +583,24 @@ static unsigned long uaudio_iommu_map_padev_err (uaudio_qdev->data->dev,"unknown mem type %d\n" , mtype); } -if (!iova || !map) +if (!iova)return 0 ; -iommu_map (uaudio_qdev->data->domain, iova, pa, size, prot,GFP_KERNEL ); +if (!map) +return iova; + + ret =iommu_map (uaudio_qdev->data->domain, iova, pa, size, prot, +GFP_KERNEL ); +if (ret) { +dev_err (uaudio_qdev->data->dev, +"failed to map %zu bytes at iova 0x%08lx: %d\n" , + size, iova, ret); +if (mtype ==MEM_XFER_RING ) +uaudio_put_iova (iova, size, + &uaudio_qdev->xfer_ring_list, + &uaudio_qdev->xfer_ring_iova_size); +return 0 ; + }return iova; }
@@ -1054,15 +1069,17 @@ static int uaudio_transfer_buffer_setup(if (!xfer_buf)return -ENOMEM ; -dma_get_sgtable (subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf, - xfer_buf_dma, len); + ret =dma_get_sgtable (subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf, + xfer_buf_dma, len); +if (ret) + goto free_xfer_buf;/* map the physical buffer into sysdev as well */ xfer_buf_dma_sysdev =uaudio_iommu_map_xfer_buf (dma_coherent, len, &xfer_buf_sgt);if (!xfer_buf_dma_sysdev) { ret = -ENOMEM ; - goto unmap_sync; + goto free_sgt; } mem_info->dma = xfer_buf_dma;
@@ -1073,7 +1090,9 @@ static int uaudio_transfer_buffer_setup(return 0 ; -unmap_sync: +free_sgt: +sg_free_table (&xfer_buf_sgt); +free_xfer_buf:usb_free_coherent (subs->dev, len, xfer_buf, xfer_buf_dma);return ret;
Greg Kroah-Hartman
maintainerPATCH 1093/1146 btrfs: only release the dirty pages io tree after successful writes
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
commit 4066c55e109475a06d18a1f127c939d551211956 upstream.
[WARNING]
With extra warning on dirty extent buffers at umount (aka, the next patch in the series), test case generic/388 can trigger the following warning about dirty extent buffers at unmount time:
BTRFS critical (device dm-2 state E): emergency shutdown
BTRFS error (device dm-2 state E): error while writing out transaction: -30
BTRFS warning (device dm-2 state E): Skipping commit of aborted transaction.
BTRFS error (device dm-2 state EA): Transaction 9 aborted (error -30)
BTRFS: error (device dm-2 state EA) in cleanup_transaction:2068: errno=-30 Readonly filesystem BTRFS info (device dm-2 state EA): forced readonly
BTRFS info (device dm-2 state EA): last unmount of filesystem 4fbf2e15-f941-49a0-bc7c-716315d2777c
------------[ cut here ]------------ WARNING: disk-io.c:3311 at invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs], CPU#8: umount/914368 CPU: 8 UID: 0 PID: 914368 Comm: umount Tainted: G OE 7.1.0-rc1-custom+ #372 PREEMPT(full) 2de38db8d1deae71fde295430a0ff3ab98ccf596 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022 RIP: 0010:invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs] Call Trace: <TASK> close_ctree+0x52e/0x574 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd] generic_shutdown_super+0x89/0x1a0 kill_anon_super+0x16/0x40 btrfs_kill_super+0x16/0x20 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd] deactivate_locked_super+0x2d/0xb0 cleanup_mnt+0xdc/0x140 task_work_run+0x5a/0xa0 exit_to_user_mode_loop+0x123/0x4b0 do_syscall_64+0x243/0x7c0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 </TASK> ---[ end trace 0000000000000000 ]--- BTRFS warning (device dm-2 state EA): unable to release extent buffer 30539776 owner 9 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30621696 owner 257 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30638080 owner 258 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30654464 owner 7 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30703616 owner 2 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30720000 owner 10 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30736384 owner 4 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30752768 owner 11 gen 9 refs 2 flags 0x7
I'm using a stripped down version, which seems to trigger the warning more reliably:
_fsstress_pid=""
workload()
{
dmesg -C
mkfs.btrfs -f -K $dev > /dev/null
echo 1 > /sys/kernel/debug/clear_warn_once
mount $dev $mnt
$fsstress -w -n 1024 -p 4 -d $mnt &
_fsstress_pid=$!
sleep 0
$godown $mnt
pkill --echo -PIPE fsstress > /dev/null
wait $_fsstress_pid
unset _fsstress_pid
umount $mnt if dmesg | grep -q "WARNING"; then
fail
fi
}
for (( i = 0; i < $runtime; i++ )); do
echo "=== $i/$runtime ==="
workload
done
[CAUSE]
Inside btrfs_write_and_wait_transaction(), we first try to write all dirty ebs, then wait for them to finish.
After that we call btrfs_extent_io_tree_release() to free all extent states from dirty_pages io tree.
However if we hit an error from btrfs_write_marked_extent(), then we still call btrfs_extent_io_tree_release() to clear that dirty_pages io tree, which may contain dirty records that we haven't yet submitted.
Furthermore, the later transaction cleanup path will utilize that dirty_pages io tree to properly cleanup those dirty ebs, but since it's already empty, no dirty ebs are properly cleaned up, thus will later trigger the warnings inside invalidate_btree_folios().
[FIX]
Normally such dirty ebs won't cause problems, as when the iput() is called on the btree inode, the dirty ebs will be forcibly written back, and since the fs is already in an error status, such writeback will not reach disk and finish immediately.
But it's still better to get rid of such dirty ebs, if we ended up with dirty ebs but the fs is not in an error status, then such writeback at iput() time will be too late, as all workers are already stopped but writeback will utilize workers, which will lead to NULL pointer dereferences.
Instead of unconditionally calling btrfs_extent_io_tree_release(), only call it if btrfs_write_and_wait_transaction() finished successfully, so that @dirty_pages extent io tree is kept untouched for transaction cleanup.
--- fs/btrfs/disk-io.c | 1 + fs/btrfs/transaction.c | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-)
fs/btrfs/disk-io.c +1 -0
@@ -4709,6 +4709,7 @@ static void btrfs_destroy_marked_extentsfree_extent_buffer_stale (eb); } } +btrfs_extent_io_tree_release (dirty_pages); } static void btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
fs/btrfs/transaction.c +4 -5
@@ -1275,14 +1275,13 @@ static int btrfs_write_and_wait_transactblk_finish_plug (&plug); ret2 =btrfs_wait_extents (fs_info, dirty_pages); -btrfs_extent_io_tree_release (&trans->transaction->dirty_pages); -if (ret)return ret; -else if (ret2) +if (ret2)return ret2; -else -return 0 ; + +btrfs_extent_io_tree_release (&trans->transaction->dirty_pages); +return 0 ; }/*
Greg Kroah-Hartman
maintainerPATCH 1094/1146 ceph: fix a buffer leak in __ceph_setxattr()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viacheslav Dubeyko <[email protected]>
commit 5d3cc36b4e77a27ce7b686b7c59c7072bcb3fa8e upstream.
The old_blob in __ceph_setxattr() can store ci->i_xattrs.prealloc_blob value during the retry. However, it is never called the ceph_buffer_put() for the old_blob object. This patch fixes the issue of the buffer leak.
--- fs/ceph/xattr.c | 1 + 1 file changed, 1 insertion(+)
fs/ceph/xattr.c +1 -0
@@ -1294,6 +1294,7 @@ retry: do_sync:spin_unlock (&ci->i_ceph_lock); +ceph_buffer_put (old_blob); do_sync_unlocked:if (lock_snap_rwsem)up_read (&mdsc->snap_rwsem);
Greg Kroah-Hartman
maintainerPATCH 1095/1146 ceph: fix BUG_ON in __ceph_build_xattrs_blob() due to stale blob size
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viacheslav Dubeyko <[email protected]>
commit 0c22d9511cbde746622f8e4c11aaa63fe76d45f9 upstream.
The generic/642 test-case can reproduce the kernel crash:
[40243.605254] ------------[ cut here ]------------ [40243.605956] kernel BUG at fs/ceph/xattr.c:918! [40243.607142] Oops: invalid opcode: 0000 [#1] SMP PTI [40243.608067] CPU: 7 UID: 0 PID: 498762 Comm: kworker/7:1 Not tainted 7.0.0-rc7+ #3 PREEMPT(full) [40243.609700] 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 [40243.611820] Workqueue: ceph-msgr ceph_con_workfn [40243.612715] RIP: 0010:__ceph_build_xattrs_blob+0x1b8/0x1e0 [40243.613731] Code: 0f 84 82 fe ff ff e9 cf 8e 56 ff 48 8d 65 e8 31 c0 5b 41 5c 41 5d 5d 31 d2 31 c9 31 f6 31 ff 45 31 c0 45 31 c9 c3 cc cc cc cc <0f> 0b 4c 8b 62 08 41 8b 85 24 07 00 00 49 83 c4 04 41 89 44 24 fc [40243.616888] RSP: 0018:ffffcc80c4d4b688 EFLAGS: 00010287 [40243.617773] RAX: 0000000000010026 RBX: 0000000000000001 RCX: 0000000000000000 [40243.618928] RDX: ffff8a773798dee0 RSI: 0000000000000000 RDI: 0000000000000000 [40243.620158] RBP: ffffcc80c4d4b6a0 R08: 0000000000000000 R09: 0000000000000000 [40243.621573] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8a75f3b58000 [40243.622907] R13: ffff8a75f3b58000 R14: 0000000000000080 R15: 000000000000bffd [40243.624054] FS: 0000000000000000(0000) GS:ffff8a787d1b4000(0000) knlGS:0000000000000000 [40243.625331] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [40243.626269] CR2: 000072f390b623c0 CR3: 000000011c02a003 CR4: 0000000000372ef0 [40243.627408] Call Trace: [40243.627839] <TASK> [40243.628188] __prep_cap+0x3fd/0x4a0 [40243.628789] ? do_raw_spin_unlock+0x4e/0xe0 [40243.629474] ceph_check_caps+0x46a/0xc80 [40243.630094] ? __lock_acquire+0x4a2/0x2650 [40243.630773] ? find_held_lock+0x31/0x90 [40243.631347] ? handle_cap_grant+0x79f/0x1060 [40243.632068] ? lock_release+0xd9/0x300 [40243.632696] ? __mutex_unlock_slowpath+0x3e/0x340 [40243.633429] ? lock_release+0xd9/0x300 [40243.634052] handle_cap_grant+0xcf6/0x1060 [40243.634745] ceph_handle_caps+0x122b/0x2110 [40243.635415] mds_dispatch+0x5bd/0x2160 [40243.636034] ? ceph_con_process_message+0x65/0x190 [40243.636828] ? lock_release+0xd9/0x300 [40243.637431] ceph_con_process_message+0x7a/0x190 [40243.638184] ? kfree+0x311/0x4f0 [40243.638749] ? kfree+0x311/0x4f0 [40243.639268] process_message+0x16/0x1a0 [40243.639915] ? sg_free_table+0x39/0x90 [40243.640572] ceph_con_v2_try_read+0xf58/0x2120 [40243.641255] ? lock_acquire+0xc8/0x300 [40243.641863] ceph_con_workfn+0x151/0x820 [40243.642493] process_one_work+0x22f/0x630 [40243.643093] ? process_one_work+0x254/0x630 [40243.643770] worker_thread+0x1e2/0x400 [40243.644332] ? __pfx_worker_thread+0x10/0x10 [40243.645020] kthread+0x109/0x140 [40243.645560] ? __pfx_kthread+0x10/0x10 [40243.646125] ret_from_fork+0x3f8/0x480 [40243.646752] ? __pfx_kthread+0x10/0x10 [40243.647316] ? __pfx_kthread+0x10/0x10 [40243.647919] ret_from_fork_asm+0x1a/0x30 [40243.648556] </TASK> [40243.648902] Modules linked in: overlay hctr2 libpolyval chacha libchacha adiantum libnh libpoly1305 essiv intel_rapl_msr intel_rapl_common intel_uncore_frequency_common skx_edac_common nfit kvm_intel kvm irqbypass joydev ghash_clmulni_intel aesni_intel rapl input_leds mac_hid psmouse vga16fb serio_raw vgastate floppy i2c_piix4 pata_acpi bochs qemu_fw_cfg i2c_smbus sch_fq_codel rbd dm_crypt msr parport_pc ppdev lp parport efi_pstore [40243.654766] ---[ end trace 0000000000000000 ]---
Commit d93231a6bc8a ("ceph: prevent a client from exceeding the MDS maximum xattr size") moved the required_blob_size computation to before the __build_xattrs() call, introducing a race.
__build_xattrs() releases and reacquires i_ceph_lock during execution. In that window, handle_cap_grant() may update i_xattrs.blob with a newer MDS-provided blob and bump i_xattrs.version. When __build_xattrs() detects that index_version < version, it destroys and rebuilds the entire xattr rb-tree from the new blob, potentially increasing count, names_size, and vals_size.
The prealloc_blob size check that follows still uses the stale required_blob_size computed before the rebuild, so it passes even when prealloc_blob is too small for the now-larger tree. After __set_xattr() adds one more xattr on top, __ceph_build_xattrs_blob() is called from the cap flush path and hits:
BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len);
Fix this by recomputing required_blob_size after __build_xattrs() returns, using the current tree state. Also re-validate against m_max_xattr_size to fall back to the sync path if the rebuilt tree now exceeds the MDS limit.
--- fs/ceph/xattr.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
fs/ceph/xattr.c +16 -0
@@ -1254,6 +1254,22 @@ retry: ceph_vinop(inode), name, ceph_cap_string(issued));__build_xattrs (inode); +/* +* __build_xattrs() may have released and reacquired i_ceph_lock, +* during which handle_cap_grant() could have replaced i_xattrs.blob +* with a newer MDS-provided blob and bumped i_xattrs.version. If that +* caused __build_xattrs() to rebuild the rb-tree from the new blob, +* count/names_size/vals_size may now be larger than when +* required_blob_size was computed above. Recompute it here so the +* prealloc_blob size check below reflects the current tree state. +*/ + required_blob_size =__get_required_blob_size (ci, name_len, val_len); +if (required_blob_size > mdsc->mdsmap->m_max_xattr_size) { +doutc (cl,"sync (size too large): %d > %llu\n" , + required_blob_size, mdsc->mdsmap->m_max_xattr_size); + goto do_sync; + } +if (!ci->i_xattrs.prealloc_blob || required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {struct ceph_buffer *blob;
Greg Kroah-Hartman
maintainerPATCH 1096/1146 ceph: put folios not suitable for writeback
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hristo Venev <[email protected]>
commit 544576f0f05c4a759806acddfaaeb686f14fb4b0 upstream.
The batch holds references to the folios (see filemap_get_folios, folio_batch_release), so we need to folio_put the folios we remove.
Tested on v6.18.
--- fs/ceph/addr.c | 2 ++ 1 file changed, 2 insertions(+)
fs/ceph/addr.c +2 -0
@@ -1322,6 +1322,7 @@ void ceph_process_folio_batch(struct add ceph_wbc, folio);if (rc == -ENODATA ) {folio_unlock (folio); +folio_put (folio); ceph_wbc->fbatch.folios[i] =NULL ;continue ; }else if (rc == -E2BIG ) {
@@ -1332,6 +1333,7 @@ void ceph_process_folio_batch(struct addif (!folio_clear_dirty_for_io (folio)) {doutc (cl,"%p !folio_clear_dirty_for_io\n" , folio);folio_unlock (folio); +folio_put (folio); ceph_wbc->fbatch.folios[i] =NULL ;continue ; }
Greg Kroah-Hartman
maintainerPATCH 1097/1146 io-wq: check that the predecessor is hashed in io_wq_remove_pending()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Carlini <[email protected]>
commit d6a2d7b04b5a093021a7a0e2e69e9d5237dfa8cc upstream.
io_wq_remove_pending() needs to fix up wq->hash_tail[] if the cancelled work was the tail of its hash bucket. When doing this, it checks whether the preceding entry in acct->work_list has the same hash value, but never checks that the predecessor is hashed at all. io_get_work_hash() is simply atomic_read(&work->flags) >> IO_WQ_HASH_SHIFT, and the hash bits are never set for non-hashed work, so it returns 0. Thus, when a hashed bucket-0 work is cancelled while a non-hashed work is its list predecessor, the check spuriously passes and a pointer to the non-hashed io_kiocb is stored in wq->hash_tail[0].
Because non-hashed work is dequeued via the fast path in io_get_next_work(), which never touches hash_tail[], the stale pointer is never cleared. Therefore, after the non-hashed io_kiocb completes and is freed back to req_cachep, wq->hash_tail[0] is a dangling pointer. The io_wq is per-task (tctx->io_wq) and survives ring open/close, so the dangling pointer persists for the lifetime of the task; the next hashed bucket-0 enqueue dereferences it in io_wq_insert_work() and wq_list_add_after() writes through freed memory.
Add the missing io_wq_is_hashed() check so a non-hashed predecessor never inherits a hash_tail[] slot.
--- io_uring/io-wq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
io_uring/io-wq.c +2 -1
@@ -1124,7 +1124,8 @@ static inline void io_wq_remove_pending(if (io_wq_is_hashed (work) && work == wq->hash_tail[hash]) {if (prev) prev_work = container_of(prev, struct io_wq_work, list); -if (prev_work &&io_get_work_hash (prev_work) == hash) +if (prev_work &&io_wq_is_hashed (prev_work) && +io_get_work_hash (prev_work) == hash) wq->hash_tail[hash] = prev_work;else wq->hash_tail[hash] =NULL ;
Greg Kroah-Hartman
maintainerPATCH 1098/1146 iommu/amd: Bounds-check devid in __rlookup_amd_iommu()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jose Fernandez (Anthropic) <[email protected]>
commit 07d0f496fe7ec5abe3bee7e38be709521567bb33 upstream.
iommu_device_register() walks every device on the PCI bus via bus_for_each_dev() and calls amd_iommu_probe_device() for each. The inlined check_device() path computes the device's sbdf, calls rlookup_amd_iommu() to find the owning IOMMU, and only afterwards verifies devid <= pci_seg->last_bdf. __rlookup_amd_iommu() indexes rlookup_table[devid] with no bounds check of its own, so for a PCI device whose BDF is not described by the IVRS, the lookup reads past the end of the allocation before the caller's bounds check can run.
This was harmless before commit e874c666b15b ("iommu/amd: Change rlookup, irq_lookup, and alias to use kvalloc()"): the table was a zeroed page-order allocation, so the over-read returned NULL and the caller's NULL check skipped the device. After that commit the table is a tight kvcalloc() and the over-read returns adjacent slab contents, which check_device() then dereferences as a struct amd_iommu *, causing a boot-time GPF.
Seen on Google Compute Engine ct6e VMs, where the virtualized IVRS describes only the four TPU endpoints 00:04.0-07.0; the gVNIC at 00:08.0 (devid 0x40) indexes 56 bytes past the 456-byte allocation, into the adjacent kmalloc-512 slab object:
pci 0000:00:04.0: Adding to iommu group 0
pci 0000:00:05.0: Adding to iommu group 1
pci 0000:00:06.0: Adding to iommu group 2
pci 0000:00:07.0: Adding to iommu group 3
Oops: general protection fault, probably for non-canonical address 0x3a64695f78746382: 0000 [#1] SMP NOPTI CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.18.22 #1 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 12/06/2025 RIP: 0010:amd_iommu_probe_device+0x54/0x3a0 Call Trace: __iommu_probe_device+0x107/0x520 probe_iommu_group+0x29/0x50 bus_for_each_dev+0x7e/0xe0 iommu_device_register+0xc9/0x240 iommu_go_to_state+0x9c0/0x1c60 amd_iommu_init+0x14/0x40 pci_iommu_init+0x16/0x60 do_one_initcall+0x47/0x2f0
Guard the array access in __rlookup_amd_iommu(). With the fix applied on 6.18.22, the gVNIC at 00:08.0 is skipped cleanly and the VM boots.
--- drivers/iommu/amd/iommu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/iommu/amd/iommu.c +6 -2
@@ -351,8 +351,12 @@ static struct amd_iommu *__rlookup_amd_istruct amd_iommu_pci_seg *pci_seg;for_each_pci_segment (pci_seg) { -if (pci_seg->id == seg) -return pci_seg->rlookup_table[devid]; +if (pci_seg->id != seg) +continue ; +/* IVRS may not describe every device on the bus */ +if (devid > pci_seg->last_bdf) +return NULL ; +return pci_seg->rlookup_table[devid]; }return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 1099/1146 x86/kexec: Push kjump return address even for non-kjump kexec
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Woodhouse <[email protected]>
commit 786a45757dcdf8f2beb9d4a6db605db16c18b2b4 upstream.
The version of purgatory code shipped by kexec-tools attempts to look above the top of its stack to find a return address for a kjump, even in a non-kjump kexec.
After the commit in Fixes: the word above the stack might not be there, leading to a fault (which is at least now caught by my exception-handling code in kexec).
That commit fixed things for the actual kjump path, but no longer "gratuitously" pushes the unused return address to the stack in the non-kjump path. Put that *back* in the non-kjump path, to prevent purgatory from crashing when trying to access it.
--- arch/x86/kernel/relocate_kernel_64.S | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/x86/kernel/relocate_kernel_64.S +8 -0
@@ -136,6 +136,14 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_ma * %r13 original CR4 when relocate_kernel() was invoked */ + /* + * Set return address to 0 if not preserving context. The purgatory + * shipped in kexec-tools will unconditionally look for the return + * address on the stack and set a kexec_jump_back_entry= command + * line option if it's non-zero. There's no other way that it can + * tell a preserve-context (kjump) kexec from a normal one. + */ + pushq $0 /* store the start address on the stack */ pushq %rdx
Greg Kroah-Hartman
maintainerPATCH 1100/1146 xfs: fix memory leak on error in xfs_alloc_zone_info()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wilfred Mallawa <[email protected]>
commit 592975da8c3ca87b043077e6eafa37665eae7936 upstream.
Currently, the 0th index of the zi_used_bucket_bitmap array is not freed on error due to the pre-decrement then evaluate semantic of the while loop used in xfs_alloc_zone_info(). Fix it by allowing for the i == 0 case to be covered.
--- fs/xfs/xfs_zone_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/xfs_zone_alloc.c +1 -1
@@ -1214,7 +1214,7 @@ xfs_alloc_zone_info(return zi; out_free_bitmaps: -while (--i >0 ) +while (--i >=0 )kvfree (zi->zi_used_bucket_bitmap[i]);kfree (zi);return NULL ;
Greg Kroah-Hartman
maintainerPATCH 1101/1146 virt: sev-guest: Do not use host-controlled page order in cleanup path
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos López <[email protected]>
commit 23e6a1ca04ae44806439a5a446e62e4d42e80bb4 upstream.
When issuing an extended guest request (SVM_VMGEXIT_EXT_GUEST_REQUEST), get_ext_report() allocates a buffer to retrieve a certificate blob from the host, keeping track of its size in report_req->certs_len.
However, the host may return SNP_GUEST_VMM_ERR_INVALID_LEN, indicating an invalid buffer size, as well as the expected length of such buffer. get_ext_report() subsequently updates report_req->certs_len with the host-controlled value, and cleans up the buffer by computing a page order from such value. This is incorrect, as the host-provided length may not match the page order of the original allocation, potentially resulting in corruption in the page allocator.
Fix this by using alloc_pages_exact() instead, and reusing @npages to compute the size passed to free_pages_exact(). For consistency, also use @npages to compute the size when allocating the pages, even though this last change has no functional effect.
--- drivers/virt/coco/sev-guest/sev-guest.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
drivers/virt/coco/sev-guest/sev-guest.c +5 -7
@@ -176,7 +176,6 @@ static int get_ext_report(struct snp_guestruct snp_guest_req req = {};int ret, npages =0 , resp_len;sockptr_t certs_address; -struct page *page;if (sockptr_is_null (io->req_data) ||sockptr_is_null (io->resp_data))return -EINVAL ;
@@ -211,16 +210,15 @@ static int get_ext_report(struct snp_gue* zeros to indicate that certificate data was not provided. */ npages = report_req->certs_len >>PAGE_SHIFT ; - page =alloc_pages (GFP_KERNEL_ACCOUNT | __GFP_ZERO, -get_order (report_req->certs_len)); -if (!page) + req.certs_data =alloc_pages_exact (npages <<PAGE_SHIFT , +GFP_KERNEL_ACCOUNT | __GFP_ZERO); +if (!req.certs_data)return -ENOMEM ; - req.certs_data =page_address (page); ret =set_memory_decrypted ((unsigned long )req.certs_data, npages);if (ret) {pr_err ("failed to mark page shared, ret=%d\n" , ret); -__free_pages (page,get_order (report_req->certs_len)); +free_pages_exact (req.certs_data, npages <<PAGE_SHIFT );return -EFAULT ; }
@@ -277,7 +275,7 @@ e_free_data:if (set_memory_encrypted ((unsigned long )req.certs_data, npages))WARN_ONCE (ret,"failed to restore encryption mask (leak it)\n" );else -__free_pages (page,get_order (report_req->certs_len)); +free_pages_exact (req.certs_data, npages <<PAGE_SHIFT ); }return ret; }
Greg Kroah-Hartman
maintainerPATCH 1102/1146 riscv: misaligned: Make enabling delegation depend on NONPORTABLE
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vivian Wang <[email protected]>
commit b69bcb13ed7024a84d6cd8ad330f1e32782fcf28 upstream.
The unaligned access emulation code in Linux has various deficiencies. For example, it doesn't emulate vector instructions [1] [2], and doesn't emulate KVM guest accesses. Therefore, requesting misaligned exception delegation with SBI FWFT actually regresses vector instructions' and KVM guests' behavior.
Until Linux can handle it properly, guard these sbi_fwft_set() calls behind RISCV_SBI_FWFT_DELEGATE_MISALIGNED, which in turn depends on NONPORTABLE. Those who are sure that this wouldn't be a problem can enable this option, perhaps getting better performance.
The rest of the existing code proceeds as before, except as if SBI_FWFT_MISALIGNED_EXC_DELEG is not available, to handle any remaining address misaligned exceptions on a best-effort basis. The KVM SBI FWFT implementation is also not touched, but it is disabled if the firmware emulates unaligned accesses.
--- arch/riscv/Kconfig | 22 ++++++++++++++++++++++ arch/riscv/kernel/traps_misaligned.c | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-)
arch/riscv/Kconfig +22 -0
@@ -941,6 +941,28 @@ config RISCV_VECTOR_MISALIGNED help Enable detecting support for vector misaligned loads and stores. +config RISCV_SBI_FWFT_DELEGATE_MISALIGNED + bool "Request firmware delegation of unaligned access exceptions" + depends on RISCV_SBI + depends on NONPORTABLE + help + Use SBI FWFT to request delegation of load address misaligned and + store address misaligned exceptions, if possible, and prefer Linux + kernel emulation of these accesses to firmware emulation. + + Unfortunately, Linux's emulation is still incomplete. Namely, it + currently does not handle vector instructions and KVM guest accesses. + On platforms where these accesses would have been handled by firmware, + enabling this causes unexpected kernel oopses, userspaces crashes and + KVM guest crashes. If you are sure that these are not a problem for + your platform, you can say Y here, which may improve performance. + + Saying N here will not worsen emulation support for unaligned accesses + even in the case where the firmware also has incomplete support. It + simply keeps the firmware's emulation enabled. + + If you don't know what to do here, say N. + choice prompt "Unaligned Accesses Support" default RISCV_PROBE_UNALIGNED_ACCESS
arch/riscv/kernel/traps_misaligned.c +1 -1
@@ -584,7 +584,7 @@ static int cpu_online_check_unaligned_acstatic bool misaligned_traps_delegated; -#ifdef CONFIG_RISCV_SBI +#if defined(CONFIG_RISCV_SBI_FWFT_DELEGATE_MISALIGNED )static int cpu_online_sbi_unaligned_setup (unsigned int cpu) {
Re: [PATCH 7.0 1102/1146] riscv: misaligned: Make enabling delegation depend on NONPORTABLE
Hi Greg and stable team,
Quoted 25 lines · Greg Kroah-Hartman
7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vivian Wang <[email protected]>
commit
b69bcb13ed7024a84d6cd8ad330f1e32782fcf28upstream.The unaligned access emulation code in Linux has various deficiencies. For example, it doesn't emulate vector instructions [1] [2], and doesn't emulate KVM guest accesses. Therefore, requesting misaligned exception delegation with SBI FWFT actually regresses vector instructions' and KVM guests' behavior.
Until Linux can handle it properly, guard these
sbi_fwft_set()calls behindRISCV_SBI_FWFT_DELEGATE_MISALIGNED, which in turn depends on NONPORTABLE. Those who are sure that this wouldn't be a problem can enable this option, perhaps getting better performance.The rest of the existing code proceeds as before, except as if
SBI_FWFT_MISALIGNED_EXC_DELEGis not available, to handle any remaining address misaligned exceptions on a best-effort basis. The KVM SBI FWFT implementation is also not touched, but it is disabled if the firmware emulates unaligned accesses.
Quoted 10 lines
Fixes cf5a8abc6560 ("riscv: misaligned: request misaligned exception from SBI")Reported-by Songsong Zhang <[email protected]> # KVMSigned-off-by Vivian Wang <[email protected]>Acked-by Conor Dooley <[email protected]>Link https://patch.msgid.link/20260401-riscv-misaligned-dont-delegate-v2-1-5014a288c097@iscas.ac.cn open hereSigned-off-by Paul Walmsley <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>
Can we drop this 7.0 patch and the 6.18 patch [1]? There were boot time crashes reported on latest 7.1-rc/linux-next [2] on some hardware/firmware. While superficially it seems to be caused by badly broken FW (one of the register dumps was a null pointer dereference in the firmware itself from emulating reading the time counter, which is essential on riscv), we don't know for sure yet and would like more time to figure out.
In other words I retract my Cc stable backport request for now.
The file name for both are
riscv-misaligned-make-enabling-delegation-depend-on-nonportable.patch
Thanks and apologies for the trouble,
Vivian "dramforever" Wang
[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/linux-riscv/nrvt74qnojaubiwjo37ums4lnclu466hovwrhmtbag6f5uhrql@q6msoe2oto4b/
Sasha Levin
maintainerRe: [PATCH 7.0 1102/1146] riscv: misaligned: Make enabling delegation depend on NONPORTABLE
Quoted 5 lines · Vivian Wang
Can we drop this 7.0 patch and the 6.18 patch [1]? There were boot time crashes reported on latest 7.1-rc/linux-next [2] on some hardware/firmware. [...]
In other words I retract my Cc stable backport request for now.
Dropped from both the 7.0 and 6.18 queues.
--
Thanks,
Sasha
Greg Kroah-Hartman
maintainerPATCH 1103/1146 powerpc/warp: Fix error handling in pika_dtm_thread
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ma Ke <[email protected]>
commit 108d7f951271cbd36ca36efc5e5d106966f5180c upstream.
pika_dtm_thread() acquires client through of_find_i2c_device_by_node() but fails to release it in error handling path. This could result in a reference count leak, preventing proper cleanup and potentially leading to resource exhaustion. Add put_device() to release the reference in the error handling path.
Found by code review.
--- arch/powerpc/platforms/44x/warp.c | 2 ++ 1 file changed, 2 insertions(+)
arch/powerpc/platforms/44x/warp.c +2 -0
@@ -293,6 +293,8 @@ static int pika_dtm_thread(void __iomemschedule_timeout (HZ ); } +put_device (&client->dev); +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 1104/1146 netfs: fix error handling in netfs_extract_user_iter()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
commit 0aad5704c6b4d14007d4eab15883e8524e4310f4 upstream.
In netfs_extract_user_iter(), if iov_iter_extract_pages() failed to extract user pages, bail out on -ENOMEM, otherwise return the error code only if @npages == 0, allowing short DIO reads and writes to be issued.
This fixes mmapstress02 from LTP tests against CIFS.
--- fs/netfs/iterator.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
fs/netfs/iterator.c +10 -3
@@ -22,7 +22,7 @@* * Extract the page fragments from the given amount of the source iterator and * build up a second iterator that refers to all of those bits. This allows -* the original iterator to disposed of. +* the original iterator to be disposed of. * * @extraction_flags can have ITER_ALLOW_P2PDMA set to request peer-to-peer DMA be * allowed on the pages extracted.
@@ -67,8 +67,8 @@ ssize_t netfs_extract_user_iter(struct i ret =iov_iter_extract_pages (orig, &pages, count, max_pages - npages, extraction_flags, &offset); -if (ret <0 ) { -pr_err ("Couldn't get user pages (rc=%zd)\n" , ret); +if (unlikely (ret <=0 )) { + ret = ret ?: -EIO ;break ; }
@@ -97,6 +97,13 @@ ssize_t netfs_extract_user_iter(struct i npages += cur_npages; } +if (ret <0 && (ret == -ENOMEM || npages ==0 )) { +for (i =0 ; i < npages; i++) +unpin_user_page (bv[i].bv_page); +kvfree (bv); +return ret; + } +iov_iter_bvec (new, orig->data_source, bv, npages, orig_len - count);return npages; }
Greg Kroah-Hartman
maintainerPATCH 1105/1146 nfsd: fix GET_DIR_DELEGATION when VFS leases are disabled
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Olga Kornievskaia <[email protected]>
commit b0bf14546bcefa4ea49f5efcd7db2a99f0cabde9 upstream.
When leases are disabled on the server, running xfstest generic/309 leads to an error because GET_DIR_DELEGATION returns EINVAL.
nfsd_get_dir_deleg() can fail in several ways: like memory allocation and unable to get a lease because either leases are disable or it's already held. Currently only the condition "already held" is translated to returning directory-delegation-is-unavailable error. However, other failure conditions are likely temporary and thus should result in the same kind of error.
--- fs/nfsd/nfs4proc.c | 4 ---- 1 file changed, 4 deletions(-)
fs/nfsd/nfs4proc.c +0 -4
@@ -2535,10 +2535,6 @@ nfsd4_get_dir_delegation(struct svc_rqst *rqstp, dd =nfsd_get_dir_deleg (cstate, gdd, nf);nfsd_file_put (nf);if (IS_ERR (dd)) { -int err =PTR_ERR (dd); - -if (err != -EAGAIN ) -return nfserrno (err); gdd->gddrnf_status =GDD4_UNAVAIL ;return nfs_ok; }
Signature · 1 line
2.54.0
Greg Kroah-Hartman
maintainerPATCH 1106/1146 nfsd: fix file change detection in CB_GETATTR
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Scott Mayhew <[email protected]>
commit 304d81a2fbf2b454def4debcb38ea173911b72cd upstream.
RFC 8881, section 10.4.3 doesn't say anything about caching the file size in the delegation record, nor does it say anything about comparing a cached file size with the size reported by the client in the CB_GETATTR reply for the purpose of determining if the client holds modified data for the file.
What section 10.4.3 of RFC 8881 does say is that the server should compare the *current* file size with the size reported by the client holding the delegation in the CB_GETATTR reply, and if they differ to treat it as a modification regardless of the change attribute retrieved via the CB_GETATTR.
Doing otherwise would cause the server to believe the client holding the delegation has a modified version of the file, even if the client flushed the modifications to the server prior to the CB_GETATTR. This would have the added side effect of subsequent CB_GETATTRs causing updates to the mtime, ctime, and change attribute even if the client holding the delegation makes no further updates to the file.
Modify nfsd4_deleg_getattr_conflict() to obtain the current file size via i_size_read(). Retain the ncf_cur_fsize field, since it's a convenient way to return the file size back to nfsd4_encode_fattr4(), but don't use it for the purpose of detecting file changes. Remove the unnecessary initialization of ncf_cur_fsize in nfs4_open_delegation().
Also, if we recall the delegation (because the client didn't respond to the CB_GETATTR), then skip the logic that checks the nfs4_cb_fattr fields.
--- fs/nfsd/nfs4state.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c +8 -5
@@ -6368,7 +6368,6 @@ nfs4_open_delegation(struct svc_rqst *rq } open->op_delegate_type = deleg_ts ?OPEN_DELEGATE_WRITE_ATTRS_DELEG :OPEN_DELEGATE_WRITE ; - dp->dl_cb_fattr.ncf_cur_fsize = stat.size; dp->dl_cb_fattr.ncf_initial_cinfo =nfsd4_change_attribute (&stat); dp->dl_atime = stat.atime; dp->dl_ctime = stat.ctime;
@@ -9417,11 +9416,15 @@ nfsd4_deleg_getattr_conflict(struct svc_if (status != nfserr_jukebox || !nfsd_wait_for_delegreturn (rqstp, inode)) goto out_status; + status = nfs_ok; + goto out_status; + } +if (!ncf->ncf_file_modified) { +if (ncf->ncf_initial_cinfo != ncf->ncf_cb_change) + ncf->ncf_file_modified = true; +else if (i_size_read (inode) != ncf->ncf_cb_fsize) + ncf->ncf_file_modified = true; } -if (!ncf->ncf_file_modified && - (ncf->ncf_initial_cinfo != ncf->ncf_cb_change || - ncf->ncf_cur_fsize != ncf->ncf_cb_fsize)) - ncf->ncf_file_modified = true;if (ncf->ncf_file_modified) {int err;
Greg Kroah-Hartman
maintainerPATCH 1107/1146 nfsd: update mtime/ctime on CLONE in presense of delegated attributes
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Olga Kornievskaia <[email protected]>
commit 2863bac7f49c4acd80a048ce52506a2b9c8db015 upstream.
When delegated attributes are given on open, the file is opened with NOCMTIME and modifying operations do not update mtime/ctime as to not get out-of-sync with the client's delegated view. However, for CLONE operation, the server should update its view of mtime/ctime and reflect that in any GETATTR queries.
--- fs/nfsd/nfs4proc.c | 3 +++ fs/nfsd/nfs4state.c | 44 +++++++++++++++++++++++++++++--------------- fs/nfsd/state.h | 1 + 3 files changed, 33 insertions(+), 15 deletions(-)
fs/nfsd/nfs4proc.c +3 -0
@@ -1413,6 +1413,9 @@ nfsd4_clone(struct svc_rqst *rqstp, stru dst, clone->cl_dst_pos, clone->cl_count, EX_ISSYNC(cstate->current_fh.fh_export)); +if (!status && (READ_ONCE (dst->nf_file->f_mode) &FMODE_NOCMTIME ) !=0 ) +nfsd_update_cmtime_attr (dst->nf_file,0 ); +nfsd_file_put (dst);nfsd_file_put (src); out:
fs/nfsd/nfs4state.c +29 -15
59 lines not on this page · raw message
fs/nfsd/state.h +1 -0
@@ -834,6 +834,7 @@ extern void nfsd4_shutdown_copy(struct nvoid nfsd4_put_client (struct nfs4_client *clp);void nfsd4_async_copy_reaper (struct nfsd_net *nn);bool nfsd4_has_active_async_copies (struct nfs4_client *clp); +void nfsd_update_cmtime_attr (struct file *f,unsigned int flags);extern struct nfs4_client_reclaim *nfs4_client_to_reclaim (struct xdr_netobj name,struct xdr_netobj princhash,struct nfsd_net *nn);extern bool nfs4_has_reclaimed_state (struct xdr_netobj name,struct nfsd_net *nn);
Greg Kroah-Hartman
maintainerPATCH 1108/1146 nfsd: update mtime/ctime on COPY in presence of delegated attributes
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Olga Kornievskaia <[email protected]>
commit 4183cf383b6faec17a0882b84cd2d901dba62b16 upstream.
When delegated attributes are given on open, the file is opened with NOCMTIME and modifying operations do not update mtime/ctime as to not get out-of-sync with the client's delegated view. However, for COPY operation, the server should update its view of mtime/ctime and reflect that in any GETATTR queries.
--- fs/nfsd/nfs4proc.c | 11 ++++++++++- fs/nfsd/xdr4.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-)
fs/nfsd/nfs4proc.c +10 -1
@@ -2121,8 +2121,10 @@ do_callback:set_bit (NFSD4_COPY_F_COMPLETED , ©->cp_flags);trace_nfsd_copy_async_done (copy); -nfsd4_send_cb_offload (copy);atomic_dec (©->cp_nn->pending_async_copies); +if (copy->cp_res.wr_bytes_written >0 && copy->attr_update) +nfsd_update_cmtime_attr (copy->nf_dst->nf_file,0 ); +nfsd4_send_cb_offload (copy);return 0 ; }
@@ -2182,6 +2184,9 @@ nfsd4_copy(struct svc_rqst *rqstp, strucmemcpy (&result->cb_stateid, ©->cp_stateid.cs_stid,sizeof (result->cb_stateid));dup_copy_fields (copy, async_copy); +if ((READ_ONCE (copy->nf_dst->nf_file->f_mode) & +FMODE_NOCMTIME ) !=0 ) + async_copy->attr_update = true;memcpy (async_copy->cp_cb_offload.co_referring_sessionid.data, cstate->session->se_sessionid.data,NFS4_MAX_SESSIONID_LEN );
@@ -2200,6 +2205,10 @@ nfsd4_copy(struct svc_rqst *rqstp, struc }else { status =nfsd4_do_copy (copy, copy->nf_src->nf_file, copy->nf_dst->nf_file, true); +if ((READ_ONCE (copy->nf_dst->nf_file->f_mode) & +FMODE_NOCMTIME ) !=0 && + copy->cp_res.wr_bytes_written >0 ) +nfsd_update_cmtime_attr (copy->nf_dst->nf_file,0 ); } out:trace_nfsd_copy_done (copy, status);
fs/nfsd/xdr4.h +1 -0
@@ -752,6 +752,7 @@ struct nfsd4_copy {struct nfsd_file *nf_src;struct nfsd_file *nf_dst; +bool attr_update;copy_stateid_t cp_stateid;
Greg Kroah-Hartman
maintainerPATCH 1109/1146 irqchip/riscv-imsic: Clear interrupt move state during CPU offlining
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yong-Xuan Wang <[email protected]>
commit cefafbd561402b0fe6447449364a30315b9b1570 upstream.
Affinity changes of IMSIC interrupts have to be careful to not lose an interrupt in the process. Each vector keeps track of an affinity change in progress with two pointers in struct imsic_vector.
imsic_vector::move_prev points to the previous CPU target data and imsic_vector::move_next to the designated new CPU target data.
imsic_vector::move_prev on the new CPU can only be cleared after the previous CPU has cleared imsic_vector::move_next, which ususally happens in __imsic_remote_sync().
In case of CPU hot-unplug __imsic_remote_sync() is not invoked because the CPU is already marked offline. That means imsic_vector::move_prev becomes stale until the CPU is onlined again.
The stale pointer prevents further affinity changes for the affected interrupts.
Solve this by clearing the imsic_vector::move_prev pointers in the CPU hotplug offline path.
[ tglx: Replace word salad in change log ]
--- drivers/irqchip/irq-riscv-imsic-early.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/irqchip/irq-riscv-imsic-early.c +2 -0
@@ -158,6 +158,8 @@ static int imsic_dying_cpu(unsigned int/* Cleanup IPIs */ imsic_ipi_dying_cpu (); +imsic_local_sync_all (false); +/* Mark per-CPU IMSIC state as offline */ imsic_state_offline ();
Greg Kroah-Hartman
maintainerPATCH 1110/1146 irqchip/meson-gpio: Use the correct register in meson_s4_gpio_irq_set_type()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xianwei Zhao <[email protected]>
commit 5363b67ac8ebcc3e227dbf59fc8061949109841d upstream.
meson_s4_gpio_irq_set_type() uses the both-edge trigger register for configuring level type and single edge mode interrupts, which is not correct.
Use REG_EDGE_POL instead.
--- drivers/irqchip/irq-meson-gpio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/irqchip/irq-meson-gpio.c +1 -2
@@ -415,8 +415,7 @@ static int meson_s4_gpio_irq_set_type(stif (type & (IRQ_TYPE_EDGE_RISING |IRQ_TYPE_EDGE_FALLING )) val |=BIT (ctl->params->edge_single_offset + idx); -meson_gpio_irq_update_bits (ctl, params->edge_pol_reg, -BIT (idx) |BIT (12 + idx), val); +meson_gpio_irq_update_bits (ctl,REG_EDGE_POL ,BIT (idx) |BIT (12 + idx), val);return 0 ; };
Greg Kroah-Hartman
maintainerPATCH 1111/1146 irqchip/gic-v5: Move LPI allocation into the LPI domain
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sascha Bischoff <[email protected]>
commit dec85d2fbd20de3711a71e65397dfdb40c3fa953 upstream.
The IPI and ITS MSI domains currently allocate and release LPIs directly, then pass the selected LPI ID to the parent LPI domain. This leaks the LPI domain's allocation policy into its child domains and forces each child to duplicate part of the parent domain's teardown.
Make the LPI domain allocate LPIs in its .alloc() callback and release them in a matching .free() callback. Child domains can then request a parent interrupt without passing an implementation-specific LPI ID, and the LPI lifetime is tied to the domain that owns the LPI namespace.
Remove the gicv5_alloc_lpi() and gicv5_free_lpi() wrappers now that no external caller needs to manage LPIs directly.
This is a preparatory change for an actual leakage problem in the allocation code and therefore tagged with the same Fixes tag.
--- drivers/irqchip/irq-gic-v5-its.c | 14 +-------- drivers/irqchip/irq-gic-v5.c | 53 ++++++++++++++++++------------------- include/linux/irqchip/arm-gic-v5.h | 3 -- 3 files changed, 28 insertions(+), 42 deletions(-)
drivers/irqchip/irq-gic-v5-its.c +2 -12
@@ -929,8 +929,8 @@ static void gicv5_its_free_eventid(strucstatic int gicv5_its_irq_domain_alloc (struct irq_domain *domain,unsigned int virq,unsigned int nr_irqs,void *arg) { -u32 device_id, event_id_base, lpi;struct gicv5_its_dev *its_dev; +u32 device_id, event_id_base;msi_alloc_info_t *info = arg;irq_hw_number_t hwirq;struct irq_data *irqd;
@@ -949,16 +949,8 @@ static int gicv5_its_irq_domain_alloc(st device_id = its_dev->device_id;for (i =0 ; i < nr_irqs; i++) { - ret =gicv5_alloc_lpi (); -if (ret <0 ) { -pr_debug ("Failed to find free LPI!\n" ); - goto out_free_irqs; - } - lpi = ret; - - ret =irq_domain_alloc_irqs_parent (domain, virq + i,1 , &lpi); + ret =irq_domain_alloc_irqs_parent (domain, virq + i,1 ,NULL );if (ret) { -gicv5_free_lpi (lpi); goto out_free_irqs; }
@@ -983,7 +975,6 @@ static int gicv5_its_irq_domain_alloc(st out_free_irqs:while (--i >=0 ) { irqd =irq_domain_get_irq_data (domain, virq + i); -gicv5_free_lpi (irqd->parent_data->hwirq);irq_domain_reset_irq_data (irqd);irq_domain_free_irqs_parent (domain, virq + i,1 ); }
@@ -1013,7 +1004,6 @@ static void gicv5_its_irq_domain_free(stfor (i =0 ; i < nr_irqs; i++) { d =irq_domain_get_irq_data (domain, virq + i); -gicv5_free_lpi (d->parent_data->hwirq);irq_domain_reset_irq_data (d);irq_domain_free_irqs_parent (domain, virq + i,1 ); }
drivers/irqchip/irq-gic-v5.c +26 -27
104 lines not on this page · raw message
include/linux/irqchip/arm-gic-v5.h +0 -3
@@ -398,9 +398,6 @@ struct gicv5_its_itt_cfg {void gicv5_init_lpis (u32 max);void gicv5_deinit_lpis (void ); -int gicv5_alloc_lpi (void ); -void gicv5_free_lpi (u32 lpi); -void __init gicv5_its_of_probe (struct device_node *parent);void __init gicv5_its_acpi_probe (void );#endif
Greg Kroah-Hartman
maintainerPATCH 1112/1146 irqchip/gic-v5: Support range allocation for LPIs
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sascha Bischoff <[email protected]>
commit eb6f6d523813ead9dc2799194a2839d42c049734 upstream.
The per-IPI parent allocation loop returns immediately on failure and leaks any parent interrupts allocated by earlier iterations.
The GICv5 LPI domain now owns LPI allocation and teardown internally, but its irq_domain callbacks still reject requests where nr_irqs is greater than one. This forces child domains to allocate and free LPIs one at a time even when the interrupt core requests a contiguous range.
Handle multi-interrupt allocation and teardown in the LPI domain by iterating over the requested range and unwinding any partially allocated state on failure.
Allocate the parent LPIs for the IPI domain with a single range request as well, which cures the leakage problem.
--- drivers/irqchip/irq-gic-v5.c | 77 +++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 35 deletions(-)
drivers/irqchip/irq-gic-v5.c +42 -35
@@ -783,15 +783,14 @@ static void gicv5_irq_lpi_domain_free(st {struct irq_data *d; -if (WARN_ON_ONCE (nr_irqs !=1 )) -return ; +for (unsigned int i =0 ; i < nr_irqs; i++, virq++) { + d =irq_domain_get_irq_data (domain, virq); - d =irq_domain_get_irq_data (domain, virq); +release_lpi (d->hwirq); -release_lpi (d->hwirq); - -irq_set_handler (virq,NULL ); -irq_domain_reset_irq_data (d); +irq_set_handler (virq,NULL ); +irq_domain_reset_irq_data (d); + } } static int gicv5_irq_lpi_domain_alloc(struct irq_domain *domain, unsigned int virq,
@@ -799,32 +798,39 @@ static int gicv5_irq_lpi_domain_alloc(st {irq_hw_number_t hwirq;struct irq_data *irqd; +unsigned int i;int ret; -if (WARN_ON_ONCE (nr_irqs !=1 )) -return -EINVAL ; - - ret =alloc_lpi (); -if (ret <0 ) -return ret; - hwirq = ret; +for (i =0 ; i < nr_irqs; i++) { + ret =alloc_lpi (); +if (ret <0 ) + goto out_free_lpis; + hwirq = ret; + + ret =gicv5_irs_iste_alloc (hwirq); +if (ret <0 ) { +/* Undo partial state first, then clean up the rest */ +release_lpi (hwirq); + goto out_free_lpis; + } - irqd =irq_domain_get_irq_data (domain, virq); + irqd =irq_domain_get_irq_data (domain, virq + i); -irq_domain_set_info (domain, virq, hwirq, &gicv5_lpi_irq_chip,NULL , - handle_fasteoi_irq,NULL ,NULL ); -irqd_set_single_target (irqd); +irq_domain_set_info (domain, virq + i, hwirq, &gicv5_lpi_irq_chip, +NULL , handle_fasteoi_irq,NULL ,NULL ); +irqd_set_single_target (irqd); - ret =gicv5_irs_iste_alloc (hwirq); -if (ret <0 ) { -release_lpi (hwirq); -return ret; +gicv5_hwirq_init (hwirq,GICV5_IRQ_PRI_MI ,GICV5_HWIRQ_TYPE_LPI ); +gicv5_lpi_config_reset (irqd); } -gicv5_hwirq_init (hwirq,GICV5_IRQ_PRI_MI ,GICV5_HWIRQ_TYPE_LPI ); -gicv5_lpi_config_reset (irqd); -return 0 ; + +out_free_lpis: +if (i) +gicv5_irq_lpi_domain_free (domain, virq, i); + +return ret; }static const struct irq_domain_ops gicv5_irq_lpi_domain_ops = {
@@ -850,21 +856,21 @@ static int gicv5_irq_ipi_domain_alloc(st unsigned int nr_irqs, void *arg) { struct irq_data *irqd; -int ret, i; +int ret; -for (i =0 ; i < nr_irqs; i++) { - ret =irq_domain_alloc_irqs_parent (domain, virq + i,1 ,NULL ); -if (ret) -return ret; + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret) +return ret; - irqd =irq_domain_get_irq_data (domain, virq + i); +for (unsigned int i =0 ; i < nr_irqs; i++, virq++) { + irqd =irq_domain_get_irq_data (domain, virq); -irq_domain_set_hwirq_and_chip (domain, virq + i, i, - &gicv5_ipi_irq_chip,NULL ); +irq_domain_set_hwirq_and_chip (domain, virq, i, + &gicv5_ipi_irq_chip,NULL );irqd_set_single_target (irqd); -irq_set_handler (virq + i, handle_percpu_irq); +irq_set_handler (virq, handle_percpu_irq); }return 0 ;
@@ -884,8 +890,9 @@ static void gicv5_irq_ipi_domain_free(stirq_set_handler (virq + i,NULL );irq_domain_reset_irq_data (d); -irq_domain_free_irqs_parent (domain, virq + i,1 ); } + +irq_domain_free_irqs_parent (domain, virq, nr_irqs); }static const struct irq_domain_ops gicv5_irq_ipi_domain_ops = {
Greg Kroah-Hartman
maintainerPATCH 1113/1146 irqchip/gic-v5: Allocate ITS parent LPIs as a range
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sascha Bischoff <[email protected]>
commit a7c7e42654b6a8676610ee09d22901432c4851af upstream.
The ITS MSI domain no longer manages LPI allocation directly. LPIs are allocated and freed by the parent LPI domain, which can now handle a full range of interrupts and unwind partial allocations internally.
Make the ITS domain request and release the parent IRQs as a single range instead of iterating over each interrupt. The ITS allocation path then only needs to reserve EventIDs, allocate the parent range, and fill in the ITS irq_data for each MSI. Since no operation in the per-MSI loop can fail, the partial parent-free unwind becomes unnecessary.
On teardown, reset the ITS irq_data for the range and then release the parent range in one call, leaving LPI teardown to the LPI domain.
--- drivers/irqchip/irq-gic-v5-its.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-)
drivers/irqchip/irq-gic-v5-its.c +7 -15
@@ -937,6 +937,7 @@ static int gicv5_its_irq_domain_alloc(stint ret, i; its_dev = info->scratchpad[0 ].ptr; + device_id = its_dev->device_id; ret =gicv5_its_alloc_eventid (its_dev, info, nr_irqs, &event_id_base);if (ret)
@@ -946,14 +947,11 @@ static int gicv5_its_irq_domain_alloc(stif (ret) goto out_eventid; - device_id = its_dev->device_id; + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs,NULL ); +if (ret) + goto out_eventid;for (i =0 ; i < nr_irqs; i++) { - ret =irq_domain_alloc_irqs_parent (domain, virq + i,1 ,NULL ); -if (ret) { - goto out_free_irqs; - } -/* * Store eventid and deviceid into the hwirq for later use. *
@@ -972,12 +970,6 @@ static int gicv5_its_irq_domain_alloc(streturn 0 ; -out_free_irqs: -while (--i >=0 ) { - irqd =irq_domain_get_irq_data (domain, virq + i); -irq_domain_reset_irq_data (irqd); -irq_domain_free_irqs_parent (domain, virq + i,1 ); - } out_eventid:gicv5_its_free_eventid (its_dev, event_id_base, nr_irqs);return ret;
@@ -1000,14 +992,14 @@ static void gicv5_its_irq_domain_free(stbitmap_release_region (its_dev->event_map, event_id_base,get_count_order (nr_irqs)); -/* Hierarchically free irq data */ for (i =0 ; i < nr_irqs; i++) { d =irq_domain_get_irq_data (domain, virq + i); -irq_domain_reset_irq_data (d); -irq_domain_free_irqs_parent (domain, virq + i,1 ); } +/* Hierarchically free irq data */ +irq_domain_free_irqs_parent (domain, virq, nr_irqs); +gicv5_its_syncr (its, its_dev);gicv5_irs_syncr (); }
Greg Kroah-Hartman
maintainerPATCH 1114/1146 libceph: Fix potential out-of-bounds access in osdmap_decode()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit 35d0ed82d03e5ee77ea4f31f20e29562a7721649 upstream.
When decoding osd_state and osd_weight from an incoming osdmap in osdmap_decode(), both are decoded for each osd, i.e., map->max_osd times. The ceph_decode_need() check only accounts for sizeof(*map->osd_weight) once. This can potentially result in an out-of-bounds memory access if the incoming message is corrupted such that the max_osd value exceeds the actual content of the osdmap message.
This patch fixes the issue by changing the corresponding part in the ceph_decode_need() check to account for map->max_osd*sizeof(*map->osd_weight).
--- net/ceph/osdmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ceph/osdmap.c +1 -1
@@ -1702,7 +1702,7 @@ static int osdmap_decode(void **p, voidceph_decode_need (p, end,3 *sizeof (u32) + map->max_osd*(struct_v >=5 ?sizeof (u32) :sizeof (u8)) + -sizeof (*map->osd_weight), e_inval); + map->max_osd*sizeof (*map->osd_weight), e_inval);if (ceph_decode_32 (p) != map->max_osd) goto e_inval;
Greg Kroah-Hartman
maintainerPATCH 1115/1146 libceph: Fix potential null-ptr-deref in decode_choose_args()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit 28b0a2ab8c82d0bbdeb8013029c67c978ce6e4bf upstream.
A message of type CEPH_MSG_OSD_MAP contains an OSD map that itself contains a CRUSH map. When decoding this CRUSH map in crush_decode(), an array of max_buckets CRUSH buckets is decoded, where some indices may not refer to actual buckets and are therefore set to NULL. The received CRUSH map may optionally contain choose_args that get decoded in decode_choose_args(). When decoding a crush_choose_arg_map, a series of choose_args for different buckets is decoded, with the bucket_index being read from the incoming message. It is only checked that the bucket index does not exceed max_buckets, but not that it doesn't point to an index with a NULL bucket. If a (potentially corrupted) message contains a crush_choose_arg_map including such a bucket_index, a null pointer dereference may occur in the subsequent processing when attempting to access the bucket with the given index.
This patch fixes the issue by extending the affected check. Now, it is only attempted to access the bucket if it is not NULL.
--- net/ceph/osdmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/ceph/osdmap.c +2 -1
@@ -389,7 +389,8 @@ static int decode_choose_args(void **p, goto fail;if (arg->ids_size && - arg->ids_size != c->buckets[bucket_index]->size) + (!c->buckets[bucket_index] || + arg->ids_size != c->buckets[bucket_index]->size)) goto e_inval; }
Greg Kroah-Hartman
maintainerPATCH 1116/1146 libceph: Fix potential out-of-bounds access in __ceph_x_decrypt()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit 821365487aa58d06bda65c676ba215d506ba9768 upstream.
In __ceph_x_decrypt(), a part of the buffer p is interpreted as a ceph_x_encrypt_header, and the magic field of this struct is accessed. This happens without any guarantee that the buffer is large enough to hold this struct. The function parameter ciphertext_len represents the length of the ciphertext to decrypt and is guaranteed to be at most the remaining size of the allocated buffer p. However, this value is not necessarily greater than sizeof(ceph_x_encrypt_header). E.g., a message frame of type FRAME_TAG_AUTH_REPLY_MORE, that is just as long to hold the ciphertext at its end with a ciphertext_len of 8 or less, can trigger an out-of-bounds memory access when accessing hdr->magic.
This patch fixes the issue by adding a check to ensure that the decrypted plaintext in the buffer is large enough to represent at least the ceph_x_encrypt_header.
--- net/ceph/auth_x.c | 5 +++++ 1 file changed, 5 insertions(+)
net/ceph/auth_x.c +5 -0
@@ -115,6 +115,11 @@ static int __ceph_x_decrypt(const structif (ret)return ret; +if (plaintext_len <sizeof (*hdr)) { +pr_err ("%s plaintext too small %d\n" , __func__, plaintext_len); +return -EINVAL ; + } + hdr = p +ceph_crypt_data_offset (key);if (le64_to_cpu (hdr->magic) !=CEPHX_ENC_MAGIC ) {pr_err ("%s bad magic\n" , __func__);
Greg Kroah-Hartman
maintainerPATCH 1117/1146 libceph: Fix potential out-of-bounds access in crush_decode()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit 4c79fc2d598694bda845b46229c9d48b65042970 upstream.
A message of type CEPH_MSG_OSD_MAP containing a crush map with at least one bucket has two fields holding the bucket algorithm. If the values in these two fields differ, an out-of-bounds access can occur. This is the case because the first algorithm field (alg) is used to allocate the correct amount of memory for a bucket of this type, while the second algorithm field inside the bucket (b->alg) is used in the subsequent processing.
This patch fixes the issue by adding a check that compares alg and b->alg and aborts the processing in case they differ. Furthermore, b->alg is set to 0 in this case, because the destruction of the crush map also uses this field to determine the bucket type, which can again result in an out-of-bounds access when trying to free the memory pointed to by the fields of the bucket. To correctly free the memory allocated for the bucket in such a case, the corresponding call to kfree is moved from the algorithm-specific crush_destroy_bucket functions to the generic crush_destroy_bucket().
--- net/ceph/crush/crush.c | 6 +----- net/ceph/osdmap.c | 4 ++++ 2 files changed, 5 insertions(+), 5 deletions(-)
net/ceph/crush/crush.c +1 -5
@@ -47,7 +47,6 @@ int crush_get_bucket_item_weight(const svoid crush_destroy_bucket_uniform (struct crush_bucket_uniform *b) {kfree (b->h.items); -kfree (b); }void crush_destroy_bucket_list (struct crush_bucket_list *b)
@@ -55,14 +54,12 @@ void crush_destroy_bucket_list(struct crkfree (b->item_weights);kfree (b->sum_weights);kfree (b->h.items); -kfree (b); }void crush_destroy_bucket_tree (struct crush_bucket_tree *b) {kfree (b->h.items);kfree (b->node_weights); -kfree (b); }void crush_destroy_bucket_straw (struct crush_bucket_straw *b)
@@ -70,14 +67,12 @@ void crush_destroy_bucket_straw(struct ckfree (b->straws);kfree (b->item_weights);kfree (b->h.items); -kfree (b); }void crush_destroy_bucket_straw2 (struct crush_bucket_straw2 *b) {kfree (b->item_weights);kfree (b->h.items); -kfree (b); }void crush_destroy_bucket (struct crush_bucket *b)
@@ -99,6 +94,7 @@ void crush_destroy_bucket(struct crush_bcrush_destroy_bucket_straw2 ((struct crush_bucket_straw2 *)b);break ; } +kfree (b); }/**
net/ceph/osdmap.c +4 -0
@@ -517,6 +517,10 @@ static struct crush_map *crush_decode(vo b->id =ceph_decode_32 (p); b->type =ceph_decode_16 (p); b->alg =ceph_decode_8 (p); +if (b->alg != alg) { + b->alg =0 ; + goto bad; + } b->hash =ceph_decode_8 (p); b->weight =ceph_decode_32 (p); b->size =ceph_decode_32 (p);
Greg Kroah-Hartman
maintainerPATCH 1118/1146 libceph: handle rbtree insertion error in decode_choose_args()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit d289478cfc0bcf81c7914200d6abdcb78bd04ded upstream.
A message of type CEPH_MSG_OSD_MAP contains an OSD map that itself contains a CRUSH map. The received CRUSH map may optionally contain choose_args that get decoded in decode_choose_args(). In this function, num_choose_arg_maps is read from the message, and a corresponding number of crush_choose_arg_maps gets decoded afterwards. Each crush_choose_arg_map has a choose_args_index, which serves as the key when inserting it into the choose_args rbtree of the decoded crush_map. If a (potentially corrupted) message contains two crush_choose_arg_maps with the same index, the assertion in insert_choose_arg_map() triggers a kernel BUG when trying to insert the second crush_choose_arg_map.
This patch fixes the issue by switching to the non-asserting rbtree insertion function and rejecting the message if the insertion fails.
[ idryomov: changelog ]
--- net/ceph/osdmap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/ceph/osdmap.c +4 -1
@@ -394,7 +394,10 @@ static int decode_choose_args(void **p, goto e_inval; } -insert_choose_arg_map (&c->choose_args, arg_map); +if (!__insert_choose_arg_map (&c->choose_args, arg_map)) { + ret = -EEXIST ; + goto fail; + } }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 1119/1146 iommu/vt-d: Disable DMAR for Intel Q35 IGFX
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naval Alcalá <[email protected]>
commit 2cda2e10dc8343ae01eae9e999a876b7e7d37861 upstream.
Intel Q35 integrated graphics (8086:29b2) exhibits broken DMAR behaviour similar to other G4x/GM45 devices for which DMAR is already disabled via quirks.
When DMAR is enabled, the system may hard lock up during boot or early device initialization, requiring a reset.
Add the missing PCI ID to the existing quirk list to disable DMAR for this device.
--- drivers/iommu/intel/iommu.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/iommu/intel/iommu.c +3 -0
@@ -3933,6 +3933,9 @@ static void quirk_iommu_igfx(struct pci_ disable_igfx_iommu =1 ; } +/* Q35 integrated gfx dmar support is totally busted. */ +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_INTEL ,0x29b2 , quirk_iommu_igfx); +/* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_INTEL ,0x2a40 , quirk_iommu_igfx);DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_INTEL ,0x2e00 , quirk_iommu_igfx);
Greg Kroah-Hartman
maintainerPATCH 1120/1146 iommu/vt-d: Fix oops due to out of scope access
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhenzhong Duan <[email protected]>
commit a6dea58d8625c06b9654c0555f101742481335c3 upstream.
Below oops triggers when kill QEMU process:
Oops: general protection fault, probably for non-canonical address 0x7fffffff844eaaa7: 0000 [#1] SMP NOPTI Call Trace: <TASK> do_raw_spin_lock+0xaa/0xc0 _raw_spin_lock_irqsave+0x21/0x40 domain_remove_dev_pasid+0x52/0x160 intel_nested_set_dev_pasid+0x1b9/0x1e0 __iommu_set_group_pasid+0x56/0x120 pci_dev_reset_iommu_done+0xe3/0x180 pcie_flr+0x65/0x160 __pci_reset_function_locked+0x5b/0x120 vfio_pci_core_close_device+0x63/0xe0 [vfio_pci_core] vfio_df_close+0x4f/0xa0 vfio_df_unbind_iommufd+0x2d/0x60 vfio_device_fops_release+0x3e/0x40 __fput+0xe5/0x2c0 task_work_run+0x58/0xa0 do_exit+0x2c8/0x600 do_group_exit+0x2f/0xa0 get_signal+0x863/0x8c0 arch_do_signal_or_restart+0x24/0x100 exit_to_user_mode_loop+0x87/0x380 do_syscall_64+0x2ff/0x11e0 entry_SYSCALL_64_after_hwframe+0x76/0x7e
The global static blocked domain is a dummy domain without corresponding dmar_domain structure, accessing beyond iommu_domain structure triggers oops easily. Fix it by return early in domain_remove_dev_pasid() like identity domain.
--- drivers/iommu/intel/iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/iommu/intel/iommu.c +2 -2
@@ -3529,8 +3529,8 @@ void domain_remove_dev_pasid(struct iommif (!domain)return ; -/* Identity domain has no meta data for pasid. */ -if (domain->type ==IOMMU_DOMAIN_IDENTITY ) +/* Identity domain and blocked domain have no meta data for pasid. */ +if (domain->type ==IOMMU_DOMAIN_IDENTITY || domain->type ==IOMMU_DOMAIN_BLOCKED )return ; dmar_domain =to_dmar_domain (domain);
Greg Kroah-Hartman
maintainerPATCH 1121/1146 iommu/vt-d: Avoid NULL pointer dereference or refcount corruption
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhenzhong Duan <[email protected]>
commit 79ea2feb917b05366b49d85573c9c5331f043b2c upstream.
Commit 60f030f7418d ("iommu/vt-d: Avoid use of NULL after WARN_ON_ONCE") fixed a NULL pointer dereference in an unlikely situation partly.
If dev_pasid is not found in the dev_pasids list, it remains NULL. However, the teardown operations are executed unconditionally, this lead to a NULL pointer dereference or refcount corruption.
If the domain was never attached to this IOMMU, info will be NULL, which would cause an immediate dereference when checking --info->refcnt.
Even if info is not NULL, decrementing the refcount without having removed a valid PASID might unbalance the count. This could lead to premature dropping of the refcount to 0, potentially causing a use-after-free for the remaining active devices sharing the domain.
Fix it by returning early if dev_pasid is NULL, before executing the teardown operations.
Issue found by AI review and suggested by Kevin Tian.
https://sashiko.dev/#/patchset/20260421031347.1408890-1-zhenzhong.duan%40intel.com
--- drivers/iommu/intel/iommu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/iommu/intel/iommu.c +5 -4
@@ -3544,12 +3544,13 @@ void domain_remove_dev_pasid(struct iomm }spin_unlock_irqrestore (&dmar_domain->lock, flags); +if (WARN_ON_ONCE (!dev_pasid)) +return ; +cache_tag_unassign_domain (dmar_domain, dev, pasid);domain_detach_iommu (dmar_domain, iommu); -if (!WARN_ON_ONCE (!dev_pasid)) { -intel_iommu_debugfs_remove_dev_pasid (dev_pasid); -kfree (dev_pasid); - } +intel_iommu_debugfs_remove_dev_pasid (dev_pasid); +kfree (dev_pasid); } static int blocking_domain_set_dev_pasid(struct iommu_domain *domain,
Greg Kroah-Hartman
maintainerPATCH 1122/1146 iommu: Fix NULL group->domain dereference in pci_dev_reset_iommu_done()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit d769711fcddd005f1e654b3bde547140917fe696 upstream.
Local sashiko review pointed it out that group->domain could be NULL when a default domain fails to allocate during the first probe, which can crash at domain->ops->attach_dev dereference in __iommu_attach_device() invoked by pci_dev_reset_iommu_done().
pci_dev_reset_iommu_prepare() is fine as an old_domain pointer can be NULL.
Skip the re-attach in pci_dev_reset_iommu_done() to fix the bug.
--- drivers/iommu/iommu.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/iommu/iommu.c +7 -2
@@ -4035,8 +4035,13 @@ void pci_dev_reset_iommu_done(struct pciif (WARN_ON (!group->blocking_domain))return ; -/* Re-attach RID domain back to group->domain */ -if (group->domain != group->blocking_domain) { +/* +* Re-attach RID domain back to group->domain +* +* Leave the device parked in the blocking_domain if group->domain isn't +* initialized yet +*/ +if (group->domain && group->domain != group->blocking_domain) {WARN_ON (__iommu_attach_device (group->domain, &pdev->dev, group->blocking_domain)); }
Greg Kroah-Hartman
maintainerPATCH 1123/1146 iommu: Replace per-group resetting_domain with per-gdev blocked flag
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit b296ca1fb43aa435edd86131f5230f70c03b2829 upstream.
The core tracks device resetting states with a per-group resetting_domain, while a reset is actually per group-device. Such a mismatch might lead to confusion and even difficulty to untangle per-gdev handling requirement.
Shuai found that cxl_reset_bus_function() calls pci_reset_bus_function() internally while both are calling pci_dev_reset_iommu_prepare/done(). And the solution requires the core to track at the group_device level as well.
Introduce a 'blocked' flag to struct group_device, to allow a multi-device group to isolate concurrent device resets independently.
As the reset routine is per gdev, it cannot clear group->resetting_domain without iterating over the device list to ensure no other device is being reset. Simplify it by replacing the resetting_domain with a 'recovery_cnt' in the struct iommu_group.
No functional change. But this is essential to apply following bug fixes.
--- drivers/iommu/iommu.c | 102 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 24 deletions(-)
drivers/iommu/iommu.c +78 -24
@@ -61,14 +61,14 @@ struct iommu_group {int id;struct iommu_domain *default_domain;struct iommu_domain *blocking_domain; -/* -* During a group device reset, @resetting_domain points to the physical -* domain, while @domain points to the attached domain before the reset. -*/ -struct iommu_domain *resetting_domain;struct iommu_domain *domain;struct list_head entry;unsigned int owner_cnt; +/* +* Number of devices in the group undergoing or awaiting recovery. +* If non-zero, concurrent domain attachments are rejected. +*/ +unsigned int recovery_cnt;void *owner; };
@@ -76,12 +76,32 @@ struct group_device {struct list_head list;struct device *dev;char *name; +/* +* Device is blocked for a pending recovery while its group->domain is +* retained. This can happen when: +* - Device is undergoing a reset +*/ +bool blocked; };/* Iterate over each struct group_device in a struct iommu_group */ #define for_each_group_device (group, pos) \ list_for_each_entry(pos, &(group)->devices, list) +static struct group_device *__dev_to_gdev (struct device *dev) +{ +struct iommu_group *group = dev->iommu_group; +struct group_device *gdev; + +lockdep_assert_held (&group->mutex); + +for_each_group_device (group, gdev) { +if (gdev->dev == dev) +return gdev; + } +return NULL ; +} +struct iommu_group_attribute {struct attribute attr;ssize_t (*show)(struct iommu_group *group,char *buf);
@@ -2195,6 +2215,8 @@ EXPORT_SYMBOL_GPL(iommu_attach_device);int iommu_deferred_attach (struct device *dev,struct iommu_domain *domain) { +struct group_device *gdev; +/* * This is called on the dma mapping fast path so avoid locking. This is * racy, but we have an expectation that the driver will setup its DMAs
@@ -2205,14 +2227,18 @@ int iommu_deferred_attach(struct deviceguard (mutex)(&dev->iommu_group->mutex); + gdev =__dev_to_gdev (dev); +if (WARN_ON (!gdev)) +return -ENODEV ; +/* -* This is a concurrent attach during a device reset. Reject it until +* This is a concurrent attach during device recovery. Reject it until * pci_dev_reset_iommu_done() attaches the device to group->domain. * * Note that this might fail the iommu_dma_map(). But there's nothing * more we can do here. */ -if (dev->iommu_group->resetting_domain) +if (gdev->blocked)return -EBUSY ;return __iommu_attach_device (domain, dev,NULL ); }
@@ -2269,19 +2295,24 @@ EXPORT_SYMBOL_GPL(iommu_get_domain_for_dstruct iommu_domain *iommu_driver_get_domain_for_dev (struct device *dev) {struct iommu_group *group = dev->iommu_group; +struct group_device *gdev;lockdep_assert_held (&group->mutex); + gdev =__dev_to_gdev (dev); +if (WARN_ON (!gdev)) +return NULL ; +/* * Driver handles the low-level __iommu_attach_device(), including the * one invoked by pci_dev_reset_iommu_done() re-attaching the device to * the cached group->domain. In this case, the driver must get the old -* domain from group->resetting_domain rather than group->domain. This +* domain from group->blocking_domain rather than group->domain. This * prevents it from re-attaching the device from group->domain (old) to * group->domain (new). */ -if (group->resetting_domain) -return group->resetting_domain; +if (gdev->blocked) +return group->blocking_domain;return group->domain; }
@@ -2440,10 +2471,10 @@ static int __iommu_group_set_domain_intereturn -EINVAL ;/* -* This is a concurrent attach during a device reset. Reject it until +* This is a concurrent attach during device recovery. Reject it until * pci_dev_reset_iommu_done() attaches the device to group->domain. */ -if (group->resetting_domain) +if (group->recovery_cnt)return -EBUSY ;/*
@@ -3577,10 +3608,10 @@ int iommu_attach_device_pasid(struct iommutex_lock (&group->mutex);/* -* This is a concurrent attach during a device reset. Reject it until +* This is a concurrent attach during device recovery. Reject it until * pci_dev_reset_iommu_done() attaches the device to group->domain. */ -if (group->resetting_domain) { +if (group->recovery_cnt) { ret = -EBUSY ; goto out_unlock; }
@@ -3670,10 +3701,10 @@ int iommu_replace_device_pasid(struct iomutex_lock (&group->mutex);/* -* This is a concurrent attach during a device reset. Reject it until +* This is a concurrent attach during device recovery. Reject it until * pci_dev_reset_iommu_done() attaches the device to group->domain. */ -if (group->resetting_domain) { +if (group->recovery_cnt) { ret = -EBUSY ; goto out_unlock; }
@@ -3944,12 +3975,12 @@ EXPORT_SYMBOL_NS_GPL(iommu_replace_group* routine wants to block any IOMMU activity: translation and ATS invalidation. * * This function attaches the device's RID/PASID(s) the group->blocking_domain, -* setting the group->resetting_domain. This allows the IOMMU driver pausing any +* incrementing the group->recovery_cnt, to allow the IOMMU driver pausing any * IOMMU activity while leaving the group->domain pointer intact. Later when the * reset is finished, pci_dev_reset_iommu_done() can restore everything. * * Caller must use pci_dev_reset_iommu_prepare() with pci_dev_reset_iommu_done() -* before/after the core-level reset routine, to unset the resetting_domain. +* before/after the core-level reset routine, to decrement the recovery_cnt. * * Return: 0 on success or negative error code if the preparation failed. *
@@ -3962,6 +3993,7 @@ EXPORT_SYMBOL_NS_GPL(iommu_replace_groupint pci_dev_reset_iommu_prepare (struct pci_dev *pdev) {struct iommu_group *group = pdev->dev.iommu_group; +struct group_device *gdev;unsigned long pasid;void *entry;int ret;
@@ -3971,8 +4003,12 @@ int pci_dev_reset_iommu_prepare(struct pguard (mutex)(&group->mutex); + gdev =__dev_to_gdev (&pdev->dev); +if (WARN_ON (!gdev)) +return -ENODEV ; +/* Re-entry is not allowed */ -if (WARN_ON (group->resetting_domain)) +if (WARN_ON (gdev->blocked))return -EBUSY ; ret =__iommu_group_alloc_blocking_domain (group);
@@ -3988,6 +4024,13 @@ int pci_dev_reset_iommu_prepare(struct p }/* +* Update gdev->blocked upon the domain change, as it is used to return +* the correct domain in iommu_driver_get_domain_for_dev() that might be +* called in a set_dev_pasid callback function. +*/ + gdev->blocked = true; + +/* * Stage PASID domains at blocking_domain while retaining pasid_array. * * The pasid_array is mostly fenced by group->mutex, except one reader
@@ -3997,7 +4040,7 @@ int pci_dev_reset_iommu_prepare(struct piommu_remove_dev_pasid (&pdev->dev, pasid,pasid_array_entry_to_domain (entry)); - group->resetting_domain = group->blocking_domain; + group->recovery_cnt++;return ret; }EXPORT_SYMBOL_GPL (pci_dev_reset_iommu_prepare);
@@ -4019,6 +4062,7 @@ EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_prvoid pci_dev_reset_iommu_done (struct pci_dev *pdev) {struct iommu_group *group = pdev->dev.iommu_group; +struct group_device *gdev;unsigned long pasid;void *entry;
@@ -4027,11 +4071,13 @@ void pci_dev_reset_iommu_done(struct pciguard (mutex)(&group->mutex); -/* pci_dev_reset_iommu_prepare() was bypassed for the device */ -if (!group->resetting_domain) + gdev =__dev_to_gdev (&pdev->dev); +if (WARN_ON (!gdev)) +return ; + +if (!gdev->blocked)return ; -/* pci_dev_reset_iommu_prepare() was not successfully called */ if (WARN_ON (!group->blocking_domain))return ;
@@ -4047,6 +4093,13 @@ void pci_dev_reset_iommu_done(struct pci }/* +* Update gdev->blocked upon the domain change, as it is used to return +* the correct domain in iommu_driver_get_domain_for_dev() that might be +* called in a set_dev_pasid callback function. +*/ + gdev->blocked = false; + +/* * Re-attach PASID domains back to the domains retained in pasid_array. * * The pasid_array is mostly fenced by group->mutex, except one reader
@@ -4057,7 +4110,8 @@ void pci_dev_reset_iommu_done(struct pcipasid_array_entry_to_domain (entry), group, pasid, group->blocking_domain)); - group->resetting_domain =NULL ; +if (!WARN_ON (group->recovery_cnt ==0 )) + group->recovery_cnt--; }EXPORT_SYMBOL_GPL (pci_dev_reset_iommu_done);
Greg Kroah-Hartman
maintainerPATCH 1124/1146 iommu: Fix WARN_ON in __iommu_group_set_domain_nofail() due to reset
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 5474e6e17a262db45c60575c73f70210f5c7001f upstream.
In __iommu_group_set_domain_internal(), concurrent domain attachments are rejected when any device in the group is recovering. This is necessary to fence concurrent attachments to a multi-device group where devices might share the same RID due to PCI DMA alias quirks, but triggers the WARN_ON in __iommu_group_set_domain_nofail().
Other IOMMU_SET_DOMAIN_MUST_SUCCEED callers in detach/teardown paths, such as __iommu_group_set_core_domain and __iommu_release_dma_ownership, should not be rejected, as the domain would be freed anyway in these nofail paths while group->domain is still pointing to it. So pci_dev_reset_iommu_done() could trigger a UAF when re-attaching group->domain.
Honor the IOMMU_SET_DOMAIN_MUST_SUCCEED flag, allowing the callers through the group->recovery_cnt fence, so as to update the group->domain pointer. Instead add a gdev->blocked check in the device iteration loop, to prevent any concurrent per-device detachment.
--- drivers/iommu/iommu.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/iommu/iommu.c +10 -2
@@ -2472,9 +2472,10 @@ static int __iommu_group_set_domain_inte/* * This is a concurrent attach during device recovery. Reject it until -* pci_dev_reset_iommu_done() attaches the device to group->domain. +* pci_dev_reset_iommu_done() attaches the device to group->domain, if +* IOMMU_SET_DOMAIN_MUST_SUCCEED is not set. */ -if (group->recovery_cnt) +if (group->recovery_cnt && !(flags &IOMMU_SET_DOMAIN_MUST_SUCCEED ))return -EBUSY ;/*
@@ -2485,6 +2486,13 @@ static int __iommu_group_set_domain_inte*/ result =0 ;for_each_group_device (group, gdev) { +/* +* Device under recovery is attached to group->blocking_domain. +* Don't change that. pci_dev_reset_iommu_done() will re-attach +* its domain to the updated group->domain, after the recovery. +*/ +if (gdev->blocked) +continue ; ret =__iommu_device_set_domain (group, gdev->dev, new_domain, group->domain, flags);if (ret) {
Greg Kroah-Hartman
maintainerPATCH 1125/1146 iommu: Fix pasid attach in pci_dev_reset_iommu_prepare/done()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 1615e8896a8f6d7b2adf6495e538a81bf6cea3e0 upstream.
Now the helpers handle per-gdev resets. Replace __iommu_set_group_pasid() with set_dev_pasid() accordingly, in the pci_dev_reset_iommu_done().
Also add max_pasids check as other callers.
--- drivers/iommu/iommu.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
drivers/iommu/iommu.c +18 -7
@@ -4044,9 +4044,14 @@ int pci_dev_reset_iommu_prepare(struct p* The pasid_array is mostly fenced by group->mutex, except one reader * in iommu_attach_handle_get(), so it's safe to read without xa_lock. */ -xa_for_each_start (&group->pasid_array, pasid, entry,1 ) -iommu_remove_dev_pasid (&pdev->dev, pasid, -pasid_array_entry_to_domain (entry)); +if (pdev->dev.iommu->max_pasids >0 ) { +xa_for_each_start (&group->pasid_array, pasid, entry,1 ) { +struct iommu_domain *pasid_dom = +pasid_array_entry_to_domain (entry); + +iommu_remove_dev_pasid (&pdev->dev, pasid, pasid_dom); + } + } group->recovery_cnt++;return ret;
@@ -4113,10 +4118,16 @@ void pci_dev_reset_iommu_done(struct pci* The pasid_array is mostly fenced by group->mutex, except one reader * in iommu_attach_handle_get(), so it's safe to read without xa_lock. */ -xa_for_each_start (&group->pasid_array, pasid, entry,1 ) -WARN_ON (__iommu_set_group_pasid ( -pasid_array_entry_to_domain (entry), group, pasid, - group->blocking_domain)); +if (pdev->dev.iommu->max_pasids >0 ) { +xa_for_each_start (&group->pasid_array, pasid, entry,1 ) { +struct iommu_domain *pasid_dom = +pasid_array_entry_to_domain (entry); + +WARN_ON (pasid_dom->ops->set_dev_pasid ( + pasid_dom, &pdev->dev, pasid, + group->blocking_domain)); + } + }if (!WARN_ON (group->recovery_cnt ==0 )) group->recovery_cnt--;
Greg Kroah-Hartman
maintainerPATCH 1126/1146 iommu: Fix nested pci_dev_reset_iommu_prepare/done()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 0d5fd7a9323ce6bedd170e21e1e90b8904917c75 upstream.
Shuai found that cxl_reset_bus_function() calls pci_reset_bus_function() internally while both are calling pci_dev_reset_iommu_prepare/done().
As pci_dev_reset_iommu_prepare() doesn't support re-entry, the inner call will trigger a WARN_ON and return -EBUSY, resulting in failing the entire device reset.
On the other hand, removing the outer calls in the PCI callers is unsafe. As pointed out by Kevin, device-specific quirks like reset_hinic_vf_dev() execute custom firmware waits after their inner pcie_flr() completes. If the IOMMU protection relies solely on the inner reset, the IOMMU will be unblocked prematurely while the device is still resetting.
Instead, fix this by making pci_dev_reset_iommu_prepare/done() reentrant.
Introduce gdev->reset_depth to handle the re-entries on the same device.
--- drivers/iommu/iommu.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/iommu/iommu.c +13 -6
@@ -82,6 +82,7 @@ struct group_device {* - Device is undergoing a reset */ bool blocked; +unsigned int reset_depth; };/* Iterate over each struct group_device in a struct iommu_group */
@@ -4015,20 +4016,23 @@ int pci_dev_reset_iommu_prepare(struct pif (WARN_ON (!gdev))return -ENODEV ; -/* Re-entry is not allowed */ -if (WARN_ON (gdev->blocked)) -return -EBUSY ; +if (gdev->reset_depth++) +return 0 ; ret =__iommu_group_alloc_blocking_domain (group); -if (ret) +if (ret) { + gdev->reset_depth--;return ret; + }/* Stage RID domain at blocking_domain while retaining group->domain */ if (group->domain != group->blocking_domain) { ret =__iommu_attach_device (group->blocking_domain, &pdev->dev, group->domain); -if (ret) +if (ret) { + gdev->reset_depth--;return ret; + } }/*
@@ -4088,7 +4092,10 @@ void pci_dev_reset_iommu_done(struct pciif (WARN_ON (!gdev))return ; -if (!gdev->blocked) +/* Unbalanced done() calls would underflow the counter */ +if (WARN_ON (gdev->reset_depth ==0 )) +return ; +if (--gdev->reset_depth)return ;if (WARN_ON (!group->blocking_domain))
Greg Kroah-Hartman
maintainerPATCH 1127/1146 iommu: Fix ATS invalidation timeouts during __iommu_remove_group_pasid()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit fc3523b16d2b4b88e61e69504b0ae0b18b869c8f upstream.
If a device is blocked, its PASID domains are already detached. Repeating iommu_remove_dev_pasid() is unnecessary and might trigger ATS invalidation timeouts.
Skip the iommu_remove_dev_pasid() call upon gdev->blocked.
--- drivers/iommu/iommu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/iommu/iommu.c +6 -1
@@ -3572,7 +3572,12 @@ static void __iommu_remove_group_pasid(sstruct group_device *device;for_each_group_device (group, device) { -if (device->dev->iommu->max_pasids >0 ) +/* +* A group-level detach cannot fail, even if there is a blocked +* device. In fact, blocked devices must be already detached for +* a pending device recovery. +*/ +if (!device->blocked && device->dev->iommu->max_pasids >0 )iommu_remove_dev_pasid (device->dev, pasid, domain); } }
Greg Kroah-Hartman
maintainerPATCH 1128/1146 drm/i915: skip __i915_request_skip() for already signaled requests
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Brzezinka <[email protected]>
commit 4cfe4c0efbdcde742a47813180cc69b132d7598e upstream.
After a GPU reset the HWSP is zeroed, so previously completed requests appear incomplete. If such a request is picked up during reset_rewind() and marked guilty, i915_request_set_error_once() returns early (fence already signaled), leaving fence.error without a fatal error code. The subsequent __i915_request_skip() then hits:
``` GEM_BUG_ON(!fatal_error(rq->fence.error)) ```
Fixes a kernel BUG observed on Sandy Bridge (Gen6) during heartbeat-triggered engine resets.
``` kernel BUG at drivers/gpu/drm/i915/i915_request.c:556! RIP: __i915_request_skip+0x15e/0x1d0 [i915] ... __i915_request_reset+0x212/0xa70 [i915] reset_rewind+0xe4/0x280 [i915] intel_gt_reset+0x30d/0x5b0 [i915] heartbeat+0x516/0x530 [i915] ```
Guard __i915_request_skip() with i915_request_signaled(), if the fence is already signaled, the ring content is committed and there is nothing left to skip.
--- drivers/gpu/drm/i915/gt/intel_reset.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/gt/intel_reset.c +2 -1
@@ -132,7 +132,8 @@ void __i915_request_reset(struct i915_rercu_read_lock ();/* protect the GEM context */ if (guilty) {i915_request_set_error_once (rq, -EIO ); -__i915_request_skip (rq); +if (!i915_request_signaled (rq)) +__i915_request_skip (rq); banned =mark_guilty (rq); }else {i915_request_set_error_once (rq, -EAGAIN );
Greg Kroah-Hartman
maintainerPATCH 1129/1146 drm/panfrost: Fix wait_bo ioctl leaking positive return from dma_resv_wait_timeout()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gyeyoung Baek <[email protected]>
commit 459d75523b71c0ec254d153d8850d0b7008af396 upstream.
dma_resv_wait_timeout() returns a positive 'remaining jiffies' value on success, 0 on timeout, and -errno on failure.
panfrost_ioctl_wait_bo() returns this 'long' result from an int-typed ioctl handler, so positive values reach userspace as bogus errors. Explicitly set ret to 0 on the success path.
--- drivers/gpu/drm/panfrost/panfrost_drv.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/panfrost/panfrost_drv.c +2 -0
@@ -390,6 +390,8 @@ panfrost_ioctl_wait_bo(struct drm_device true, timeout);if (!ret) ret = timeout ? -ETIMEDOUT : -EBUSY ; +else if (ret >0 ) + ret =0 ;drm_gem_object_put (gem_obj);
Greg Kroah-Hartman
maintainerPATCH 1130/1146 drm/xe/dma-buf: handle empty bo and UAF races
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Auld <[email protected]>
commit 981bedbbe61364fcc3a3b87ebaf648a66cd07108 upstream.
There look to be some nasty races here when triggering the invalidate_mappings hook:
1) We do xe_bo_alloc() followed by the attach, before the actual full bo init step in xe_dma_buf_init_obj(). However the bo is visible on the attachments list after the attach. This is bad since exporter driver, say amdgpu, can at any time call back into our invalidate_mappings hook, with an empty/bogus bo, leading to potential bugs/crashes.
2) Similar to 1) but here we get a UAF, when the invalidate_mappings hook is triggered. For example, we get as far as xe_bo_init_locked() but this fails in some way. But here the bo will be freed on error, but we still have it attached from dma-buf pov, so if the invalidate_mappings is now triggered then the bo we access is gone and we trigger UAF and more bugs/crashes.
To fix this, move the attach step until after we actually have a fully set up buffer object. Note that the bo is not published to userspace until later, so not sure what the comment "Don't publish the bo until we have a valid attachment", is referring to.
We have at least two different customers reporting hitting a NULL ptr deref in evict_flags when importing something from amdgpu, followed by triggering the evict flow. Hit rate is also pretty low, which would hint at some kind of race, so something like 1) or 2) might explain this.
v2:
- Shuffle the order of the ops slightly (no functional change)
- Improve the comment to better explain the ordering (Matt B)
--- drivers/gpu/drm/xe/xe_dma_buf.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-)
drivers/gpu/drm/xe/xe_dma_buf.c +16 -15
@@ -337,15 +337,25 @@ struct drm_gem_object *xe_gem_prime_impo } } -/* -* Don't publish the bo until we have a valid attachment, and a -* valid attachment needs the bo address. So pre-create a bo before -* creating the attachment and publish. -*/ bo =xe_bo_alloc ();if (IS_ERR (bo))return ERR_CAST (bo); +/* +* xe_dma_buf_init_obj() takes ownership of the raw bo, so do not touch +* on fail, since it will already take care of cleanup. On success we +* still need to drop the ref, if something later fails. +* +* In addition this needs to happen before the attach, since +* it will create a new attachment for this, and add it to the list of +* attachments, at which point it is globally visible, and at any point +* the export side can call into on invalidate_mappings callback, which +* require a working object. +*/ + obj =xe_dma_buf_init_obj (dev, bo, dma_buf); +if (IS_ERR (obj)) +return obj; + attach_ops = &xe_dma_buf_attach_ops;#if IS_ENABLED (CONFIG_DRM_XE_KUNIT_TEST )if (test)
@@ -358,21 +368,12 @@ struct drm_gem_object *xe_gem_prime_impo goto out_err; } -/* -* xe_dma_buf_init_obj() takes ownership of bo on both success -* and failure, so we must not touch bo after this call. -*/ - obj =xe_dma_buf_init_obj (dev, bo, dma_buf); -if (IS_ERR (obj)) { -dma_buf_detach (dma_buf, attach); -return obj; - }get_dma_buf (dma_buf); obj->import_attach = attach;return obj; out_err: -xe_bo_free (bo); +xe_bo_put (bo);return obj; }
Greg Kroah-Hartman
maintainerPATCH 1131/1146 drm/xe/dma-buf: fix UAF with retry loop
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Auld <[email protected]>
commit 155a372a1cc50fa93387c5d3cdfd614a61e1afd1 upstream.
Retry doesn't work here, since bo will be freed on error, leading to UAF. However, now that we do the alloc & init before the attach, we can now combine this as one unit and have the init do the alloc for us. This should make the retry safe.
Reported by Sashiko.
v2: Fix up the error unwind (CI)
--- drivers/gpu/drm/xe/xe_dma_buf.c | 49 +++++++++------------------------------- 1 file changed, 12 insertions(+), 37 deletions(-)
drivers/gpu/drm/xe/xe_dma_buf.c +12 -37
@@ -238,16 +238,8 @@ struct dma_buf *xe_gem_prime_export(strureturn buf; } -/* -* Takes ownership of @storage: on success it is transferred to the returned -* drm_gem_object; on failure it is freed before returning the error. -* This matches the contract of xe_bo_init_locked() which frees @storage on -* its error paths, so callers need not (and must not) free @storage after -* this call. -*/ static struct drm_gem_object * -xe_dma_buf_init_obj (struct drm_device *dev,struct xe_bo *storage, -struct dma_buf *dma_buf) +xe_dma_buf_create_obj (struct drm_device *dev,struct dma_buf *dma_buf) {struct dma_resv *resv = dma_buf->resv;struct xe_device *xe =to_xe_device (dev);
@@ -258,10 +250,8 @@ xe_dma_buf_init_obj(struct drm_device *dint ret =0 ; dummy_obj =drm_gpuvm_resv_object_alloc (&xe->drm); -if (!dummy_obj) { -xe_bo_free (storage); +if (!dummy_obj)return ERR_PTR (-ENOMEM ); - } dummy_obj->resv = resv; xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {}, ret) {
@@ -270,8 +260,7 @@ xe_dma_buf_init_obj(struct drm_device *dif (ret)break ; -/* xe_bo_init_locked() frees storage on error */ - bo =xe_bo_init_locked (xe, storage,NULL , resv,NULL , dma_buf->size, + bo =xe_bo_init_locked (xe,NULL ,NULL , resv,NULL , dma_buf->size,0 ,/* Will require 1way or 2way for vm_bind */ ttm_bo_type_sg,XE_BO_FLAG_SYSTEM , &exec);drm_exec_retry_on_contention (&exec);
@@ -322,7 +311,6 @@ struct drm_gem_object *xe_gem_prime_impoconst struct dma_buf_attach_ops *attach_ops;struct dma_buf_attachment *attach;struct drm_gem_object *obj; -struct xe_bo *bo;if (dma_buf->ops == &xe_dmabuf_ops) { obj = dma_buf->priv;
@@ -337,22 +325,14 @@ struct drm_gem_object *xe_gem_prime_impo } } - bo =xe_bo_alloc (); -if (IS_ERR (bo)) -return ERR_CAST (bo); -/* -* xe_dma_buf_init_obj() takes ownership of the raw bo, so do not touch -* on fail, since it will already take care of cleanup. On success we -* still need to drop the ref, if something later fails. -* -* In addition this needs to happen before the attach, since -* it will create a new attachment for this, and add it to the list of -* attachments, at which point it is globally visible, and at any point -* the export side can call into on invalidate_mappings callback, which -* require a working object. +* This needs to happen before the attach, since it will create a new +* attachment for this, and add it to the list of attachments, at which +* point it is globally visible, and at any point the export side can +* call into on invalidate_mappings callback, which require a working +* object. */ - obj =xe_dma_buf_init_obj (dev, bo, dma_buf); + obj =xe_dma_buf_create_obj (dev, dma_buf);if (IS_ERR (obj))return obj;
@@ -362,20 +342,15 @@ struct drm_gem_object *xe_gem_prime_impo attach_ops = test->attach_ops;#endif - attach =dma_buf_dynamic_attach (dma_buf, dev->dev, attach_ops, &bo->ttm.base); + attach =dma_buf_dynamic_attach (dma_buf, dev->dev, attach_ops, obj);if (IS_ERR (attach)) { - obj =ERR_CAST (attach); - goto out_err; +xe_bo_put (gem_to_xe_bo (obj)); +return ERR_CAST (attach); }get_dma_buf (dma_buf); obj->import_attach = attach;return obj; - -out_err: -xe_bo_put (bo); - -return obj; }#if IS_ENABLED (CONFIG_DRM_XE_KUNIT_TEST )
Greg Kroah-Hartman
maintainerPATCH 1132/1146 drm/ttm: Fix ttm_bo_shrink() infinite LRU walk on backup failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Hellström <[email protected]>
commit 1d59f36e95f7f7134db0e313c9d787cb0adb2153 upstream.
Apply the same fix as b2ed01e7ad ("drm/ttm: Fix ttm_bo_swapout() infinite LRU walk on swapout failure") to the ttm_bo_shrink() path.
Move del_bulk_move from before the backup to after success only, using ttm_resource_del_bulk_move_unevictable() since the resource is now unevictable once fully backed up.
--- drivers/gpu/drm/ttm/ttm_bo_util.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
drivers/gpu/drm/ttm/ttm_bo_util.c +3 -8
@@ -1112,19 +1112,14 @@ long ttm_bo_shrink(struct ttm_operation_if (lret <0 )return lret; -if (bo->bulk_move) { -spin_lock (&bdev->lru_lock); -ttm_resource_del_bulk_move (bo->resource, bo); -spin_unlock (&bdev->lru_lock); - } - lret =ttm_tt_backup (bdev, bo->ttm, (struct ttm_backup_flags ) {.purge = flags.purge, .writeback = flags.writeback}); -if (lret <=0 && bo->bulk_move) { +if (lret >0 ) {spin_lock (&bdev->lru_lock); -ttm_resource_add_bulk_move (bo->resource, bo); +ttm_resource_del_bulk_move_unevictable (bo->resource, bo); +ttm_resource_move_to_lru_tail (bo->resource);spin_unlock (&bdev->lru_lock); }
Greg Kroah-Hartman
maintainerPATCH 1133/1146 drm/ttm: Convert -EAGAIN from dmem_cgroup_try_charge to -ENOSPC
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Hellström <[email protected]>
commit 591711b32681a04b57d00c2a404658f8419a081c upstream.
dmem_cgroup_try_charge() returns -EAGAIN when the cgroup limit is hit and the charge fails. TTM has no concept of -EAGAIN from resource allocation; -ENOSPC is the canonical error meaning "no space, try eviction". Convert at the source in ttm_resource_alloc() so no caller needs to handle an unexpected error code, and clean up the now-redundant -EAGAIN check in ttm_bo_alloc_resource().
Without this, -EAGAIN escaping ttm_resource_alloc() during an eviction walk causes the walk to terminate early instead of continuing to the next candidate.
--- drivers/gpu/drm/ttm/ttm_bo.c | 2 +- drivers/gpu/drm/ttm/ttm_resource.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/ttm/ttm_bo.c +1 -1
@@ -740,7 +740,7 @@ static int ttm_bo_alloc_resource(struct may_evict = (force_space && place->mem_type !=TTM_PL_SYSTEM ); ret =ttm_resource_alloc (bo, place, res, force_space ? &limit_pool :NULL );if (ret) { -if (ret != -ENOSPC && ret != -EAGAIN ) { +if (ret != -ENOSPC ) {dmem_cgroup_pool_state_put (limit_pool);return ret; }
drivers/gpu/drm/ttm/ttm_resource.c +4 -1
@@ -398,8 +398,11 @@ int ttm_resource_alloc(struct ttm_bufferif (man->cg) { ret =dmem_cgroup_try_charge (man->cg, bo->base.size, &pool, ret_limit_pool); -if (ret) +if (ret) { +if (ret == -EAGAIN ) + ret = -ENOSPC ;return ret; + } } ret = man->func->alloc (man, bo, place, res_ptr);
Greg Kroah-Hartman
maintainerPATCH 1134/1146 drm/gma500/oaktrail_hdmi: fix i2c adapter leak on setup
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 950953f774b3f69da6f413e045ef075e1f3da2df upstream.
Make sure to drop the reference taken to the I2C adapter (and its module) when setting up HDMI to allow the adapter to be deregistered.
--- drivers/gpu/drm/gma500/oaktrail_hdmi.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/gma500/oaktrail_hdmi.c +1 -0
@@ -580,6 +580,7 @@ static int oaktrail_hdmi_get_modes(struc }else { edid = (struct edid *)raw_edid;/* FIXME ? edid = drm_get_edid(connector, i2c_adap); */ +i2c_put_adapter (i2c_adap); }if (edid) {
Greg Kroah-Hartman
maintainerPATCH 1135/1146 drm/gma500/oaktrail_lvds: fix hang on init failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 657a091ab6d01d0091b77660c75cfed573c9a53e upstream.
The LVDS init code looks up an I2C adapter using i2c_get_adapter() and tries to read the EDID before falling back to allocating and registering its own adapter.
The error handling does not separate these cases so on a late init failure it will try to deregister and free also an adapter that had previously been registered. Since i2c_get_adapter() takes another reference to the adapter, deregistration hangs indefinitely while waiting for the reference to be released.
Fix this by only destroying adapters allocated during LVDS init on errors.
--- drivers/gpu/drm/gma500/oaktrail_lvds.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/gpu/drm/gma500/oaktrail_lvds.c +3 -2
@@ -293,7 +293,7 @@ void oaktrail_lvds_init(struct drm_devic {struct gma_encoder *gma_encoder;struct gma_connector *gma_connector; -struct gma_i2c_chan *ddc_bus; +struct gma_i2c_chan *ddc_bus =NULL ;struct drm_connector *connector;struct drm_encoder *encoder;struct drm_psb_private *dev_priv =to_drm_psb_private (dev);
@@ -421,7 +421,8 @@ out: err_unlock:mutex_unlock (&dev->mode_config.mutex); -gma_i2c_destroy (to_gma_i2c_chan (connector->ddc)); +if (!IS_ERR_OR_NULL (ddc_bus)) +gma_i2c_destroy (ddc_bus);drm_encoder_cleanup (encoder); err_connector_cleanup:drm_connector_cleanup (connector);
Greg Kroah-Hartman
maintainerPATCH 1136/1146 drm/gma500/oaktrail_lvds: fix i2c adapter leaks on init
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 84d1c9b416d54afe760ca4c378bd95c89261254c upstream.
The LVDS init code looks up an I2C adapter using i2c_get_adapter() and tries to read the EDID before falling back to allocating and registering its own adapter.
Make sure to drop the references taken by i2c_get_adapter() when falling back to allocating an adapter as well as on late errors to allow the looked up adapter to be deregistered.
--- drivers/gpu/drm/gma500/oaktrail_lvds.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/gpu/drm/gma500/oaktrail_lvds.c +4 -0
@@ -367,6 +367,8 @@ void oaktrail_lvds_init(struct drm_devicif (edid ==NULL && dev_priv->lpc_gpio_base) { ddc_bus =oaktrail_lvds_i2c_init (dev);if (!IS_ERR (ddc_bus)) { +if (i2c_adap) +i2c_put_adapter (i2c_adap); i2c_adap = &ddc_bus->base; edid =drm_get_edid (connector, i2c_adap); }
@@ -423,6 +425,8 @@ err_unlock:mutex_unlock (&dev->mode_config.mutex);if (!IS_ERR_OR_NULL (ddc_bus))gma_i2c_destroy (ddc_bus); +else if (i2c_adap) +i2c_put_adapter (i2c_adap);drm_encoder_cleanup (encoder); err_connector_cleanup:drm_connector_cleanup (connector);
Greg Kroah-Hartman
maintainerPATCH 1137/1146 arm_mpam: Fix monitor instance selection when checking for hardware NRDY
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Horgan <[email protected]>
commit 1ef2a89584b7b788b2603590d886db076b2f24cc upstream.
In _mpam_ris_hw_probe_hw_nrdy() a new register value to select the first monitor and relevant RIS is prepared in mon_sel. However, it is written to the monitor value register, e.g. MSMON_CSU, rather than MSMON_CFG_MON_SEL.
As MSMON_CFG_MON_SEL is a 32 bit register update the type of mon_sel to u32. Write mon_sel to the intended register, MSMON_CFG_MON_SEL.
--- drivers/resctrl/mpam_devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/resctrl/mpam_devices.c +2 -2
@@ -635,7 +635,7 @@ static struct mpam_msc_ris *mpam_get_or_static bool _mpam_ris_hw_probe_hw_nrdy (struct mpam_msc_ris *ris,u32 mon_reg) {u32 now; -u64 mon_sel; +u32 mon_sel;bool can_set, can_clear;struct mpam_msc *msc = ris->vmsc->msc;
@@ -644,7 +644,7 @@ static bool _mpam_ris_hw_probe_hw_nrdy(s mon_sel =FIELD_PREP (MSMON_CFG_MON_SEL_MON_SEL ,0 ) |FIELD_PREP (MSMON_CFG_MON_SEL_RIS , ris->ris_idx); -_mpam_write_monsel_reg (msc, mon_reg, mon_sel); +mpam_write_monsel_reg (msc,CFG_MON_SEL , mon_sel);_mpam_write_monsel_reg (msc, mon_reg,MSMON___NRDY ); now =_mpam_read_monsel_reg (msc, mon_reg);
Greg Kroah-Hartman
maintainerPATCH 1138/1146 arm_mpam: Pretend that NRDY is always hardware managed
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Horgan <[email protected]>
commit 4387970bbd84fd14e0c49c3089c5061ccd86b98a upstream.
Rule ZTXDS of the MPAM specification, IHI009 version B.b, states: "If a monitor does not support automatic updates of NRDY, software can use that bit for any purpose."
As software is not reliably informed whether or not the monitor supports automatic updates of NRDY always assume that hardware may manage NRDY but don't rely on it. When NRDY is truly untouched by hardware then, as it is written to 0 on configuration, it will always read 0.
At probe it's checked if MSMON_CSU.NRDY and MSMON_MBWU.NRDY are hardware managed but not MSMON_MBWU_L.NDRY. Specialize the checking for hardware managed NRDY to CSU counters as this is the only case where hardware management makes sense. Continue to inform the user if MSMON_CSU.NRDY appears to be hardware managed but the firmware doesn't provide the associated time limit for the automatic clearing of NRDY. Remove the NRDY feature flags as they are now unused.
--- drivers/resctrl/mpam_devices.c | 53 ++++++++++++---------------------------- drivers/resctrl/mpam_internal.h | 2 - 2 files changed, 17 insertions(+), 38 deletions(-)
drivers/resctrl/mpam_devices.c +17 -36
@@ -632,7 +632,7 @@ static struct mpam_msc_ris *mpam_get_or_* Try and see what values stick in this bit. If we can write either value, * its probably not implemented by hardware. */ -static bool _mpam_ris_hw_probe_hw_nrdy (struct mpam_msc_ris *ris,u32 mon_reg) +static bool mpam_ris_hw_probe_csu_nrdy (struct mpam_msc_ris *ris) {u32 now;u32 mon_sel;
@@ -646,21 +646,18 @@ static bool _mpam_ris_hw_probe_hw_nrdy(sFIELD_PREP (MSMON_CFG_MON_SEL_RIS , ris->ris_idx);mpam_write_monsel_reg (msc,CFG_MON_SEL , mon_sel); -_mpam_write_monsel_reg (msc, mon_reg,MSMON___NRDY ); - now =_mpam_read_monsel_reg (msc, mon_reg); +_mpam_write_monsel_reg (msc,MSMON_CSU ,MSMON___NRDY ); + now =_mpam_read_monsel_reg (msc,MSMON_CSU ); can_set = now &MSMON___NRDY ; -_mpam_write_monsel_reg (msc, mon_reg,0 ); - now =_mpam_read_monsel_reg (msc, mon_reg); +_mpam_write_monsel_reg (msc,MSMON_CSU ,0 ); + now =_mpam_read_monsel_reg (msc,MSMON_CSU ); can_clear = !(now &MSMON___NRDY );mpam_mon_sel_unlock (msc);return (!can_set || !can_clear); } -#define mpam_ris_hw_probe_hw_nrdy (_ris, _mon_reg) \ - _mpam_ris_hw_probe_hw_nrdy(_ris, MSMON_##_mon_reg) -static void mpam_ris_hw_probe (struct mpam_msc_ris *ris) {int err;
@@ -770,20 +767,18 @@ static void mpam_ris_hw_probe(struct mpampam_set_feature (mpam_feat_msmon_csu_xcl, props);/* Is NRDY hardware managed? */ - hw_managed =mpam_ris_hw_probe_hw_nrdy (ris,CSU ); -if (hw_managed) -mpam_set_feature (mpam_feat_msmon_csu_hw_nrdy, props); - } + hw_managed =mpam_ris_hw_probe_csu_nrdy (ris); -/* -* Accept the missing firmware property if NRDY appears -* un-implemented. -*/ -if (err &&mpam_has_feature (mpam_feat_msmon_csu_hw_nrdy, props)) -dev_err_once (dev,"Counters are not usable because not-ready timeout was not provided by firmware." ); +/* +* Accept the missing firmware property if NRDY appears +* un-implemented. +*/ +if (err && hw_managed) +dev_err_once (dev,"Counters are not usable because not-ready timeout was not provided by firmware." ); + } }if (FIELD_GET (MPAMF_MSMON_IDR_MSMON_MBWU , msmon_features)) { -bool has_long, hw_managed; +bool has_long;u32 mbwumon_idr =mpam_read_partsel_reg (msc,MBWUMON_IDR ); props->num_mbwu_mon =FIELD_GET (MPAMF_MBWUMON_IDR_NUM_MON , mbwumon_idr);
@@ -802,16 +797,6 @@ static void mpam_ris_hw_probe(struct mpa }else {mpam_set_feature (mpam_feat_msmon_mbwu_31counter, props); } - -/* Is NRDY hardware managed? */ - hw_managed =mpam_ris_hw_probe_hw_nrdy (ris,MBWU ); -if (hw_managed) -mpam_set_feature (mpam_feat_msmon_mbwu_hw_nrdy, props); - -/* -* Don't warn about any missing firmware property for -* MBWU NRDY - it doesn't make any sense! -*/ } } }
@@ -1078,7 +1063,6 @@ static void __ris_msmon_read(void *arg)bool reset_on_next_read = false;struct mpam_msc_ris *ris = m->ris;struct msmon_mbwu_state *mbwu_state; -struct mpam_props *rprops = &ris->props;struct mpam_msc *msc = m->ris->vmsc->msc;u32 mon_sel, ctl_val, flt_val, cur_ctl, cur_flt;
@@ -1134,8 +1118,7 @@ static void __ris_msmon_read(void *arg)switch (m->type) {case mpam_feat_msmon_csu: now =mpam_read_monsel_reg (msc,CSU ); -if (mpam_has_feature (mpam_feat_msmon_csu_hw_nrdy, rprops)) - nrdy = now &MSMON___NRDY ; + nrdy = now &MSMON___NRDY ; now =FIELD_GET (MSMON___VALUE , now);break ;case mpam_feat_msmon_mbwu_31counter:
@@ -1143,8 +1126,7 @@ static void __ris_msmon_read(void *arg)case mpam_feat_msmon_mbwu_63counter:if (m->type != mpam_feat_msmon_mbwu_31counter) { now =mpam_msc_read_mbwu_l (msc); -if (mpam_has_feature (mpam_feat_msmon_mbwu_hw_nrdy, rprops)) - nrdy = now &MSMON___L_NRDY ; + nrdy = now &MSMON___L_NRDY ;if (m->type == mpam_feat_msmon_mbwu_63counter) now =FIELD_GET (MSMON___LWD_VALUE , now);
@@ -1152,8 +1134,7 @@ static void __ris_msmon_read(void *arg) now =FIELD_GET (MSMON___L_VALUE , now); }else { now =mpam_read_monsel_reg (msc,MBWU ); -if (mpam_has_feature (mpam_feat_msmon_mbwu_hw_nrdy, rprops)) - nrdy = now &MSMON___NRDY ; + nrdy = now &MSMON___NRDY ; now =FIELD_GET (MSMON___VALUE , now); }
drivers/resctrl/mpam_internal.h +0 -2
@@ -167,14 +167,12 @@ enum mpam_device_features { mpam_feat_msmon_csu, mpam_feat_msmon_csu_capture, mpam_feat_msmon_csu_xcl, - mpam_feat_msmon_csu_hw_nrdy, mpam_feat_msmon_mbwu, mpam_feat_msmon_mbwu_31counter, mpam_feat_msmon_mbwu_44counter, mpam_feat_msmon_mbwu_63counter, mpam_feat_msmon_mbwu_capture, mpam_feat_msmon_mbwu_rwbw, - mpam_feat_msmon_mbwu_hw_nrdy, mpam_feat_partid_nrw,MPAM_FEATURE_LAST };
Greg Kroah-Hartman
maintainerPATCH 1139/1146 arm_mpam: Improve check for whether or not NRDY is hardware managed
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Horgan <[email protected]>
commit ccad6001be5c38426ccf45790c411467ad3c03c6 upstream.
mpam_ris_hw_probe_csu_nrdy() sets and clears MSMON_CSU.NRDY and checks whether it's configuration sticks. However, hardware isn't given a chance to disagree. Based on rule LRTGP, in MPAM specification IHI0099 version B.b, the hardware will set NRDY if it needs time to establish a count after a configuration change.
Enable the monitor so that NRDY becomes relevant and change the configuration after clearing NRDY to try and coax the hardware into setting it.
--- drivers/resctrl/mpam_devices.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/resctrl/mpam_devices.c +11 -2
@@ -634,8 +634,7 @@ static struct mpam_msc_ris *mpam_get_or_*/ static bool mpam_ris_hw_probe_csu_nrdy (struct mpam_msc_ris *ris) { -u32 now; -u32 mon_sel; +u32 now, mon_sel, ctl_val;bool can_set, can_clear;struct mpam_msc *msc = ris->vmsc->msc;
@@ -646,11 +645,21 @@ static bool mpam_ris_hw_probe_csu_nrdy(sFIELD_PREP (MSMON_CFG_MON_SEL_RIS , ris->ris_idx);mpam_write_monsel_reg (msc,CFG_MON_SEL , mon_sel); +/* Hardware might ignore nrdy if it's not enabled */ + ctl_val =MSMON_CFG_CSU_CTL_TYPE_CSU ; + ctl_val |= MSMON_CFG_x_CTL_MATCH_PARTID; + ctl_val |= MSMON_CFG_x_CTL_MATCH_PMG; + ctl_val |= MSMON_CFG_x_CTL_EN; +mpam_write_monsel_reg (msc,CFG_CSU_FLT ,0 ); +mpam_write_monsel_reg (msc,CFG_CSU_CTL , ctl_val); +_mpam_write_monsel_reg (msc,MSMON_CSU ,MSMON___NRDY ); now =_mpam_read_monsel_reg (msc,MSMON_CSU ); can_set = now &MSMON___NRDY ;_mpam_write_monsel_reg (msc,MSMON_CSU ,0 ); +/* Configuration change to try and coax hardware into setting nrdy */ +mpam_write_monsel_reg (msc,CFG_CSU_FLT ,0x1 ); now =_mpam_read_monsel_reg (msc,MSMON_CSU ); can_clear = !(now &MSMON___NRDY );mpam_mon_sel_unlock (msc);
Greg Kroah-Hartman
maintainerPATCH 1140/1146 arm_mpam: Fix false positive assert failure during mpam_disable()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Morse <[email protected]>
commit f1caff3335ea6eab88cdc84ec8f2e3c45ca05486 upstream.
mpam_assert_partid_sizes_fixed() is used to document that the caller doesn't expect the discovered PARTID size to change while it is walking a list sized by PARTID. Typically the MSC state is not written to until all the MSC have been discovered and this value is set.
However, if discovering the MSC fails and schedules mpam_disable(), then the MSC state is written to reset it. In this case the discovered PARTID size may be become smaller - but only PARTID 0 will be used once resctrl_exit() has been called.
Skip the WARN_ON_ONCE() if mpam_disable_reason has been set.
--- drivers/resctrl/mpam_devices.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/resctrl/mpam_devices.c +8 -2
@@ -148,11 +148,17 @@ static void mpam_free_garbage(void)/* * Once mpam is enabled, new requestors cannot further reduce the available * partid. Assert that the size is fixed, and new requestors will be turned -* away. +* away. This is needed when walking over structures sized by PARTID. +* +* During mpam_disable() these structures are not fixed, but the MSC state +* is still reset using whatever sizes have been discovered so far. As only +* PARTID 0 will be used after mpam_disable(), any race would be benign. +* Skip the check if a mpam_disable_reason has been set. */ static void mpam_assert_partid_sizes_fixed (void ) { -WARN_ON_ONCE (!partid_max_published); +if (!mpam_disable_reason) +WARN_ON_ONCE (!partid_max_published); }static u32 __mpam_read_reg (struct mpam_msc *msc,u16 reg)
Greg Kroah-Hartman
maintainerPATCH 1141/1146 arm_mpam: Check whether the config array is allocated before destroying it
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Morse <[email protected]>
commit 6ccbb613b42a1f1ba7bfd547a148f644a902a25c upstream.
__destroy_component_cfg() is called to free the configuration array. It uses the embedded 'garbage' structure, which means the array has to be allocated.
If __destroy_component_cfg() is called from mpam_disable() before the configuration was ever allocated, then a NULL pointer is dereferenced.
Check for this case and return early if the configuration is not allocated.
__destroy_component_cfg() also frees the mbwu_state as this is allocated by __allocate_component_cfg(). As the mbwu_state is allocated after comp->cfg is set, and is also under mpam_list_lock, only the first pointer needs checking.
--- drivers/resctrl/mpam_devices.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/resctrl/mpam_devices.c +3 -0
@@ -2359,6 +2359,9 @@ static void __destroy_component_cfg(strulockdep_assert_held (&mpam_list_lock); +if (!comp->cfg) +return ; +add_to_garbage (comp->cfg);list_for_each_entry (vmsc, &comp->vmsc, comp_list) { msc = vmsc->msc;
Greg Kroah-Hartman
maintainerPATCH 1142/1146 eventfs: Simplify code using guard()s
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 4d9b262031ffef203243e53577a90ae6e1090e67 ]
Use guard(mutex), scoped_guard(mutex) and guard(src) to simplify the code and remove a lot of the jumps to "out:" labels.
Stable-dep-of: f67950b2887f ("eventfs: Use list_add_tail_rcu() for SRCU-protected children list")
--- fs/tracefs/event_inode.c | 96 +++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 60 deletions(-)
fs/tracefs/event_inode.c +36 -60
@@ -180,29 +180,25 @@ static int eventfs_set_attr(struct mnt_iconst char *name;int ret; -mutex_lock (&eventfs_mutex); +guard (mutex)(&eventfs_mutex); ei = dentry->d_fsdata; -if (ei->is_freed) { -/* Do not allow changes if the event is about to be removed. */ -mutex_unlock (&eventfs_mutex); +/* Do not allow changes if the event is about to be removed. */ +if (ei->is_freed)return -ENODEV ; - }/* Preallocate the children mode array if necessary */ if (!(dentry->d_inode->i_mode &S_IFDIR )) {if (!ei->entry_attrs) { ei->entry_attrs =kzalloc_objs (*ei->entry_attrs, ei->nr_entries,GFP_NOFS ); -if (!ei->entry_attrs) { - ret = -ENOMEM ; - goto out; - } +if (!ei->entry_attrs) +return -ENOMEM ; } } ret =simple_setattr (idmap, dentry, iattr);if (ret <0 ) - goto out; +return ret;/* * If this is a dir, then update the ei cache, only the file
@@ -225,8 +221,6 @@ static int eventfs_set_attr(struct mnt_i } } } - out: -mutex_unlock (&eventfs_mutex);return ret; }
@@ -530,26 +524,24 @@ static struct dentry *eventfs_root_lookustruct tracefs_inode *ti;struct eventfs_inode *ei;const char *name = dentry->d_name.name; -struct dentry *result =NULL ; ti =get_tracefs (dir);if (WARN_ON_ONCE (!(ti->flags &TRACEFS_EVENT_INODE )))return ERR_PTR (-EIO ); -mutex_lock (&eventfs_mutex); +guard (mutex)(&eventfs_mutex); ei = ti->private;if (!ei || ei->is_freed) - goto out; +return NULL ;list_for_each_entry (ei_child, &ei->children, list) {if (strcmp (ei_child->name, name) !=0 )continue ;/* A child is freed and removed from the list at the same time */ if (WARN_ON_ONCE (ei_child->is_freed)) - goto out; - result =lookup_dir_entry (dentry, ei, ei_child); - goto out; +return NULL ; +return lookup_dir_entry (dentry, ei, ei_child); }for (int i =0 ; i < ei->nr_entries; i++) {
@@ -563,14 +555,12 @@ static struct dentry *eventfs_root_looku data = ei->data;if (entry->callback (name, &mode, &data, &fops) <=0 ) - goto out; +return NULL ; + +return lookup_file_dentry (dentry, ei, i, mode, data, fops); - result =lookup_file_dentry (dentry, ei, i, mode, data, fops); - goto out; } - out: -mutex_unlock (&eventfs_mutex); -return result; +return NULL ; }/*
@@ -586,7 +576,6 @@ static int eventfs_iterate(struct file *struct eventfs_inode *ei;const char *name;umode_t mode; -int idx;int ret = -EINVAL ;int ino;int i, r, c;
@@ -600,16 +589,13 @@ static int eventfs_iterate(struct file * c = ctx->pos -2 ; - idx =srcu_read_lock (&eventfs_srcu); +guard (srcu)(&eventfs_srcu); -mutex_lock (&eventfs_mutex); - ei =READ_ONCE (ti->private); -if (ei && ei->is_freed) - ei =NULL ; -mutex_unlock (&eventfs_mutex); - -if (!ei) - goto out; + scoped_guard(mutex, &eventfs_mutex) { + ei =READ_ONCE (ti->private); +if (!ei || ei->is_freed) +return -EINVAL ; + }/* * Need to create the dentries and inodes to have a consistent
@@ -624,21 +610,19 @@ static int eventfs_iterate(struct file * entry = &ei->entries[i]; name = entry->name; -mutex_lock (&eventfs_mutex);/* If ei->is_freed then just bail here, nothing more to do */ -if (ei->is_freed) { -mutex_unlock (&eventfs_mutex); - goto out; + scoped_guard(mutex, &eventfs_mutex) { +if (ei->is_freed) +return -EINVAL ; + r = entry->callback (name, &mode, &cdata, &fops); } - r = entry->callback (name, &mode, &cdata, &fops); -mutex_unlock (&eventfs_mutex);if (r <=0 )continue ; ino =EVENTFS_FILE_INODE_INO ;if (!dir_emit (ctx, name,strlen (name), ino,DT_REG )) - goto out; +return -EINVAL ; }/* Subtract the skipped entries above */
@@ -661,19 +645,13 @@ static int eventfs_iterate(struct file * ino =eventfs_dir_ino (ei_child); -if (!dir_emit (ctx, name,strlen (name), ino,DT_DIR )) - goto out_dec; +if (!dir_emit (ctx, name,strlen (name), ino,DT_DIR )) { +/* Incremented ctx->pos without adding something, reset it */ + ctx->pos--; +return -EINVAL ; + } } - ret =1 ; - out: -srcu_read_unlock (&eventfs_srcu, idx); - -return ret; - - out_dec: -/* Incremented ctx->pos without adding something, reset it */ - ctx->pos--; - goto out; +return 1 ; }/**
@@ -730,11 +708,10 @@ struct eventfs_inode *eventfs_create_dirINIT_LIST_HEAD (&ei->children);INIT_LIST_HEAD (&ei->list); -mutex_lock (&eventfs_mutex); -if (!parent->is_freed) -list_add_tail (&ei->list, &parent->children); -mutex_unlock (&eventfs_mutex); - + scoped_guard(mutex, &eventfs_mutex) { +if (!parent->is_freed) +list_add_tail (&ei->list, &parent->children); + }/* Was the parent freed? */ if (list_empty (&ei->list)) {cleanup_ei (ei);
@@ -880,9 +857,8 @@ void eventfs_remove_dir(struct eventfs_iif (!ei)return ; -mutex_lock (&eventfs_mutex); +guard (mutex)(&eventfs_mutex);eventfs_remove_rec (ei,0 ); -mutex_unlock (&eventfs_mutex); }/**
Greg Kroah-Hartman
maintainerPATCH 1143/1146 eventfs: Use list_add_tail_rcu() for SRCU-protected children list
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
[ Upstream commit f67950b2887fa10df50c4317a1fe98a65bc6875b ]
Commit d2603279c7d6 ("eventfs: Use list_del_rcu() for SRCU protected list variable") converted the removal side to pair with the list_for_each_entry_srcu() walker in eventfs_iterate(). The insertion in eventfs_create_dir() was left as a plain list_add_tail(), which on weakly-ordered architectures can expose a new entry to the SRCU reader before its list pointers and fields are observable.
Use list_add_tail_rcu() so the publication pairs with the existing list_del_rcu() and list_for_each_entry_srcu().
--- fs/tracefs/event_inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/tracefs/event_inode.c +1 -1
@@ -710,7 +710,7 @@ struct eventfs_inode *eventfs_create_dir scoped_guard(mutex, &eventfs_mutex) {if (!parent->is_freed) -list_add_tail (&ei->list, &parent->children); +list_add_tail_rcu (&ei->list, &parent->children); }/* Was the parent freed? */ if (list_empty (&ei->list)) {