7.2.7-rc1 review
Subsystems (5)
Greg Kroah-Hartman
maintainerPATCH 361/733 net: macb: reject an unknown link speed in the taprio setup
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksei Sviridkin <[email protected]>
[ Upstream commit 2b6c0e25a3d713c4032e45f212bdd9e14c50f8a0 ]
speed is a u32, so SPEED_UNKNOWN arrives as 0xffffffff and passes the "speed <= 0" check, which only ever catches zero. That is what an autonegotiating link reports while it is down: the limit derived from the speed collapses to a nanosecond at most and the first entry fails with a misleading "exceeds hardware limit". Zero stays covered, it is what an interface that was never opened reports, and enst_max_hw_interval() divides by it. Say which case it was in the error.
--- drivers/net/ethernet/cadence/macb_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/cadence/macb_main.c +2 -2
@@ -4360,8 +4360,8 @@ static int macb_taprio_setup_replace(struct net_device *netdev, } speed = kset.base.speed; -if (unlikely (speed <=0 )) { -netdev_err (netdev,"Invalid speed: %d\n" , speed); +if (unlikely (speed ==SPEED_UNKNOWN || !speed)) { +netdev_err (netdev,"Invalid speed %d, link-down?\n" , speed);return -EINVAL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 362/733 net: ethernet: cortina: Fix budget accounting
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit a0de06d0da78a3db53de65dfd7452cc6d111f703 ]
The gmac_rx() function returns the remaining NAPI budget, but its caller treats the return value as the number of packets received. An idle poll therefore reports a full budget and remains scheduled.
Return the number of received packets instead. Preserve the existing free queue refill accounting by adding that count directly; continuing to subtract it from the budget would invert the refill behavior.
--- drivers/net/ethernet/cortina/gemini.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/net/ethernet/cortina/gemini.c +5 -3
@@ -1450,6 +1450,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)unsigned int frame_len, frag_len;struct gmac_rxdesc *rx =NULL ;struct gmac_queue_page *gpage; +unsigned int received =0 ;union gmac_rxdesc_0 word0;union gmac_rxdesc_1 word1;union gmac_rxdesc_3 word3;
@@ -1545,7 +1546,8 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)napi_gro_frags (&port->napi); skb =NULL ; frag_nr =0 ; - --budget; + budget--; + received++; }continue ;
@@ -1565,7 +1567,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) port->rx_skb = skb; port->rx_frag_nr = frag_nr;writew (r, ptr_reg); -return budget; +return received; }static int gmac_napi_poll (struct napi_struct *napi,int budget)
@@ -1586,7 +1588,7 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget) ++port->rx_napi_exits; } - port->freeq_refill += (budget - received); + port->freeq_refill += received;if (port->freeq_refill > freeq_threshold) { port->freeq_refill -= freeq_threshold;geth_fill_freeq (geth, true);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 363/733 net: ethernet: cortina: Finish RX updates before NAPI completion
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit baa26841cb9a2cdc7e0e99d6854a4e3359bf7393 ]
napi_complete_done() releases ownership of the NAPI instance, but the Gemini poll keeps the RX statistics writer section open and updates the free queue after calling it. A new poll can therefore start while the old writer is still active.
Finish the statistics and free queue updates before releasing ownership. Only re-enable RX interrupts when napi_complete_done() reports successful completion.
--- drivers/net/ethernet/cortina/gemini.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/net/ethernet/cortina/gemini.c +6 -6
@@ -1581,12 +1581,10 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)u64_stats_update_begin (&port->rx_stats_syncp); received =gmac_rx (napi->dev, budget); -if (received < budget) { -napi_gro_flush (napi, false); -napi_complete_done (napi, received); -gmac_enable_rx_irq (napi->dev,1 ); +if (received < budget) ++port->rx_napi_exits; - } + +u64_stats_update_end (&port->rx_stats_syncp); port->freeq_refill += received;if (port->freeq_refill > freeq_threshold) {
@@ -1594,7 +1592,9 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)geth_fill_freeq (geth, true); } -u64_stats_update_end (&port->rx_stats_syncp); +if (received < budget &&napi_complete_done (napi, received)) +gmac_enable_rx_irq (napi->dev,1 ); +return received; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 364/733 net: ethernet: cortina: Count dropped frames as NAPI work
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit b856c552f556bc0341c1dbe0bf88e630fd1dc4b7 ]
The RX loop only consumes budget when it successfully delivers a frame. Error paths keep consuming descriptors without reducing the budget, so a stream of bad frames can process the entire receive ring in one poll.
Move the budget accounting to a common end-of-frame path. This counts each completed frame as NAPI work whether it was delivered or dropped, matching the behavior of the vendor driver.
--- drivers/net/ethernet/cortina/gemini.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/net/ethernet/cortina/gemini.c +10 -5
@@ -1501,7 +1501,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) skb =NULL ; frag_nr =0 ; } -continue ; + goto next_desc; } page = gpage->page;
@@ -1523,7 +1523,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) }else if (!skb) {put_page (page); -continue ; + goto next_desc; }if (word3.bits32 &EOF_BIT )
@@ -1546,10 +1546,8 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)napi_gro_frags (&port->napi); skb =NULL ; frag_nr =0 ; - budget--; - received++; } -continue ; + goto next_desc; err_drop:if (skb) {
@@ -1562,6 +1560,13 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)put_page (page); port->stats.rx_dropped++; + +next_desc: +/* Final or single-descriptor fragment, advance things */ +if (word3.bits32 &EOF_BIT ) { + budget--; + received++; + } } port->rx_skb = skb;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 365/733 net: ethernet: cortina: Count RX drops once per frame
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit 6520198c430c81bcc367f0dd5e32f2fb740b9d51 ]
The absence of a partial skb means either that the driver is not assembling a frame or that the current frame was already dropped. Consequently, repeated descriptor errors can increment rx_dropped more than once, while an orphaned descriptor chain can reach EOF without being counted at all.
Track the dropping state across NAPI polls. Clear it at frame boundaries and route mapping failures and orphaned continuations through the common drop path so each discarded frame is counted exactly once.
--- drivers/net/ethernet/cortina/gemini.c | 41 +++++++++++++++------------ 1 file changed, 23 insertions(+), 18 deletions(-)
drivers/net/ethernet/cortina/gemini.c +23 -18
@@ -124,6 +124,7 @@ struct gemini_ethernet_port {unsigned int rx_coalesce_nsecs;struct sk_buff *rx_skb;unsigned int rx_frag_nr; +bool rx_dropping;unsigned int freeq_refill;struct gmac_txq txq[TX_QUEUE_NUM ];
@@ -1451,6 +1452,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)struct gmac_rxdesc *rx =NULL ;struct gmac_queue_page *gpage;unsigned int received =0 ; +bool dropping = port->rx_dropping;union gmac_rxdesc_0 word0;union gmac_rxdesc_1 word1;union gmac_rxdesc_3 word3;
@@ -1472,6 +1474,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) w = rw.bits.wptr;while (budget && w != r) { + page =NULL ; rx = port->rxq_ring + r; word0 = rx->word0; word1 = rx->word1;
@@ -1485,6 +1488,16 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) frame_len = word1.bits.byte_count; page_offs = mapping & ~PAGE_MASK ; +if (word3.bits32 &SOF_BIT ) { +if (skb) { +napi_free_frags (&port->napi); + port->stats.rx_dropped++; + skb =NULL ; + frag_nr =0 ; + } + dropping = false; + } +if (!mapping) {netdev_err (netdev,"rxq[%u]: HW BUG: zero DMA desc\n" , r);
@@ -1495,24 +1508,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) gpage =gmac_get_queue_page (geth, port, mapping +PAGE_SIZE );if (!gpage) {dev_err (geth->dev,"could not find mapping\n" ); - port->stats.rx_dropped++; -if (skb) { -napi_free_frags (&port->napi); - skb =NULL ; - frag_nr =0 ; - } - goto next_desc; + goto err_drop; } page = gpage->page;if (word3.bits32 &SOF_BIT ) { -if (skb) { -napi_free_frags (&port->napi); - port->stats.rx_dropped++; - skb =NULL ; - frag_nr =0 ; - } - skb =gmac_skb_if_good_frame (port, word0, frame_len);if (!skb) goto err_drop;
@@ -1522,8 +1522,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) frag_nr =0 ; }else if (!skb) { -put_page (page); - goto next_desc; + goto err_drop; }if (word3.bits32 &EOF_BIT )
@@ -1556,21 +1555,26 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) frag_nr =0 ; } -if (mapping) +if (page)put_page (page); - port->stats.rx_dropped++; +if (!dropping) { + port->stats.rx_dropped++; + dropping = true; + } next_desc:/* Final or single-descriptor fragment, advance things */ if (word3.bits32 &EOF_BIT ) { budget--; received++; + dropping = false; } } port->rx_skb = skb; port->rx_frag_nr = frag_nr; + port->rx_dropping = dropping;writew (r, ptr_reg);return received; }
@@ -1900,6 +1904,7 @@ static int gmac_stop(struct net_device *netdev)napi_disable (&port->napi); port->rx_skb =NULL ; port->rx_frag_nr =0 ; + port->rx_dropping = false;gmac_enable_irq (netdev,0 );gmac_cleanup_rxq (netdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 366/733 net: ethernet: cortina: Count RX descriptors for freeq refill
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit e89e88ad41d9f31c829c2af39c48313e8e48d5b0 ]
The software free queue provides one buffer fragment for every descriptor moved to an RX queue. The refill heuristic instead advances by NAPI work, which counts frames. A fragmented or discarded frame can consume several queue entries while adding only one to the refill count.
Count the RX descriptors as they are consumed and report that separately from NAPI work. Use the descriptor count to drive free queue refills.
--- drivers/net/ethernet/cortina/gemini.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/ethernet/cortina/gemini.c +8 -3
@@ -1440,7 +1440,8 @@ static struct sk_buff *gmac_skb_if_good_frame(struct gemini_ethernet_port *port,return skb; } -static unsigned int gmac_rx (struct net_device *netdev,unsigned int budget) +static unsigned int gmac_rx (struct net_device *netdev,unsigned int budget, +unsigned int *freeq_consumed) {struct gemini_ethernet_port *port =netdev_priv (netdev);unsigned short m = (1 << port->rxq_order) -1 ;
@@ -1448,6 +1449,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)void __iomem *ptr_reg = port->rxq_rwptr;unsigned int frag_nr = port->rx_frag_nr;struct sk_buff *skb = port->rx_skb; +unsigned int consumed =0 ;unsigned int frame_len, frag_len;struct gmac_rxdesc *rx =NULL ;struct gmac_queue_page *gpage;
@@ -1483,6 +1485,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) r++; r &= m; + consumed++; frag_len = word0.bits.buffer_size; frame_len = word1.bits.byte_count;
@@ -1575,6 +1578,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) port->rx_skb = skb; port->rx_frag_nr = frag_nr; port->rx_dropping = dropping; + *freeq_consumed = consumed;writew (r, ptr_reg);return received; }
@@ -1584,18 +1588,19 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)struct gemini_ethernet_port *port =netdev_priv (napi->dev);struct gemini_ethernet *geth = port->geth;unsigned int freeq_threshold; +unsigned int freeq_consumed;unsigned int received; freeq_threshold =1 << (geth->freeq_order -1 );u64_stats_update_begin (&port->rx_stats_syncp); - received =gmac_rx (napi->dev, budget); + received =gmac_rx (napi->dev, budget, &freeq_consumed);if (received < budget) ++port->rx_napi_exits;u64_stats_update_end (&port->rx_stats_syncp); - port->freeq_refill += received; + port->freeq_refill += freeq_consumed;if (port->freeq_refill > freeq_threshold) { port->freeq_refill -= freeq_threshold;geth_fill_freeq (geth, true);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 367/733 drm/adp: Drop the select of the nonexistent CONFIG_DRM_KMS_DMA_HELPER
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit fedf002d7d08bee36693aacd1ade2ba39351ea91 ]
There is no Kconfig symbol CONFIG_DRM_KMS_DMA_HELPER. The former CONFIG_DRM_KMS_CMA_HELPER was removed by commit 09717af7d13d ("drm:
Remove CONFIG_DRM_KMS_CMA_HELPER option") before this driver was added, so the select does nothing. The driver already selects CONFIG_DRM_GEM_DMA_HELPER, which is what it needs.
Remove the dead line.
--- drivers/gpu/drm/adp/Kconfig | 1 - 1 file changed, 1 deletion(-)
drivers/gpu/drm/adp/Kconfig +0 -1
@@ -6,7 +6,6 @@ config DRM_ADP select DRM_KMS_HELPER select DRM_BRIDGE_CONNECTOR select DRM_DISPLAY_HELPER - select DRM_KMS_DMA_HELPER select DRM_GEM_DMA_HELPER select DRM_PANEL_BRIDGE select VIDEOMODE_HELPERS
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 368/733 drm/logicvc: Drop the select of the nonexistent CONFIG_DRM_KMS_DMA_HELPER
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit f97802dd98b27e45c04293f9926f07642578b23f ]
CONFIG_DRM_KMS_CMA_HELPER was removed by commit 09717af7d13d ("drm:
Remove CONFIG_DRM_KMS_CMA_HELPER option"). When commit 6bcfe8eaeef0 ("drm/fb: rename FB CMA helpers to FB DMA helpers") later renamed the select in this Kconfig to CONFIG_DRM_KMS_DMA_HELPER, no symbol of that name existed, and git log -S finds no Kconfig file that has defined one since. The select is silently ignored. The driver already selects CONFIG_DRM_GEM_DMA_HELPER, which is what it needs.
Remove the dead line.
--- drivers/gpu/drm/logicvc/Kconfig | 1 - 1 file changed, 1 deletion(-)
drivers/gpu/drm/logicvc/Kconfig +0 -1
@@ -4,7 +4,6 @@ config DRM_LOGICVC depends on OF || COMPILE_TEST select DRM_CLIENT_SELECTION select DRM_KMS_HELPER - select DRM_KMS_DMA_HELPER select DRM_GEM_DMA_HELPER select REGMAP select REGMAP_MMIO
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 369/733 s390/debug: Fix NULL pointer dereference in debug_set_level()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Zaslonko <[email protected]>
[ Upstream commit b1eb31d533cdfcae1011ed53850d52f36afe5774 ]
Commit a2cec6863709 ("s390/debug: Add s390dbf kernel parameter") incorrectly removed a null-id check from debug_set_level(), introducing a possible NULL pointer dereference for debug-API users that put debug_register() results unchecked into debug_set_level().
Fix this by moving the check from the internal _debug_set_level() variant back to the external debug_set_level() wrapper.
--- arch/s390/kernel/debug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/s390/kernel/debug.c +3 -3
@@ -1074,9 +1074,6 @@ static void _debug_set_level(debug_info_t *id, int new_level) {unsigned long flags; -if (!id) -return ; -if (new_level ==DEBUG_OFF_LEVEL ) {pr_info ("%s: switched off\n" , id->name); }else if ((new_level >DEBUG_MAX_LEVEL ) || (new_level <0 )) {
@@ -1101,6 +1098,9 @@ static void _debug_set_level(debug_info_t *id, int new_level)*/ void debug_set_level (debug_info_t *id,int new_level) { +if (!id) +return ; +/* Level specified via kernel parameter takes precedence */ debug_get_param (id->name, &new_level,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 370/733 ALSA: hda: Report a change when only the channel status bytes move
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 7284788743121ec8bed556b00f830dc52ad9955d ]
The put() callback of "IEC958 Playback Default" returns whether the converted register value moved. The convert_from_spdif_status() helper reads part of the first two channel status bytes and none of the last two, while the get() callback returns all four. So a write that lands only in the bits it does not read changes what userspace reads back and reports no change. Of the 31 bits above the mode bit, 20 are such bits in consumer mode and 29 in professional mode. The core notifies only on a positive return.
Toggling status[2] bit 0 on an HDA HDMI codec moves the read-back from 04 00 00 00 to 04 00 01 00 with no event. Toggling the non-audio bit in status[0] gives one.
Compare the stored status as well, the way the ac97 code does. The write to the codec stays gated on the converted value.
--- sound/hda/common/codec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/hda/common/codec.c +3 -1
@@ -2271,6 +2271,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,int idx = kcontrol->private_value;struct hda_spdif_out *spdif;hda_nid_t nid; +unsigned int old_status;unsigned short val;int change;
@@ -2279,6 +2280,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,guard (mutex)(&codec->spdif_mutex); spdif =snd_array_elem (&codec->spdif_out, idx); nid = spdif->nid; + old_status = spdif->status; spdif->status = ucontrol->value.iec958.status[0 ] | ((unsigned int )ucontrol->value.iec958.status[1 ] <<8 ) | ((unsigned int)ucontrol->value.iec958.status[2] << 16) |
@@ -2289,7 +2291,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, spdif->ctls = val;if (change && nid != (u16)-1 )set_dig_out_convert (codec, nid, val &0xff , (val >>8 ) &0xff ); -return change; +return change || spdif->status != old_status; }#define snd_hda_spdif_out_switch_info snd_ctl_boolean_mono_info
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 371/733 platform/x86: x86-android-tablets: fix gpio_secondary_fwnode_init() not working
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hans de Goede <[email protected]>
[ Upstream commit dd519eb8f66eaa205bbbdcb753588138a1d18414 ]
acpi_bus_find_device_by_name() call returns a pointer to the device object on the ACPI bus, aka the ACPI companion device.
gpio_secondary_fwnode_init() then continues with setting the secondary fwnode on this device. But this is not the actual physical device for the GPIO controller (e.g. the GPIO controller platform bus device).
This mismatch is causing GPIO lookups by secondary fwnode to not work.
Modify gpio_secondary_fwnode_init() to instead set the secondary fwnode of the first physical device associated with the ACPI companion device.
This fixes the GPIO lookups not working.
--- drivers/platform/x86/x86-android-tablets/core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/platform/x86/x86-android-tablets/core.c +9 -2
@@ -381,6 +381,7 @@ static int gpio_secondary_fwnode_init(struct device *parent) {const struct software_node *const *swnode;struct fwnode_handle *fwnode; +struct device *phys_dev;int ret;if (!gpiochip_node_group)
@@ -408,9 +409,15 @@ static int gpio_secondary_fwnode_init(struct device *parent)if (WARN_ON (!fwnode))return -ENOENT ; -set_secondary_fwnode (dev, fwnode); + phys_dev =acpi_get_first_physical_node (to_acpi_device (dev)); +if (!phys_dev) +return dev_err_probe (parent, -ENODEV , +"No physical device for ACPI GPIO dev: %pfwP\n" , + fwnode); - ret =devm_add_action_or_reset (parent, gpio_secondary_unset,get_device (dev)); +set_secondary_fwnode (phys_dev, fwnode); + + ret =devm_add_action_or_reset (parent, gpio_secondary_unset,get_device (phys_dev));if (ret)return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 372/733 idpf: account for VLAN header when parsing RSC packet header
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Hay <[email protected]>
[ Upstream commit cc6d60ef92278a31ffc2e94966a0921b9646af18 ]
While parsing the header of a Receive Side Coalesced (RSC) packet, check if a VLAN tag is present and adjust the header parsing accordingly. Otherwise, Rx TCP traffic is completely broken for any VLAN interface whose underlying interface has RSC (rx-gro-hw) enabled.
We only need to worry about one VLAN header since Rx packets with multiple VLAN headers are not candidates for RSC.
--- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/net/ethernet/intel/idpf/idpf_txrx.c +7 -3
@@ -3299,6 +3299,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb, struct libeth_rx_pt decoded) {u16 rsc_segments, rsc_seg_len; +u16 l3_start =0 ;bool ipv4, ipv6;int len;
@@ -3321,7 +3322,10 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,NAPI_GRO_CB (skb)->count = rsc_segments;skb_shinfo (skb)->gso_size = rsc_seg_len; -skb_reset_network_header (skb); +if (unlikely (eth_type_vlan (skb->protocol))) + l3_start =VLAN_HLEN ; + +skb_set_network_header (skb, l3_start);if (ipv4) {struct iphdr *ipv4h =ip_hdr (skb);
@@ -3329,7 +3333,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,skb_shinfo (skb)->gso_type =SKB_GSO_TCPV4 ;/* Reset and set transport header offset in skb */ -skb_set_transport_header (skb,sizeof (struct iphdr )); +skb_set_transport_header (skb, l3_start +sizeof (struct iphdr )); len = skb->len -skb_transport_offset (skb);/* Compute the TCP pseudo header checksum*/
@@ -3339,7 +3343,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,struct ipv6hdr *ipv6h =ipv6_hdr (skb);skb_shinfo (skb)->gso_type =SKB_GSO_TCPV6 ; -skb_set_transport_header (skb,sizeof (struct ipv6hdr )); +skb_set_transport_header (skb, l3_start +sizeof (struct ipv6hdr )); len = skb->len -skb_transport_offset (skb);tcp_hdr (skb)->check = ~tcp_v6_check (len, &ipv6h->saddr, &ipv6h->daddr,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 373/733 ice: add missing xa_destroy for sched_node_ids
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacob Keller <[email protected]>
[ Upstream commit 53432c4c3e869076350aef319534431af8ba99c1 ]
Commit 16dfa49406bc ("ice: Introduce new parameters in ice_sched_node") added a sched_node_ids xarray to the port info structure, but never called xa_destroy on it.
Since xarrays can allocate internal memory, this can result in a memory leak even if every element in the xarray has been removed.
The xarray is currently embedded in the port_info structure. This appears to have been done because its use is within functions that take the port_info as a primary argument.
However, this complicates managing the lifecycle of the field. The port_info structure is allocated in ice_init_hw() using devm, and it is not released until the devm cleanup when the driver is unloaded.
The ice_init_hw() function is called in many places, including devlink reload, and possibly during DDP load after updating the Tx scheduler layout.
Adding a call of xa_destroy to the ice_deinit_hw() causes Sashiko to raise multiple concerns due to potential ordering issues and possible ways that port_info could be a dangling reference.
To handle this, move the sched_node_ids out of port_info and into the hw structure. All users of the array already have a pointer to hw anyways, and there is only one sched_node_ids per adapter. While here, remove the overly verbose comment explaining the nature of the sched_node_ids xarray.
Add the missing xa_destroy to the cleanup path and to ice_deinit_hw(), ensuring that we properly release the xarray memory.
This was caught by Sashiko during development of unrelated code.
--- drivers/net/ethernet/intel/ice/ice_common.c | 9 ++++++--- drivers/net/ethernet/intel/ice/ice_sched.c | 4 ++-- drivers/net/ethernet/intel/ice/ice_type.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-)
drivers/net/ethernet/intel/ice/ice_common.c +6 -3
@@ -1051,14 +1051,13 @@ int ice_init_hw(struct ice_hw *hw) hw->evb_veb = true; -/* init xarray for identifying scheduling nodes uniquely */ -xa_init_flags (&hw->port_info->sched_node_ids,XA_FLAGS_ALLOC ); +xa_init_flags (&hw->sched_node_ids,XA_FLAGS_ALLOC );/* Query the allocated resources for Tx scheduler */ status =ice_sched_query_res_alloc (hw);if (status) {ice_debug (hw,ICE_DBG_SCHED ,"Failed to get scheduler allocated resources\n" ); - goto err_unroll_alloc; + goto err_unroll_xarray; }ice_sched_get_psm_clk_freq (hw);
@@ -1146,6 +1145,8 @@ int ice_init_hw(struct ice_hw *hw)ice_cleanup_fltr_mgmt_struct (hw); err_unroll_sched:ice_sched_cleanup_all (hw); +err_unroll_xarray: +xa_destroy (&hw->sched_node_ids); err_unroll_alloc:devm_kfree (ice_hw_to_dev (hw), hw->port_info); err_unroll_cqinit:
@@ -1186,6 +1187,8 @@ void ice_deinit_hw(struct ice_hw *hw)/* Clear VSI contexts if not already cleared */ ice_clear_all_vsi_ctx (hw); + +xa_destroy (&hw->sched_node_ids); }/**
drivers/net/ethernet/intel/ice/ice_sched.c +2 -2
@@ -371,7 +371,7 @@ void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)devm_kfree (ice_hw_to_dev (hw), node->children);kfree (node->name); -xa_erase (&pi->sched_node_ids, node->id); +xa_erase (&hw->sched_node_ids, node->id);devm_kfree (ice_hw_to_dev (hw), node); }
@@ -977,7 +977,7 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,if (!new_node->name)return -ENOMEM ; - status =xa_alloc (&pi->sched_node_ids, &new_node->id,NULL ,XA_LIMIT (0 ,UINT_MAX ), + status =xa_alloc (&hw->sched_node_ids, &new_node->id,NULL ,XA_LIMIT (0 ,UINT_MAX ),GFP_KERNEL );if (status) { ice_debug(hw, ICE_DBG_SCHED, "xa_alloc failed for sched node status =%d\n",
drivers/net/ethernet/intel/ice/ice_type.h +1 -1
@@ -765,7 +765,6 @@ struct ice_port_info {/* List contain profile ID(s) and other params per layer */ struct list_head rl_prof_list[ICE_AQC_TOPO_MAX_LEVEL_NUM ];struct ice_qos_cfg qos_cfg; -struct xarray sched_node_ids; u8 is_vf:1; u8 is_custom_tx_enabled:1; };
@@ -930,6 +929,7 @@ struct ice_hw {u8 sw_entry_point_layer;u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM ];struct list_head agg_list;/* lists all aggregator */ +struct xarray sched_node_ids;struct ice_vsi_ctx *vsi_ctx[ICE_MAX_VSI ];u8 evb_veb;/* true for VEB, false for VEPA */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 374/733 eth: ice: dont dereference pointers from TP_printk()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit b8bf9bfda5f62e11444e483c2b4aaff90c5cfc6b ]
After forwarding net-next during the v7.3 merge window we started seeing:
TRACE EVENT ERROR: Event ice_tx_dim_work has double dereference in TP_printk: REC->q_vector->tx.tx_ring->q_index
WARNING: kernel/trace/trace_events.c:420 at test_double_dereference.cold+0x39/0x4b
this is due to extra checks added in tracing subsystem in
commit b5cc230af5e5 ("tracing: Warn when an event dereferences a pointer in TP_printk()").
Printing happens long after the event was recorded, by which point the pointers may be invalid (the ring or the dim instance). Copy the eight scalars into the event instead.
--- drivers/net/ethernet/intel/ice/ice_trace.h | 64 ++++++++++++++-------- 1 file changed, 42 insertions(+), 22 deletions(-)
drivers/net/ethernet/intel/ice/ice_trace.h +42 -22
@@ -63,23 +63,33 @@DECLARE_EVENT_CLASS (ice_rx_dim_template, TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),TP_ARGS (q_vector, dim), - TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector) - __field(struct dim *, dim) + TP_STRUCT__entry(__field(u16, q_index) + __field(u8, state) + __field(u8, profile_ix) + __field(u8, tune_state) + __field(u8, steps_right) + __field(u8, steps_left) + __field(u8, tired)__string (devname, q_vector->rx.rx_ring->netdev->name)), - TP_fast_assign(__entry->q_vector = q_vector; - __entry->dim = dim; + TP_fast_assign(__entry->q_index = q_vector->rx.rx_ring->q_index; + __entry->state = dim->state; + __entry->profile_ix = dim->profile_ix; + __entry->tune_state = dim->tune_state; + __entry->steps_right = dim->steps_right; + __entry->steps_left = dim->steps_left; + __entry->tired = dim->tired; __assign_str(devname);),TP_printk ("netdev: %s Rx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d" ,__get_str (devname), - __entry->q_vector->rx.rx_ring->q_index, - __entry->dim->state, - __entry->dim->profile_ix, - __entry->dim->tune_state, - __entry->dim->steps_right, - __entry->dim->steps_left, - __entry->dim->tired) + __entry->q_index, + __entry->state, + __entry->profile_ix, + __entry->tune_state, + __entry->steps_right, + __entry->steps_left, + __entry->tired) ); DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,
@@ -90,23 +100,33 @@ DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,DECLARE_EVENT_CLASS (ice_tx_dim_template, TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),TP_ARGS (q_vector, dim), - TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector) - __field(struct dim *, dim) + TP_STRUCT__entry(__field(u16, q_index) + __field(u8, state) + __field(u8, profile_ix) + __field(u8, tune_state) + __field(u8, steps_right) + __field(u8, steps_left) + __field(u8, tired)__string (devname, q_vector->tx.tx_ring->netdev->name)), - TP_fast_assign(__entry->q_vector = q_vector; - __entry->dim = dim; + TP_fast_assign(__entry->q_index = q_vector->tx.tx_ring->q_index; + __entry->state = dim->state; + __entry->profile_ix = dim->profile_ix; + __entry->tune_state = dim->tune_state; + __entry->steps_right = dim->steps_right; + __entry->steps_left = dim->steps_left; + __entry->tired = dim->tired; __assign_str(devname);),TP_printk ("netdev: %s Tx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d" ,__get_str (devname), - __entry->q_vector->tx.tx_ring->q_index, - __entry->dim->state, - __entry->dim->profile_ix, - __entry->dim->tune_state, - __entry->dim->steps_right, - __entry->dim->steps_left, - __entry->dim->tired) + __entry->q_index, + __entry->state, + __entry->profile_ix, + __entry->tune_state, + __entry->steps_right, + __entry->steps_left, + __entry->tired) ); DEFINE_EVENT(ice_tx_dim_template, ice_tx_dim_work,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 375/733 Bluetooth: Properly disable remote wakeup for MT7922/MT7925 on Ryzen platform
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rong Zhang <[email protected]>
[ Upstream commit dcaf83ead130d3067862599089b0999b3da140a4 ]
It is reported that a remote wakeup could cause MT7922/MT7925's btusb interface completely unresponsive. Resetting the xHCI root hub doesn't help at all, and recovering from such a state needs a power cycle.
All reports seen to be relevant to Ryzen-based laptops. These NICs are usually used as OEM components thanks to some sort of reference designs. Their popularity on other platforms is unclear. While there is still a chance that the quirk may exist on other platforms, be cautious and only apply the quirk to direct children of Ryzen platforms's root hubs for the time being. In most cases the root hub is on the SoC or PCH, which needs the quirk. Unfortunately, this can't distinguish root hubs on PCIe add-in cards. Such roughness should be acceptable, as PCIe USB controller add-in cards are less commonly used nowadays. On the other hand, applying the quirk doesn't hurt any functionalities either, as the device can still be used as a wakeup source if desired. Theoretically, we could retrieve the root hub's PCI vendor ID with some hierarchy magic, but that's too intrusive...
Meanwhile, though device_set_wakeup_capable(false) is the correct fix for other NICs with fake remote wakeup capabilities, doing so for MT7922/MT7925 effectively prevents it from being used as wakeup sources as per userspace requests. Hence, return -EBUSY on runtime suspend to prevent the interface from being autosuspended while it's still opened, which has the same effect as device_set_wakeup_capable(false), since disabling remote wakeup simply causes the USB core to gate runtime autosuspend as well due to needs_remote_wakeup == 1. The interface can be safely autosuspended as long as remote wakeup is disabled, i.e., after closing the HCI device.
Specifically, the interface may still take the advantage of remote wakeup in order to wake up the system from sleep if userspace has enabled it as a wakeup source.
--- drivers/bluetooth/btmtk.c | 10 ------ drivers/bluetooth/btusb.c | 73 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 14 deletions(-)
drivers/bluetooth/btmtk.c +0 -10
@@ -1374,16 +1374,6 @@ int btmtk_usb_setup(struct hci_dev *hdev)break ;case 0x7922 :case 0x7925 : -/* -* A remote wakeup could cause the device completely unresponsive, and -* recovering from such a state needs a power cycle. -* -* Since the remote wakeup capability is super broken, just disable it -* to get rid of the troubles. The device can still be autosuspended -* when the bluetooth interface is closed. -*/ -device_set_wakeup_capable (&btmtk_data->udev->dev, false); - fallthrough;case 0x7961 :case 0x7902 :case 0x6639 :
drivers/bluetooth/btusb.c +69 -4
109 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 376/733 Bluetooth: btusb: Fix UAF of btusb_data by rx_work
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Augusto von Dentz <[email protected]>
[ Upstream commit 1c12c3117639e78940959d956519c758c57d0849 ]
btusb_close() and btusb_flush() cancel data->rx_work with the asynchronous cancel_delayed_work(), so if btusb_rx_work() is already running on another CPU it keeps running after the cancel returns.
btusb_disconnect() calls hci_unregister_dev(), which invokes btusb_close(), and then frees the btusb_data. A still running btusb_rx_work() then dereferences the freed data:
while ((skb = skb_dequeue(&data->acl_q))) data->recv_acl(data->hdev, skb);
Use cancel_delayed_work_sync() instead. In btusb_close() the cancel also has to happen after btusb_stop_traffic(), otherwise an URB completion racing with the cancel can requeue the work right after it has been waited for.
--- drivers/bluetooth/btusb.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/bluetooth/btusb.c +10 -4
@@ -2074,18 +2074,24 @@ static int btusb_close(struct hci_dev *hdev)BT_DBG ("%s" , hdev->name); -cancel_delayed_work (&data->rx_work);cancel_work_sync (&data->work);cancel_work_sync (&data->waker); -skb_queue_purge (&data->acl_q); -clear_bit (BTUSB_ISOC_RUNNING , &data->flags);clear_bit (BTUSB_BULK_RUNNING , &data->flags);clear_bit (BTUSB_INTR_RUNNING , &data->flags);clear_bit (BTUSB_DIAG_RUNNING , &data->flags);btusb_stop_traffic (data); + +/* rx_work must only be canceled once the URBs that can rearm it are +* gone, and it must be canceled synchronously since btusb_disconnect() +* frees the btusb_data it dereferences right after hci_unregister_dev(). +*/ +cancel_delayed_work_sync (&data->rx_work); + +skb_queue_purge (&data->acl_q); +btusb_free_frags (data); err =usb_autopm_get_interface (data->intf);
@@ -2111,7 +2117,7 @@ static int btusb_flush(struct hci_dev *hdev)BT_DBG ("%s" , hdev->name); -cancel_delayed_work (&data->rx_work); +cancel_delayed_work_sync (&data->rx_work);skb_queue_purge (&data->acl_q);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 377/733 Bluetooth: btintel_pcie: validate packet_len before skb_put_data
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiran K <[email protected]>
[ Upstream commit 6436e1b5331b1aebf905c13e0880a37032719b75 ]
btintel_pcie_submit_rx_work() reads packet_len from rfh_hdr without checking if it exceeds the RX buffer size. An oversized packet_len can lead to an out-of-bounds read in skb_put_data().
Validate packet_len to ensure it is non-zero and does not exceed BTINTEL_PCIE_BUFFER_SIZE - sizeof(*rfh_hdr), logging an error when invalid.
This issue was reported by Claude Mythos. It can be simulated either by using customized firmware configured to return an invalid packet_len or by modifying rfh_hdr->packet_len in the driver before calling btintel_pcie_submit_rx_work().
--- drivers/bluetooth/btintel_pcie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/bluetooth/btintel_pcie.c +3 -1
@@ -1537,7 +1537,9 @@ static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status rfh_hdr = buf; len = rfh_hdr->packet_len; -if (len <=0 ) { +if (len ==0 || len >BTINTEL_PCIE_BUFFER_SIZE -sizeof (*rfh_hdr)) { +bt_dev_err (data->hdev,"Invalid packet_len %d (max %zu)" , len, +BTINTEL_PCIE_BUFFER_SIZE -sizeof (*rfh_hdr)); ret = -EINVAL ; goto resubmit; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 378/733 Bluetooth: btintel_pcie: fix tx_handle bounds off-by-one
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiran K <[email protected]>
[ Upstream commit 3dd1b41f96aad08444be1b7626c89de2b9f2abd4 ]
Valid indices into txq->urbd0s/tfds/bufs are 0..txq->count-1, so tfd_index == txq->count is already out of range. Change the guard in btintel_pcie_msix_tx_handle() from '> txq->count' to '>= txq->count'.
This issue was reported by Claude Mythos.
--- drivers/bluetooth/btintel_pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bluetooth/btintel_pcie.c +1 -1
@@ -1099,7 +1099,7 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data) urbd0 = &txq->urbd0s[cr_tia]; -if (urbd0->tfd_index > txq->count) +if (urbd0->tfd_index >= txq->count)return ; cr_tia = (cr_tia +1 ) % txq->count;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 379/733 Bluetooth: btmtk: Declare MT7920 (MT7961 1a) Bluetooth firmware
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Hu <[email protected]>
[ Upstream commit 3d8a8e81ea8ad8813d4c82a12ba53ecb597b217d ]
btmtk_fw_get_filename() constructs the firmware name at runtime, so for the MT7920 variant (dev_id 0x7961 with fw_flavor set) it requests "mediatek/BT_RAM_CODE_MT7961_1a_2_hdr.bin" without ever declaring it via MODULE_FIRMWARE(). Tools that select firmware from module metadata (e.g. "modinfo -F firmware") therefore omit this blob, so request_firmware() fails and Bluetooth does not initialise on MT7920, even though the file is present in linux-firmware.
Declare it with MODULE_FIRMWARE(), as the mt76 driver already does for the corresponding MT7920 wifi firmware.
--- drivers/bluetooth/btmtk.c | 1 + drivers/bluetooth/btmtk.h | 1 + 2 files changed, 2 insertions(+)
drivers/bluetooth/btmtk.c +1 -0
@@ -1577,5 +1577,6 @@ MODULE_FIRMWARE(FIRMWARE_MT7663);MODULE_FIRMWARE (FIRMWARE_MT7668 );MODULE_FIRMWARE (FIRMWARE_MT7922 );MODULE_FIRMWARE (FIRMWARE_MT7961 ); +MODULE_FIRMWARE (FIRMWARE_MT7920 );MODULE_FIRMWARE (FIRMWARE_MT7925 );MODULE_FIRMWARE (FIRMWARE_MT7927 );
drivers/bluetooth/btmtk.h +1 -0
@@ -7,6 +7,7 @@#define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin"#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin"#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin" +#define FIRMWARE_MT7920 "mediatek/BT_RAM_CODE_MT7961_1a_2_hdr.bin"#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"#define FIRMWARE_MT7927 "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 380/733 Bluetooth: hci_sysfs: Fix NULL pointer dereference in device_del()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krystian Kaniewski <[email protected]>
[ Upstream commit 9b851b09b392da68bd715601f10a5adb2d8d19b8 ]
A NULL pointer dereference in klist_put() occurs when a child device (such as a BNEP network device in bnep_session) is concurrently being unregistered while hci_conn_del_sysfs() reparents child devices.
This is caused by a race condition between hci_conn_del_sysfs() and concurrent child device unregistration (e.g. bnep_session calling unregister_netdev()). During device unregistration, device_del() snapshots a non-NULL parent pointer. Concurrently, hci_conn_del_sysfs() finds the child device using device_find_any_child() and calls device_move() to reparent it to NULL, which removes the node from its parent's klist and clears knode_parent. Subsequently, device_del() calls klist_del(&dev->p->knode_parent) using the stale parent snapshot, causing klist_put() to dereference knode_klist(n)->put on an already removed node, resulting in a NULL pointer dereference.
This race was introduced by commit 27aabf27fd01 ("Bluetooth: fix use-after-free in device_for_each_child()"), which replaced device_find_child(..., __match_tty) with device_find_any_child() in hci_conn_del_sysfs(). That change was intended to avoid a use-after-free where conn->dev outlived its parent hdev->dev when child devices held references to conn->dev, because conn->dev only held a reference to hdev->dev while registered in sysfs.
Fix the issue properly by taking an explicit reference to the parent device with get_device(&hdev->dev) in hci_conn_init_sysfs() and dropping it with put_device(parent) in bt_link_release() when the conn device is freed. This ensures that hdev->dev remains valid for the entire lifecycle of conn->dev, resolving the underlying use-after-free. With the parent reference held properly, restore the __match_tty filter in hci_conn_del_sysfs() so that device_move() is only invoked on persistent RFCOMM TTY devices as originally intended, eliminating the race condition with unregistering network devices.
--- net/bluetooth/hci_sysfs.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
net/bluetooth/hci_sysfs.c +15 -2
@@ -13,7 +13,10 @@ static const struct class bt_class = {static void bt_link_release (struct device *dev) {struct hci_conn *conn =to_hci_conn (dev); +struct device *parent = dev->parent; +kfree (conn); +put_device (parent); }static const struct device_type bt_link = {
@@ -21,6 +24,16 @@ static const struct device_type bt_link = { .release = bt_link_release, }; +/* +* The rfcomm tty device will possibly retain even when conn +* is down, and sysfs doesn't support move zombie device, +* so we should move the device before conn device is destroyed. +*/ +static int __match_tty (struct device *dev,const void *data) +{ +return !strncmp (dev_name (dev),"rfcomm" ,6 ); +} +void hci_conn_init_sysfs (struct hci_conn *conn) {struct hci_dev *hdev = conn->hdev;
@@ -29,7 +42,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn) conn->dev.type = &bt_link; conn->dev.class = &bt_class; - conn->dev.parent = &hdev->dev; + conn->dev.parent =get_device (&hdev->dev);device_initialize (&conn->dev); }
@@ -69,7 +82,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn)while (1 ) {struct device *dev; - dev =device_find_any_child (&conn->dev); + dev =device_find_child (&conn->dev,NULL , __match_tty);if (!dev)break ;device_move (dev,NULL ,DPM_ORDER_DEV_LAST );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 381/733 Bluetooth: btusb: mediatek: Fix leaked runtime PM reference in reset
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiajia Liu <[email protected]>
[ Upstream commit e486a891c412d9d82ee865987f4eead6196e1f96 ]
MT7925 on HP Pro Mini 260 sometimes timed out during reloading driver and reset usb device. btusb_suspend is not called again after closing bluetooth interface.
usbcore: registered new interface driver btusb
Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20260605184935
Bluetooth: hci0: Execution of wmt command timed out
Bluetooth: hci0: Failed to send wmt patch dwnld (-110)
Bluetooth: hci0: Failed to set up firmware (-110)
usb 3-10: reset high-speed USB device number 4 using xhci_hcd
Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20260605184935
Bluetooth: hci0: Device setup in 1856545 usecs
Bluetooth: hci0: AOSP extensions version v1.00
Bluetooth: hci0: AOSP quality report is supported
Bluetooth: MGMT ver 1.23
btusb_mtk_reset calls usb_autopm_get_interface to resume the device before driving the hardware reset, but never calls the matching usb_autopm_put_interface. Every hardware reset therefore leaks a PM usage reference of the interface, preventing the device from being runtime suspended again until it is unbound.
Add the BTUSB_RESET flag. It is set before usb_queue_reset_device and is cleared in btusb_disconnect, which drops the reference as well. If the flag is already set when a new reset is requested, drop one reference.
Also clear BTMTK_HW_RESET_ACTIVE if usb_autopm_get_interface fails, otherwise no further reset could ever be attempted.
--- drivers/bluetooth/btusb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/bluetooth/btusb.c +13 -1
@@ -970,6 +970,7 @@ struct qca_dump_info {#define BTUSB_ALT6_CONTINUOUS_TX 16#define BTUSB_HW_SSR_ACTIVE 17#define BTUSB_WAKEUP_BROKEN 18 +#define BTUSB_RESET 19struct btusb_data {struct hci_dev *hdev;
@@ -2911,8 +2912,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) } err =usb_autopm_get_interface (data->intf); -if (err <0 ) +if (err <0 ) { +bt_dev_err (hdev,"Failed usb_autopm_get_interface: %d" , err); +clear_bit (BTMTK_HW_RESET_ACTIVE , &btmtk_data->flags);return err; + }/* Release MediaTek ISO data interface */ btusb_mtk_release_iso_intf (hdev);
@@ -2935,6 +2939,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) err =btmtk_usb_subsys_reset (hdev, btmtk_data->dev_id); +if (test_and_set_bit (BTUSB_RESET , &data->flags)) { +bt_dev_err (hdev,"last usb reset failed? Resetting again" ); +usb_autopm_put_interface_no_suspend (data->intf); + } +usb_queue_reset_device (data->intf);clear_bit (BTMTK_HW_RESET_ACTIVE , &btmtk_data->flags);
@@ -4572,6 +4581,9 @@ static void btusb_disconnect(struct usb_interface *intf)if (data->reset_gpio)gpiod_put (data->reset_gpio); +if (test_and_clear_bit (BTUSB_RESET , &data->flags)) +usb_autopm_put_interface_no_suspend (data->intf); +if (intf == data->intf) {if (data->isoc)usb_driver_release_interface (&btusb_driver, data->isoc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 382/733 Bluetooth: btusb: Fix leaked runtime PM reference in btusb_reset
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiajia Liu <[email protected]>
[ Upstream commit c93922dd316b7273a8667d29084632066fa8a2d3 ]
btusb_reset calls usb_autopm_get_interface to resume the device before queuing a reset of it, but never calls the matching usb_autopm_put_interface.
usb_queue_reset_device ends up in usb_reset_device(), and since btusb provides no pre_reset/post_reset callbacks the interface is merely unbound and rebound: the interface device object survives this cycle, and so does its PM usage count, which is not cleared when the driver is unbound.
As a result every reset permanently leaks a PM usage reference, preventing the interface from being runtime suspended again until it is unbound.
Set BTUSB_RESET flag before usb_queue_reset_device so that btusb_disconnect drops the reference. If the flag is already set, drop one reference.
--- drivers/bluetooth/btusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/bluetooth/btusb.c +3 -1
@@ -1047,13 +1047,15 @@ static void btusb_reset(struct hci_dev *hdev)int err; data =hci_get_drvdata (hdev); -/* This is not an unbalanced PM reference since the device will reset */ err =usb_autopm_get_interface (data->intf);if (err) {bt_dev_err (hdev,"Failed usb_autopm_get_interface: %d" , err);return ; } +if (test_and_set_bit (BTUSB_RESET , &data->flags)) +usb_autopm_put_interface_no_suspend (data->intf); +bt_dev_err (hdev,"Resetting usb device." );usb_queue_reset_device (data->intf); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 383/733 net: mana: Clear RDMA teardown and suspend state in mana_rdma_probe()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <[email protected]>
[ Upstream commit f6d61fe4c19cf448e5cba6d8767b4e6966f58606 ]
mana_rdma_remove() sets gd->rdma_teardown to stop mana_rdma_service_handle() from acting on servicing events, but nothing ever clears it. A hardware service reset (GDMA_EQE_HWC_RESET_REQUEST) goes through mana_gd_suspend() -> mana_rdma_remove() and mana_gd_resume() -> mana_rdma_probe(), so from the first reset onwards every GDMA_EQE_HWC_SOC_SERVICE event returns early and RDMA suspend/resume servicing is silently dropped for the life of the device.
gd->is_suspended has the same problem: it is set when servicing removes the adev and is cleared only by a matching resume. A reset while RDMA is suspended re-adds the adev but leaves is_suspended set, so a later resume event calls add_adev() on top of a live gd->adev and leaks it. This is currently masked by the rdma_teardown bug.
Clear both in mana_rdma_probe(). On the reset path mana_rdma_remove() has closed the gate and drained the service workqueue, so clear is_suspended first and re-open the gate with smp_store_release(), paired with smp_load_acquire() in the handler, so the handler cannot observe an open gate with a stale is_suspended. On the initial probe path the gate was never closed and both flags are already clear.
This does not order gd->adev, which add_adev() publishes afterwards. A servicing event arriving in that window is still dropped, as it is in mainline today on the initial probe path; closing it needs probe and the handler to be serialized and is left to a separate change.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +17 -1
@@ -3728,7 +3728,8 @@ static void mana_rdma_service_handle(struct work_struct *work)struct device *dev = gd->gdma_context->dev;int ret; -if (READ_ONCE (gd->rdma_teardown)) +/* Pairs with the smp_store_release() in mana_rdma_probe(). */ +if (smp_load_acquire (&gd->rdma_teardown)) goto out;switch (serv_work->event) {
@@ -4024,6 +4025,21 @@ int mana_rdma_probe(struct gdma_dev *gd)if (err)return err; +/* Clear the state left by a previous mana_rdma_remove() so servicing +* events are handled again after a reset cycle. +*/ + gd->is_suspended = false; + +/* Publish is_suspended before re-opening the gate, so the handler +* cannot observe an open gate with a stale is_suspended. Pairs +* with the smp_load_acquire() in mana_rdma_service_handle(). This +* matters on the reset path, where mana_rdma_remove() closed the +* gate and drained the workqueue; on the initial probe path the +* gate was never closed and both flags are already clear. It does +* not order gd->adev, which add_adev() publishes below. +*/ +smp_store_release (&gd->rdma_teardown, false); + err =add_adev (gd,"rdma" );if (err)mana_gd_deregister_device (gd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 384/733 ipv6: null-check fib6_node before accessing in __ip6_del_rt_siblings()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naman Gulati <[email protected]>
[ Upstream commit cdca92eddc025fdb90071be97738f7d55a65f8dd ]
syzbot reported a null-ptr-deref in __ip6_del_rt_siblings() [0].
The stack trace hinted towards a null dereference of rt->fib6_node when fn->leaf is accessed in __ip6_del_rt_siblings(). With RTNL_FLAG_DOIT_UNLOCKED set, inet6_rtm_delroute() operations run concurrently without acquiring the RTNL lock. In ip6_route_del(), the route lookup happens under rcu_read_lock() without acquiring table->tb6_lock.
Between ip6_route_del() looking up the route and __ip6_del_rt_siblings() acquiring table->tb6_lock, another thread can modify the routing table. For example, when an ECMP route is replaced via RTM_NEWROUTE with NLM_F_REPLACE, fib6_add_rt2node() unlinks all old siblings and sets iter->fib6_node = NULL. A reproducer was found that triggers this [1].
Add a check to ensure rt->fib6_node is non-null before accessing it.
[0]
KASAN: null-ptr-deref in range [0x0000000000000020-0x0000000000000027] RIP: 0010:__ip6_del_rt_siblings+0x31e/0x7c0 net/ipv6/route.c:4056 Call Trace: <TASK> ip6_route_del+0x1054/0x1110 net/ipv6/route.c:4232 inet6_rtm_delroute+0x5d7/0x6d0 net/ipv6/route.c:5669 rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7132 netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2556 netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline] netlink_unicast+0x7f5/0x990 net/netlink/af_netlink.c:1345 netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1900 sock_sendmsg_nosec+0x13a/0x180 net/socket.c:800 __sock_sendmsg net/socket.c:815 [inline] ____sys_sendmsg+0x565/0x870 net/socket.c:2713 ___sys_sendmsg+0x2a5/0x360 net/socket.c:2767 __sys_sendmsg net/socket.c:2799 [inline] __do_sys_sendmsg net/socket.c:2804 [inline] __se_sys_sendmsg net/socket.c:2802 [inline] __x64_sys_sendmsg+0x1b7/0x290 net/socket.c:2802 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline] do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK>
[1] https://gist.github.com/NamanGulati/0766a1159b6ca61928faaf87425ff899
--- net/ipv6/route.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
net/ipv6/route.c +6 -3
@@ -4010,6 +4010,7 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)struct net *net = info->nl_net;struct sk_buff *skb =NULL ;struct fib6_table *table; +struct fib6_node *fn;int err = -ENOENT ;if (rt == net->ipv6.fib6_null_entry)
@@ -4017,9 +4018,13 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg) table = rt->fib6_table;spin_lock_bh (&table->tb6_lock); + fn =rcu_dereference_protected (rt->fib6_node, +lockdep_is_held (&table->tb6_lock)); +if (!fn) + goto out_unlock; +if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {struct fib6_info *sibling, *next_sibling; -struct fib6_node *fn;/* prefer to send a single notification with all hops */ skb =nlmsg_new (rt6_nlmsg_size (rt),GFP_ATOMIC );
@@ -4041,8 +4046,6 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)* and emit a replace or delete notification, respectively. */ info->skip_notify_kernel =1 ; - fn =rcu_dereference_protected (rt->fib6_node, -lockdep_is_held (&table->tb6_lock));if (rcu_access_pointer (fn->leaf) == rt) {struct fib6_info *last_sibling, *replace_rt;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 385/733 net: macb: destroy the phylink instance on the probe error path
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Buchwitz <[email protected]>
[ Upstream commit 7d059f390750152b9bd69df934198651b94fc26d ]
macb_mii_init() creates a phylink instance on both of its success paths, but the probe unwind frees the netdev without destroying it, so a failing macb_alloc_tieoff() or register_netdev() leaks the instance.
Destroy it at err_out_unregister_mdio, which is only reachable once macb_mii_init() has succeeded, so bp->phylink is valid there.
--- drivers/net/ethernet/cadence/macb_main.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/cadence/macb_main.c +1 -0
@@ -5968,6 +5968,7 @@ static int macb_probe(struct platform_device *pdev)mdiobus_unregister (bp->mii_bus);mdiobus_free (bp->mii_bus); } +phylink_destroy (bp->phylink); err_out_phy_exit:phy_exit (bp->phy);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 386/733 net: macb: put the "mdio" child node reference on success
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Buchwitz <[email protected]>
[ Upstream commit 382a373d9ea7a6ac4de9c022385b6217f65ae3cc ]
macb_mii_init() holds the reference returned by of_get_child_by_name() for macb_mdiobus_register() and drops it only on the error paths, so every successful probe leaks a node reference. On a CM5, overlay removal after four bind cycles reports
OF: ERROR: memory leak, expected refcount 1 instead of 5
Drop the reference after registration, where __mdiobus_register() has already taken its own for the lifetime of the bus.
--- drivers/net/ethernet/cadence/macb_main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/cadence/macb_main.c +2 -0
@@ -1164,6 +1164,8 @@ static int macb_mii_init(struct macb *bp)if (err) goto err_out_unregister_bus; +of_node_put (mdio_np); +return 0 ; err_out_unregister_bus:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 387/733 nstree: check listing permission before taking a namespace reference
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
[ Upstream commit 56ea4e86832d8abe8930394473566c194d189f85 ]
legitimize_ns() takes a reference on the candidate namespace before may_list_ns() has decided whether the caller may see it. The __free(ns_put) cleanup on the denied path can drop the last reference to a mount namespace while we still hold the rcu read lock, and put_mnt_ns() may sleep there. This is the same problem commit 2ec2aff3c8e2 ("ns: make sure reference are dropped outside of rcu lock") fixed for the put_user() path. Neither ns_requested() nor may_list_ns() needs a reference, both only look at the namespace type and at the caller's own namespaces, so do the checks first and take the reference last.
Splat:
Voluntary context switch within RCU read-side critical section!
WARNING: kernel/rcu/tree_plugin.h:332 at rcu_note_context_switch+0x238/0x2a0, CPU#5: a/3442 CPU: 5 UID: 1000 PID: 3442 Comm: a Not tainted 7.0.0-30-generic #30-Ubuntu PREEMPT(lazy) RIP: 0010:rcu_note_context_switch+0x238/0x2a0 Call Trace: <TASK> __schedule+0xcf/0x650 schedule+0x27/0x90 schedule_preempt_disabled+0x15/0x30 __mutex_lock.constprop.0+0x550/0xaf0 __mutex_lock_slowpath+0x13/0x20 mutex_lock+0x3b/0x50 exp_funnel_lock+0xb2/0x260 synchronize_rcu_expedited+0xe7/0x220 namespace_unlock+0x26a/0x320 put_mnt_ns+0xd3/0x120 mntns_put+0xe/0x20 do_listns+0x13e/0x560 __do_sys_listns+0x126/0x2d0 __x64_sys_listns+0x20/0x30 x64_sys_call+0x2366/0x2390 do_syscall_64+0x105/0x5a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e </TASK>
--- kernel/nstree.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
kernel/nstree.c +2 -8
@@ -533,19 +533,13 @@ DEFINE_FREE(ns_put, struct ns_common *, if (!IS_ERR_OR_NULL(_T)) ns_put(_T))static inline struct ns_common *__must_check legitimize_ns (const struct klistns *kls,struct ns_common *candidate) { - struct ns_common *ns __free(ns_put) = NULL; -if (!ns_requested (kls, candidate))return NULL ; - ns =ns_get_unless_inactive (candidate); -if (!ns) -return NULL ; - -if (!may_list_ns (kls, ns)) +if (!may_list_ns (kls, candidate))return NULL ; -return no_free_ptr (ns); +return ns_get_unless_inactive (candidate); }static ssize_t do_listns_userns (struct klistns *kls)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 388/733 drm/xe: Guard page-fault worker with runtime PM check
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Varun Gupta <[email protected]>
[ Upstream commit 20fce5b34b21a995839743b4917a1edd2fd503ba ]
During VM teardown, the VM's runtime PM reference is dropped asynchronously, allowing the device to autosuspend while stale page faults belonging to the now-dead VM are still queued. When the page-fault worker later tries to ack one of these, it calls into guc_ct_send_locked() on an already-suspended device, tripping:
Assertion !xe_pm_runtime_suspended(xe) failed!
WARNING at xe_device.c:1267 xe_device_assert_mem_access+0x11c/0x140 [xe]
A live VM/exec queue always holds a PM reference while it has outstanding work, so if the device is suspended at ack time, the owning context is already gone and the fault is stale.
Take a runtime PM reference across the entire pagefault queue worker to safely deliver acks for torn-down VMs.
v3:
- Move PM ref to the generic xe_pagefault_queue_work using guard(xe_pm_runtime)(xe) instead of tracking it in the GuC backend(Matt Brost).
v2:
- Hold PM ref across the entire batch (begin/end) instead of per-ack. This prevents the device from autosuspending mid-batch, which would leave write_only acks written but the end flush skipped, and skip counter++, desyncing the cadence check.(Himal)
- Add a comment explaining stale faults.(Himal)
--- drivers/gpu/drm/xe/xe_pagefault.c | 10 ++++++++++ drivers/gpu/drm/xe/xe_pagefault_types.h | 3 +++ 2 files changed, 13 insertions(+)
drivers/gpu/drm/xe/xe_pagefault.c +10 -0
@@ -16,6 +16,7 @@#include "xe_hw_engine.h" #include "xe_pagefault.h" #include "xe_pagefault_types.h" +#include "xe_pm.h" #include "xe_svm.h" #include "xe_trace_bo.h" #include "xe_vm.h"
@@ -292,9 +293,17 @@ static void xe_pagefault_queue_work(struct work_struct *w) {struct xe_pagefault_queue *pf_queue =container_of (w,typeof (*pf_queue), worker); +struct xe_device *xe = pf_queue->xe;struct xe_pagefault pf;unsigned long threshold; +/* +* A live VM holds a PM reference, but a torn-down VM does not. +* Guard the entire worker loop to safely drain stale faults and +* prevent autosuspends from desyncing batched CT flushes. +*/ +guard (xe_pm_runtime)(xe); +#define USM_QUEUE_MAX_RUNTIME_MS 20 threshold = jiffies +msecs_to_jiffies (USM_QUEUE_MAX_RUNTIME_MS );
@@ -365,6 +374,7 @@ static int xe_pagefault_queue_init(struct xe_device *xe,drm_dbg (&xe->drm,"xe_pagefault_entry_size=%d, total_num_eus=%d, pf_queue->size=%u" ,xe_pagefault_entry_size (), total_num_eus, pf_queue->size); + pf_queue->xe = xe;spin_lock_init (&pf_queue->lock);INIT_WORK (&pf_queue->worker, xe_pagefault_queue_work);
drivers/gpu/drm/xe/xe_pagefault_types.h +3 -0
@@ -8,6 +8,7 @@#include <linux/workqueue.h> +struct xe_device ;struct xe_gt ;struct xe_pagefault ;
@@ -118,6 +119,8 @@ struct xe_pagefault {* queue to absorb the device’s worst-case number of outstanding faults. */ struct xe_pagefault_queue { +/** @xe: Back-pointer to the Xe device */ +struct xe_device *xe;/** * @data: Data in queue containing struct xe_pagefault, protected by * @lock
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 389/733 mptcp: remove unneeded READ_ONCE() annotation
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
[ Upstream commit caa4a79f74f32084ce28aee8653bc04df745970d ]
The subflow->fully_established flag is always written under the subflow socket lock. Reading such value under the same lock does not require any ONCE annotation.
--- net/mptcp/options.c | 4 ++-- net/mptcp/protocol.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
net/mptcp/options.c +2 -2
@@ -529,7 +529,7 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,return false;/* MPC/MPJ needed only on 3rd ack packet, DATA_FIN and TCP shutdown take precedence */ -if (READ_ONCE (subflow->fully_established) || snd_data_fin_enable || +if (subflow->fully_established || snd_data_fin_enable || subflow->snd_isn !=TCP_SKB_CB (skb)->seq || sk->sk_state !=TCP_ESTABLISHED )return false;
@@ -980,7 +980,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,/* here we can process OoO, in-window pkts, only in-sequence 4th ack * will make the subflow fully established */ -if (likely (READ_ONCE (subflow->fully_established))) { +if (likely (subflow->fully_established)) {/* on passive sockets, check for 3rd ack retransmission * note that msk is always set by subflow_syn_recv_sock() * for mp_join subflows
net/mptcp/protocol.c +1 -1
@@ -3743,7 +3743,7 @@ static void schedule_3rdack_retransmission(struct sock *ssk)struct tcp_sock *tp =tcp_sk (ssk);unsigned long timeout; -if (READ_ONCE (mptcp_subflow_ctx (ssk)->fully_established)) +if (mptcp_subflow_ctx (ssk)->fully_established)return ;/* reschedule with a timeout above RTT, as we must look only for drop */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 390/733 watchdog: fix hrtimer start when pretimeout is zero
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Arcari <[email protected]>
[ Upstream commit 0fa37512eb747e4ffdcf367274f9e72845f1bca4 ]
Per the watchdog API, a pretimeout value of 0 disables the feature. However, watchdog_hrtimer_pretimeout_start() fails to verify if the pretimeout is non-zero before arming the timer.
This omission inadvertently starts the software pretimeout timer, which could result in the pretimeout handler executing incorrectly when the watchdog timeout is reached.
Fix this by adding a check for wdd->pretimeout before calling hrtimer_start(), ensuring the disabled state is respected.
--- drivers/watchdog/watchdog_hrtimer_pretimeout.c | 1 + 1 file changed, 1 insertion(+)
drivers/watchdog/watchdog_hrtimer_pretimeout.c +1 -0
@@ -30,6 +30,7 @@ void watchdog_hrtimer_pretimeout_init(struct watchdog_device *wdd)void watchdog_hrtimer_pretimeout_start (struct watchdog_device *wdd) {if (!(wdd->info->options &WDIOF_PRETIMEOUT ) && + wdd->pretimeout && !watchdog_pretimeout_invalid (wdd, wdd->pretimeout)) hrtimer_start(&wdd->wd_data->pretimeout_timer, ktime_set(wdd->timeout - wdd->pretimeout, 0),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 391/733 watchdog: msc313e: Avoid division by zero
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 3c73a37f5e40972ce26d8eeb98e8b938d719b069 ]
clk_get_rate() could return 0. Avoid a division by zero panic.
--- drivers/watchdog/msc313e_wdt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/watchdog/msc313e_wdt.c +5 -1
@@ -97,6 +97,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev) {struct device *dev = &pdev->dev;struct msc313e_wdt_priv *priv; +unsigned long rate; priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL );if (!priv)
@@ -116,7 +117,10 @@ static int msc313e_wdt_probe(struct platform_device *pdev) priv->wdev.ops = &msc313e_wdt_ops, priv->wdev.parent = dev; priv->wdev.min_timeout =MSC313E_WDT_MIN_TIMEOUT ; - priv->wdev.max_timeout =U32_MAX /clk_get_rate (priv->clk); + rate =clk_get_rate (priv->clk); +if (!rate) +return -EINVAL ; + priv->wdev.max_timeout =U32_MAX / rate; priv->wdev.timeout =MSC313E_WDT_DEFAULT_TIMEOUT ;/* If the period is non-zero the WDT is running */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 392/733 watchdog: msc313e: Fix clock leak and spurious timer in settimeout()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 3db30f315935c2fb0d95f46b7a593b5b4d3ec3d0 ]
msc313e_wdt_settimeout() unconditionally calls msc313e_wdt_start() which introduces two severe bugs:
1. If the watchdog is already active, calling start() again will increase the reference count of the clock again. However stop() is only called once, the reference count is unbalance.
2. If the watchdog is stopped, calling settimeout() will start the hardware timer accidentally.
Factor out the register-writing logic into a helper function. Only call it in settimeout() if the watchdog is running. Otherwise, simply update wdev->timeout.
--- drivers/watchdog/msc313e_wdt.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/watchdog/msc313e_wdt.c +16 -6
@@ -31,20 +31,26 @@ struct msc313e_wdt_priv {struct clk *clk; }; +static void msc313e_wdt_set_hw_timeout (struct msc313e_wdt_priv *priv, +unsigned int timeout) +{ +u32 t = timeout *clk_get_rate (priv->clk); + +writew (t &0xffff , priv->base +REG_WDT_MAX_PRD_L ); +writew ((t >>16 ) &0xffff , priv->base +REG_WDT_MAX_PRD_H ); +writew (1 , priv->base +REG_WDT_CLR ); +} +static int msc313e_wdt_start (struct watchdog_device *wdev) {struct msc313e_wdt_priv *priv =watchdog_get_drvdata (wdev); -u32 timeout;int err; err =clk_prepare_enable (priv->clk);if (err)return err; - timeout = wdev->timeout *clk_get_rate (priv->clk); -writew (timeout &0xffff , priv->base +REG_WDT_MAX_PRD_L ); -writew ((timeout >>16 ) &0xffff , priv->base +REG_WDT_MAX_PRD_H ); -writew (1 , priv->base +REG_WDT_CLR ); +msc313e_wdt_set_hw_timeout (priv, wdev->timeout);return 0 ; }
@@ -69,9 +75,13 @@ static int msc313e_wdt_stop(struct watchdog_device *wdev)static int msc313e_wdt_settimeout (struct watchdog_device *wdev,unsigned int new_time) { +struct msc313e_wdt_priv *priv =watchdog_get_drvdata (wdev); + wdev->timeout = new_time; -return msc313e_wdt_start (wdev); +if (watchdog_hw_running (wdev) ||watchdog_active (wdev)) +msc313e_wdt_set_hw_timeout (priv, wdev->timeout); +return 0 ; }static const struct watchdog_info msc313e_wdt_ident = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 393/733 watchdog: msc313e: Enable clock before accessing hardware registers
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 3db2df24e7f11fb117718f6abe326628d91bc500 ]
msc313e_wdt_probe() reads from hardware registers without ensuring the required clock is enabled. Furthermore, if the bootloader leaves the watchdog running, msc313e_wdt_probe() sets WDOG_HW_RUNNING without increasing the clock's reference count.
While the clock is currently supplied as a fixed clock by the device tree (xtal_div2 in arch/arm/boot/dts/sigmastar/mstar-v7.dtsi) which masks the physical issue, this still violates the API usage.
Call clk_prepare_enable() before reading WDT registers. If the WDT is running, leave the clock enabled so the CCF reference counter is balanced.
--- drivers/watchdog/msc313e_wdt.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
drivers/watchdog/msc313e_wdt.c +21 -2
@@ -108,6 +108,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)struct device *dev = &pdev->dev;struct msc313e_wdt_priv *priv;unsigned long rate; +int ret; priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL );if (!priv)
@@ -133,9 +134,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev) priv->wdev.max_timeout =U32_MAX / rate; priv->wdev.timeout =MSC313E_WDT_DEFAULT_TIMEOUT ; + ret =clk_prepare_enable (priv->clk); +if (ret) +return ret; +/* If the period is non-zero the WDT is running */ -if (readw (priv->base +REG_WDT_MAX_PRD_L ) | (readw (priv->base +REG_WDT_MAX_PRD_H ) <<16 )) +if (readw (priv->base +REG_WDT_MAX_PRD_L ) | (readw (priv->base +REG_WDT_MAX_PRD_H ) <<16 )) {set_bit (WDOG_HW_RUNNING , &priv->wdev.status); +/* +* Keep the clock enabled. The watchdog core will skip the next +* start() and a future stop() will balance the CCF reference +* count. +*/ + }else { +clk_disable_unprepare (priv->clk); + }watchdog_set_drvdata (&priv->wdev, priv);platform_set_drvdata (pdev, priv);
@@ -144,7 +157,13 @@ static int msc313e_wdt_probe(struct platform_device *pdev)watchdog_stop_on_reboot (&priv->wdev);watchdog_stop_on_unregister (&priv->wdev); -return devm_watchdog_register_device (dev, &priv->wdev); + ret =devm_watchdog_register_device (dev, &priv->wdev); + +/* If the WDT is running and anything goes wrong, disable the clock. */ +if (ret &&test_bit (WDOG_HW_RUNNING , &priv->wdev.status)) +clk_disable_unprepare (priv->clk); + +return ret; }static int __maybe_unused msc313e_wdt_suspend (struct device *dev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 394/733 watchdog: msc313e: Fix spurious reset on suspend
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 4f6817c9eff4aa1078e16652d82e4b7ef4ffae3e ]
If the hardware watchdog was started by the bootloader and the device is suspended before userspace opens it, the ping worker (from watchdog core) is frozen and the active hardware timer continues running. This leads to a spurious system reset.
Check both watchdog_active() and watchdog_hw_running() when deciding whether to start or stop the watchdog during suspend and resume.
Additionally, call watchdog_stop_ping_on_suspend() to ensure the ping worker be correctly paused and restarted during suspend and resume.
--- drivers/watchdog/msc313e_wdt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/watchdog/msc313e_wdt.c +3 -2
@@ -156,6 +156,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)watchdog_init_timeout (&priv->wdev, timeout, dev);watchdog_stop_on_reboot (&priv->wdev);watchdog_stop_on_unregister (&priv->wdev); +watchdog_stop_ping_on_suspend (&priv->wdev); ret =devm_watchdog_register_device (dev, &priv->wdev);
@@ -170,7 +171,7 @@ static int __maybe_unused msc313e_wdt_suspend(struct device *dev) {struct msc313e_wdt_priv *priv =dev_get_drvdata (dev); -if (watchdog_active (&priv->wdev)) +if (watchdog_active (&priv->wdev) ||watchdog_hw_running (&priv->wdev))msc313e_wdt_stop (&priv->wdev);return 0 ;
@@ -180,7 +181,7 @@ static int __maybe_unused msc313e_wdt_resume(struct device *dev) {struct msc313e_wdt_priv *priv =dev_get_drvdata (dev); -if (watchdog_active (&priv->wdev)) +if (watchdog_active (&priv->wdev) ||watchdog_hw_running (&priv->wdev))msc313e_wdt_start (&priv->wdev);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 395/733 watchdog: msc313e: Fix undefined behavior
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit ab390021b2a3bb4cc875f28a6f76d13de90d7457 ]
readw() returns a u16. Left shifting a u16 by 16 bits yields undefined behavior.
Cast to u32 explicitly before the shift.
--- drivers/watchdog/msc313e_wdt.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/watchdog/msc313e_wdt.c +11 -1
@@ -31,6 +31,16 @@ struct msc313e_wdt_priv {struct clk *clk; }; +static u32 msc313e_wdt_get_hw_timeout (struct msc313e_wdt_priv *priv) +{ +u16 low, high; + + low =readw (priv->base +REG_WDT_MAX_PRD_L ); + high =readw (priv->base +REG_WDT_MAX_PRD_H ); + +return ((u32 )high <<16 ) | low; +} +static void msc313e_wdt_set_hw_timeout (struct msc313e_wdt_priv *priv,unsigned int timeout) {
@@ -139,7 +149,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)return ret;/* If the period is non-zero the WDT is running */ -if (readw (priv->base +REG_WDT_MAX_PRD_L ) | (readw (priv->base +REG_WDT_MAX_PRD_H ) <<16 )) { +if (msc313e_wdt_get_hw_timeout (priv)) {set_bit (WDOG_HW_RUNNING , &priv->wdev.status);/* * Keep the clock enabled. The watchdog core will skip the next
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 396/733 watchdog: msc313e: Sync timeout value if WDT was running at boot
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 01504d14e47b34779911250dd308a03f6ef681c2 ]
If WDT was running at boot, the hardware timeout might be set to values other than the final software timeout.
To be consistent, set the hardware timeout to match the final software timeout (i.e., after watchdog_init_timeout()) if WDT was running.
--- drivers/watchdog/msc313e_wdt.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
drivers/watchdog/msc313e_wdt.c +9 -8
@@ -144,12 +144,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev) priv->wdev.max_timeout =U32_MAX / rate; priv->wdev.timeout =MSC313E_WDT_DEFAULT_TIMEOUT ; +watchdog_set_drvdata (&priv->wdev, priv); +platform_set_drvdata (pdev, priv); + +watchdog_init_timeout (&priv->wdev, timeout, dev); +watchdog_stop_on_reboot (&priv->wdev); +watchdog_stop_on_unregister (&priv->wdev); +watchdog_stop_ping_on_suspend (&priv->wdev); + ret =clk_prepare_enable (priv->clk);if (ret)return ret;/* If the period is non-zero the WDT is running */ if (msc313e_wdt_get_hw_timeout (priv)) { +msc313e_wdt_set_hw_timeout (priv, priv->wdev.timeout);set_bit (WDOG_HW_RUNNING , &priv->wdev.status);/* * Keep the clock enabled. The watchdog core will skip the next
@@ -160,14 +169,6 @@ static int msc313e_wdt_probe(struct platform_device *pdev)clk_disable_unprepare (priv->clk); } -watchdog_set_drvdata (&priv->wdev, priv); -platform_set_drvdata (pdev, priv); - -watchdog_init_timeout (&priv->wdev, timeout, dev); -watchdog_stop_on_reboot (&priv->wdev); -watchdog_stop_on_unregister (&priv->wdev); -watchdog_stop_ping_on_suspend (&priv->wdev); - ret =devm_watchdog_register_device (dev, &priv->wdev);/* If the WDT is running and anything goes wrong, disable the clock. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 397/733 net: dsa: lantiq_gswip: fix GSWIP_MDIO_PHY_FCONTX_EN value
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Havran (Advantech Czech) <[email protected]>
[ Upstream commit 59fb389ad6bf50916189e56dafcd225ab977f874 ]
Per the GSW145 data sheet, the FCONTX (bits 8:7) and FCONRX (bits 6:5) flow-control fields of the PHY_ADDR_n register both encode 00 = AUTO, 01 = EN, 10 = reserved, 11 = DIS. GSWIP_MDIO_PHY_FCONTX_EN was 0x0100, i.e. field value 10 (the reserved encoding), instead of 0x0080 (01 = EN); FCONRX_EN is already 0x0020 (01). Enabling tx flow control therefore wrote the reserved value.
Set FCONTX_EN to 0x0080. The register is shared by all supported parts.
--- drivers/net/dsa/lantiq/lantiq_gswip.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/lantiq/lantiq_gswip.h +1 -1
@@ -42,7 +42,7 @@#define GSWIP_MDIO_PHY_FDUP_DIS 0x0600#define GSWIP_MDIO_PHY_FCONTX_MASK 0x0180#define GSWIP_MDIO_PHY_FCONTX_AUTO 0x0000 -#define GSWIP_MDIO_PHY_FCONTX_EN 0x0100 +#define GSWIP_MDIO_PHY_FCONTX_EN 0x0080#define GSWIP_MDIO_PHY_FCONTX_DIS 0x0180#define GSWIP_MDIO_PHY_FCONRX_MASK 0x0060#define GSWIP_MDIO_PHY_FCONRX_AUTO 0x0000
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 398/733 net: ks8851: Fix receiver error in 100BASE-TX mode following software power-down
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marek Vasut <[email protected]>
[ Upstream commit 66ef5adb75446627f8b6c26cd04f2adc86d4de56 ]
KSZ8851 errata sheet DS80000716D-page 4 Module 3 [1] states that, when issuing a software power-down (PMECR[1:0] = 10) followed by a power-on (PMECR[1:0] = 00), the receiver circuit can fail to start properly preventing communication. The Transmitter will still send data, but no data will be received.
The errata sheet also includes a workaround, which states that, it is recommended that the software power-down feature not be used.
Implement that workaround and drop the entry into software power-down mode. The ks8851_write_mac_addr() calls entry into normal power-on mode at the very beginning of the function, therefore dropping the second call to enter software power-down mode is sufficient here. The ks8851_net_stop() can only be called after ks8851_net_start() was already called, and ks8851_net_start() also makes the MAC enter normal power-on mode, therefore it is also fine to drop the call to enter software power-down mode from ks8851_net_stop().
This will lead to a slight increase in power consumption, but it also fixes a sporadic reliability problem on at least KSZ8851-16MLL, which is where the problem was reported and this fix was tested.
[1] https://ww1.microchip.com/downloads/en/DeviceDoc/80000716D.pdf
--- drivers/net/ethernet/micrel/ks8851_common.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
drivers/net/ethernet/micrel/ks8851_common.c +1 -7
@@ -143,9 +143,6 @@ static int ks8851_write_mac_addr(struct net_device *dev)ks8851_wrreg16 (ks,KS_MAR (i), val); } -if (!netif_running (dev)) -ks8851_set_powermode (ks,PMECR_PM_SOFTDOWN ); -ks8851_unlock (ks);return 0 ;
@@ -478,8 +475,7 @@ static int ks8851_net_open(struct net_device *dev)* @dev: The device being closed. * * Called to close down a network device which has been active. Cancel any -* work, shutdown the RX and TX process and then place the chip into a low -* power state whilst it is not being used. +* work and shutdown the RX and TX process. */ static int ks8851_net_stop (struct net_device *dev) {
@@ -506,8 +502,6 @@ static int ks8851_net_stop(struct net_device *dev)/* shutdown TX process */ ks8851_wrreg16 (ks,KS_TXCR ,0x0000 ); -/* set powermode to soft power down to save power */ -ks8851_set_powermode (ks,PMECR_PM_SOFTDOWN );ks8851_unlock (ks);/* ensure any queued tx buffers are dumped */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 399/733 hwmon: (corsair-cpro) Create debugfs entries after hwmon registration
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 508baf1713f32f287bfb4f85d759403ec8ba35a3 ]
ccp_debugfs_init() registers debugfs files whose private data is the devm allocated ccp. It runs before hwmon_device_register_with_info(), so when that registration fails, ccp_probe() returns with the files still in place. The HID core then frees ccp, and ccp_remove() is not called for a failed probe, so nothing removes them later either. Reading one of the files dereferences the freed pointer.
Create the debugfs entries only after the hwmon device has been registered, so no failing path can leave them behind.
The two version queries stay where they are. They send USB commands without holding ccp->mutex, which is only safe as long as nothing else can call send_usb_cmd(); once the hwmon device is registered its callbacks can do so concurrently. Only the debugfs creation moves, and it is told which queries succeeded.
--- drivers/hwmon/corsair-cpro.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
drivers/hwmon/corsair-cpro.c +13 -7
@@ -566,21 +566,18 @@ static int bootloader_show(struct seq_file *seqf, void *unused) }DEFINE_SHOW_ATTRIBUTE (bootloader); -static void ccp_debugfs_init (struct ccp_device *ccp) +static void ccp_debugfs_init (struct ccp_device *ccp,bool fw_valid,bool bl_valid) {char name[32 ]; -int ret;scnprintf (name,sizeof (name),"corsaircpro-%s" ,dev_name (&ccp->hdev->dev)); ccp->debugfs =debugfs_create_dir (name,NULL ); - ret =get_fw_version (ccp); -if (!ret) +if (fw_valid)debugfs_create_file ("firmware_version" ,0444 , ccp->debugfs, ccp, &firmware_fops); - ret =get_bl_version (ccp); -if (!ret) +if (bl_valid)debugfs_create_file ("bootloader_version" ,0444 , ccp->debugfs, ccp, &bootloader_fops); }
@@ -588,6 +585,7 @@ static void ccp_debugfs_init(struct ccp_device *ccp)static int ccp_probe (struct hid_device *hdev,const struct hid_device_id *id) {struct ccp_device *ccp; +bool fw_valid, bl_valid;int ret; ccp =devm_kzalloc (&hdev->dev,sizeof (*ccp),GFP_KERNEL );
@@ -632,7 +630,13 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)if (ret) goto out_hw_close; -ccp_debugfs_init (ccp); +/* +* Query the versions before registering the hwmon device: they send +* USB commands without holding ccp->mutex, which is only safe while +* nothing else can call send_usb_cmd(). +*/ + fw_valid = !get_fw_version (ccp); + bl_valid = !get_bl_version (ccp); ccp->hwmon_dev =hwmon_device_register_with_info (&hdev->dev,"corsaircpro" , ccp, &ccp_chip_info,NULL );
@@ -641,6 +645,8 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) goto out_hw_close; } +ccp_debugfs_init (ccp, fw_valid, bl_valid); +return 0 ; out_hw_close:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 400/733 hwmon: (gpio-fan) take fan_data->lock in gpio_fan_shutdown()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
[ Upstream commit bb2424c3502cc72292eedade46960c331d5f28fb ]
set_fan_speed() writes the control GPIOs one bit at a time. Every other caller locks around it; gpio_fan_shutdown() doesn't. If it races a locked caller, the GPIO writes can interleave and leave the fan at a speed neither caller asked for.
--- drivers/hwmon/gpio-fan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/hwmon/gpio-fan.c +4 -1
@@ -606,8 +606,11 @@ static void gpio_fan_shutdown(struct platform_device *pdev) {struct gpio_fan_data *fan_data =platform_get_drvdata (pdev); -if (fan_data->gpios) +if (fan_data->gpios) { +mutex_lock (&fan_data->lock);set_fan_speed (fan_data,0 ); +mutex_unlock (&fan_data->lock); + } }static int gpio_fan_runtime_suspend (struct device *dev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 401/733 hwmon: (aspeed-pwm-tacho) Propagate reset deassert errors
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 09a9e1746a87845d7d8e2b4e23bb613306effdff ]
aspeed_pwm_tacho_probe() installs its reset cleanup action and configures the
controller after an unchecked reset deassertion.
Stop probing when the reset controller rejects the transition, before the hwmon device becomes visible.
--- drivers/hwmon/aspeed-pwm-tacho.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hwmon/aspeed-pwm-tacho.c +3 -1
@@ -934,7 +934,9 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev) "missing or invalid reset controller device tree entry");return PTR_ERR (priv->rst); } -reset_control_deassert (priv->rst); + ret =reset_control_deassert (priv->rst); +if (ret) +return ret; ret =devm_add_action_or_reset (dev, aspeed_pwm_tacho_remove, priv);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 402/733 hwmon: (corsair-cpro) Remove debugfs entries when probe fails
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 4ee875c423c66c45d7ef7bbff403cd0e3971e0a2 ]
ccp_debugfs_init() registers debugfs files whose private data is the devm allocated ccp. If hwmon_device_register_with_info() fails right after it, ccp_probe() returns without removing them: the HID core then frees ccp, and ccp_remove() is not called for a failed probe, so the files stay behind. Reading one of them dereferences the freed pointer.
Remove the debugfs entries on that error path. debugfs_remove_recursive() waits for readers already inside the show callbacks, so ccp is no longer reachable through debugfs by the time probe returns.
--- drivers/hwmon/corsair-cpro.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hwmon/corsair-cpro.c +3 -1
@@ -642,13 +642,15 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) ccp, &ccp_chip_info, NULL);if (IS_ERR (ccp->hwmon_dev)) { ret =PTR_ERR (ccp->hwmon_dev); - goto out_hw_close; + goto out_debugfs_remove; }ccp_debugfs_init (ccp, fw_valid, bl_valid);return 0 ; +out_debugfs_remove: +debugfs_remove_recursive (ccp->debugfs); out_hw_close:hid_hw_close (hdev);hid_device_io_stop (hdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 403/733 hwmon: (nct6694) do not expose enable on DTIN temperature channels
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
[ Upstream commit c88a6338ae485e4d6210cc74cdb7664d6476c925 ]
The driver registers 26 temperature channels, all advertising HWMON_T_ENABLE, and indexes the enable bitmap with the raw channel:
data->hwmon_en.tin_en[channel / 8] |= BIT(channel % 8);
tin_en is two bytes and only covers the 5 THR and 5 TDP channels (index 0-9). The 16 DTIN channels (index 10-25) are enabled by the firmware and were never meant to carry an enable bit. Because the control structure is packed, writing temp17_enable and above indexes past tin_en into the fin_en bytes that follow it, so it toggles fan enable state instead; nct6694_hwmon_init() then sends the whole structure back to the device, and reads report fan state as temperature state. It stays within the structure, so this is not a memory safety problem, but on a board that uses the fan channels it is not harmless.
Give the DTIN channels a temperature config without HWMON_T_ENABLE so the core never creates their enable attribute. The enable path is then reachable only for the first 10 channels, which stay within tin_en, and fin_en is left alone. The DTIN input and limit attributes are unchanged.
--- drivers/hwmon/nct6694-hwmon.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-)
drivers/hwmon/nct6694-hwmon.c +19 -16
@@ -159,6 +159,9 @@ static inline s8 temp_to_reg(long val)#define NCT6694_HWMON_TEMP_CONFIG (HWMON_T_INPUT | HWMON_T_ENABLE | \ HWMON_T_MAX | HWMON_T_MAX_HYST | \ HWMON_T_MAX_ALARM) +#define NCT6694_HWMON_DTIN_CONFIG (HWMON_T_INPUT | \ + HWMON_T_MAX | HWMON_T_MAX_HYST | \ + HWMON_T_MAX_ALARM)#define NCT6694_HWMON_FAN_CONFIG (HWMON_F_INPUT | HWMON_F_ENABLE | \ HWMON_F_MIN | HWMON_F_MIN_ALARM)#define NCT6694_HWMON_PWM_CONFIG (HWMON_PWM_INPUT | HWMON_PWM_ENABLE | \
@@ -193,22 +196,22 @@ static const struct hwmon_channel_info *nct6694_info[] = {NCT6694_HWMON_TEMP_CONFIG ,/* TDP2 */ NCT6694_HWMON_TEMP_CONFIG ,/* TDP3 */ NCT6694_HWMON_TEMP_CONFIG ,/* TDP4 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN0 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN1 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN2 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN3 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN4 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN5 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN6 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN7 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN8 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN9 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN10 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN11 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN12 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN13 */ -NCT6694_HWMON_TEMP_CONFIG ,/* DTIN14 */ - NCT6694_HWMON_TEMP_CONFIG), /* DTIN15 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN0 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN1 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN2 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN3 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN4 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN5 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN6 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN7 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN8 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN9 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN10 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN11 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN12 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN13 */ +NCT6694_HWMON_DTIN_CONFIG ,/* DTIN14 */ + NCT6694_HWMON_DTIN_CONFIG), /* DTIN15 */ HWMON_CHANNEL_INFO(fan, NCT6694_HWMON_FAN_CONFIG, /* FIN0 */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 404/733 octeontx2-pf: reset HTB scheduler topology before freeing queues
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratheesh Kannoth <[email protected]>
[ Upstream commit ef39fca8508597fa565cf2be72a884a712fb98af ]
HTB offload programs NIX_AF_TLxX_TOPOLOGY on QoS-allocated scheduler queues via otx2_qos_txschq_set_parent_topology(), but teardown freed those queues without clearing TOPOLOGY. The AF only restores PARENT and SCHEDULE on free, so PRIO_ANCHOR/RR_PRIO settings can survive in the shared scheduler pool and affect later allocations.
Add otx2_qos_reset_schq_topology() and otx2_qos_free_hw_schq() to zero TL4 through TL2 TOPOLOGY before each schq is returned to the AF during hierarchy teardown and cfg rollback. Skip the aggregation level (TL1):
it is a per-tx-link queue shared by the PF, default Tx hierarchy and VFs, and is not freed back to the AF by nix_txschq_free_one().
--- .../net/ethernet/marvell/octeontx2/nic/qos.c | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-)
drivers/net/ethernet/marvell/octeontx2/nic/qos.c +55 -5
@@ -235,13 +235,63 @@ static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf,return rc; } +static int otx2_qos_reset_schq_topology (struct otx2_nic *pfvf,u16 lvl, +u16 schq) +{ +struct mbox *mbox = &pfvf->mbox; +struct nix_txschq_config *cfg; +int rc; + +if (lvl <NIX_TXSCH_LVL_TL4 || lvl >=NIX_TXSCH_LVL_TL1 ) +return 0 ; + +mutex_lock (&mbox->lock); + + cfg =otx2_mbox_alloc_msg_nix_txschq_cfg (mbox); +if (!cfg) { +mutex_unlock (&mbox->lock); +return -ENOMEM ; + } + + cfg->lvl = lvl; + cfg->num_regs =1 ; + +if (lvl ==NIX_TXSCH_LVL_TL4 ) + cfg->reg[0 ] =NIX_AF_TL4X_TOPOLOGY (schq); +else if (lvl ==NIX_TXSCH_LVL_TL3 ) + cfg->reg[0 ] =NIX_AF_TL3X_TOPOLOGY (schq); +else if (lvl ==NIX_TXSCH_LVL_TL2 ) + cfg->reg[0 ] =NIX_AF_TL2X_TOPOLOGY (schq); + + cfg->regval[0 ] =0 ; + + rc =otx2_sync_mbox_msg (mbox); + +mutex_unlock (&mbox->lock); + +return rc; +} + +static void otx2_qos_free_hw_schq (struct otx2_nic *pfvf,u16 lvl,u16 schq) +{ +int err; + + err =otx2_qos_reset_schq_topology (pfvf, lvl, schq); +if (err) +netdev_warn (pfvf->netdev, +"QoS: failed to reset topology for schq %u at level %u: %d\n" , + schq, lvl, err); + +otx2_txschq_free_one (pfvf, lvl, schq); +} +static void otx2_qos_free_hw_node_schq (struct otx2_nic *pfvf,struct otx2_qos_node *parent) {struct otx2_qos_node *node;list_for_each_entry_reverse (node, &parent->child_schq_list, list) -otx2_txschq_free_one (pfvf, node->level, node->schq); +otx2_qos_free_hw_schq (pfvf, node->level, node->schq); } static void otx2_qos_free_hw_node(struct otx2_nic *pfvf,
@@ -252,7 +302,7 @@ static void otx2_qos_free_hw_node(struct otx2_nic *pfvf,list_for_each_entry_safe (node, tmp, &parent->child_list, list) {otx2_qos_free_hw_node (pfvf, node);otx2_qos_free_hw_node_schq (pfvf, node); -otx2_txschq_free_one (pfvf, node->level, node->schq); +otx2_qos_free_hw_schq (pfvf, node->level, node->schq); } }
@@ -266,7 +316,7 @@ static void otx2_qos_free_hw_cfg(struct otx2_nic *pfvf,otx2_qos_free_hw_node_schq (pfvf, node);/* free node hw mappings */ -otx2_txschq_free_one (pfvf, node->level, node->schq); +otx2_qos_free_hw_schq (pfvf, node->level, node->schq);mutex_unlock (&pfvf->qos.qos_lock); }
@@ -913,7 +963,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg)for (lvl =0 ; lvl <NIX_TXSCH_LVL_CNT ; lvl++) {for (idx =0 ; idx < cfg->schq[lvl]; idx++) { schq = cfg->schq_list[lvl][idx]; -otx2_txschq_free_one (pfvf, lvl, schq); +otx2_qos_free_hw_schq (pfvf, lvl, schq); } }
@@ -921,7 +971,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg)for (idx =0 ; idx < cfg->schq_contig[lvl]; idx++) {if (cfg->schq_index_used[lvl][idx]) { schq = cfg->schq_contig_list[lvl][idx]; -otx2_txschq_free_one (pfvf, lvl, schq); +otx2_qos_free_hw_schq (pfvf, lvl, schq); } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 405/733 vxlan: initialize _md in vxlan_xmit_one()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit be83178bfc44588f6e3adb827ed874c683193466 ]
If a VXLAN device is configured with both VXLAN_F_COLLECT_METADATA and VXLAN_F_GBP, and a packet is transmitted through it using an external ip_tunnel_info that lacks the IP_TUNNEL_VXLAN_OPT_BIT flag, md is left pointing to the uninitialized _md stack variable:
if (test_bit(IP_TUNNEL_VXLAN_OPT_BIT, info->key.tun_flags)) {
if (info->options_len < sizeof(*md))
goto drop;
md = ip_tunnel_info_opts(info);
}Because IP_TUNNEL_VXLAN_OPT_BIT is not set, md is not updated and remains pointing to _md. Later, vxlan_build_skb() is called with md, which eventually calls vxlan_build_gbp_hdr():
if (vxflags & VXLAN_F_GBP)
vxlan_build_gbp_hdr(vxh, md);
Inside vxlan_build_gbp_hdr(), md->gbp is read:
if (!md->gbp)
return;
gbp = (struct vxlanhdr_gbp *)vxh;
...
if (md->gbp & VXLAN_GBP_DONT_LEARN)
gbp->dont_learn = 1;If the stack contains garbage, this causes:
1) VXLAN_HF_GBP flag to be spuriously set in the VXLAN header.
2) gbp->dont_learn and gbp->policy_applied to be set from stack bits.
3) gbp->policy_id to receive 16 bits of uninitialized kernel stack data, leaking it onto the wire.
Fix this by zero-initializing _md. If IP_TUNNEL_VXLAN_OPT_BIT is not present, md->gbp remains 0, and vxlan_build_gbp_hdr() returns early without modifying the VXLAN header.
--- drivers/net/vxlan/vxlan_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/vxlan/vxlan_core.c +1 -1
@@ -2373,7 +2373,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,struct ip_tunnel_key key;struct vxlan_dev *vxlan =netdev_priv (dev);const struct iphdr *old_iph; -struct vxlan_metadata _md; +struct vxlan_metadata _md = {};struct vxlan_metadata *md = &_md;unsigned int pkt_len = skb->len;__be16 src_port =0 , dst_port;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 406/733 ppp_synctty: ensure a writeable skb header
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingfang Deng <[email protected]>
[ Upstream commit 8aaeb56aff2a557a88f83ae866da2c91ad247e59 ]
ppp_sync_txmunge() checks headroom before prepending the address and control bytes, but does not ensure that the skb header is writable. A received skb can reach this function through PPP channel bridging without passing through ppp_start_xmit(), which calls skb_cow_head().
For example, a PPPoE frame may share its buffer with a clone queued to an AF_PACKET socket. If it is bridged to a synchronous tty channel, the address/control bytes can overwrite data still visible to that socket.
Use skb_cow_head() to ensure both sufficient headroom and a writable header.
--- drivers/net/ppp/ppp_synctty.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-)
drivers/net/ppp/ppp_synctty.c +3 -11
@@ -457,17 +457,9 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)/* prepend address/control fields if necessary */ if ((ap->flags &SC_COMP_AC ) ==0 || islcp) { -if (skb_headroom (skb) <2 ) { -struct sk_buff *npkt =dev_alloc_skb (skb->len +2 ); -if (npkt ==NULL ) { -kfree_skb (skb); -return NULL ; - } -skb_reserve (npkt,2 ); -skb_copy_from_linear_data (skb, -skb_put (npkt, skb->len), skb->len); -consume_skb (skb); - skb = npkt; +if (skb_cow_head (skb,2 )) { +kfree_skb (skb); +return NULL ; }skb_push (skb,2 ); skb->data[0 ] =PPP_ALLSTATIONS ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 407/733 net: phylink: initialise link_state before a forced major config
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksei Sviridkin <[email protected]>
[ Upstream commit 113998aa372f4869bf62cfc75c28a2849e8487be ]
phylink_resolve() leaves link_state on the stack unpopulated on its disable and link-failed branches, which set only link_state.link. phylink_apply_manual_flow() then reads the struct's advertising on every mode but MLO_AN_FIXED, and has done so since long before force_major_config existed.
force_major_config turns that into a write to the hardware. It is the only trigger for the major-config block that does not require mac_config, so phylink_major_config() programs the MAC for whatever the stack held, a zeroed interface is PHY_INTERFACE_MODE_NA, and the write-back stores it in pl->link_config.interface.
phylink_replay_link_end() is the only in-tree setter, and sja1105_static_config_reload() calls it for every port that has a phylink instance, regardless of admin state. On a stopped port phylink_run_resolve() no-ops, so the flag outlives the call. The next resolve consumes it whatever branch it takes; an unpopulated branch is where that does damage.
Found while developing a series that attaches a late PHY from a delayed work item and sets this flag there, so the PHY attached after its port was already up. The link stayed down until the port was cycled 29 minutes later. With this patch on the same board the same attach programs the MAC for 2500base-x rather than unknown, and the PHY's interrupt fires without a port bounce where it had stayed at zero throughout the failure.
--- drivers/net/phy/phylink.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/phy/phylink.c +2 -0
@@ -1630,8 +1630,10 @@ static void phylink_resolve(struct work_struct *w)if (pl->phylink_disable_state) { pl->link_failed = false; + link_state = pl->link_config; link_state.link = false; }else if (pl->link_failed) { + link_state = pl->link_config; link_state.link = false; retrigger = true; }else if (pl->act_link_an_mode ==MLO_AN_FIXED ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 408/733 net: stmmac: initialize ptp_lock at probe time
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 0338c68e22abd2ee509ec2e32508a50896618c32 ]
priv->ptp_lock is only initialized in stmmac_ptp_register(), which runs during __stmmac_open(). However, the lock is also used while the interface is down and has never been opened: tc_taprio_configure() invokes the PTP gettime64() callback to compute the EST base time when offloading a TAPRIO schedule, and stmmac_get_time() takes priv->ptp_lock. Using an uninitialized rwlock is undefined behaviour. Move the rwlock_init() to __stmmac_dvr_probe(), together with the other private locks, so that ptp_lock is always valid regardless of the interface state.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1 -0
@@ -8032,6 +8032,7 @@ static int __stmmac_dvr_probe(struct device *device,stmmac_napi_add (ndev);mutex_init (&priv->lock); +rwlock_init (&priv->ptp_lock);stmmac_fpe_init (priv);
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +0 -1
@@ -365,7 +365,6 @@ void stmmac_ptp_register(struct stmmac_priv *priv)if (priv->plat->crosststamp) priv->ptp_clock_ops.getcrosststamp = stmmac_getcrosststamp; -rwlock_init (&priv->ptp_lock);mutex_init (&priv->aux_ts_lock); priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 409/733 net/mlx5e: Move representor vnic reporter to eswitch devlink port
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carolina Jubran <[email protected]>
[ Upstream commit 7f26a5e8040b4957ef4dbdfcde6cc7ba2db53937 ]
The representor vnic devlink health reporter is created and destroyed along the representor netdev (un)load path, which is not serialized by the devlink instance lock. Destroying the reporter from there triggers a devl_assert_locked() splat on driver unbind:
WARNING: net/devlink/core.c:259 at devl_assert_locked+0x54/0x70, CPU#2: bash/3758 Modules linked in: mlx5_vdpa vringh vdpa mlx5_ib mlx5_fwctl mlx5_core ... CPU: 2 UID: 0 PID: 3758 Comm: bash Tainted: G W 6.19.0+ #1 PREEMPT Tainted: [W]=WARN Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), ... RIP: 0010:devl_assert_locked+0x54/0x70 Call Trace: <TASK> devl_health_reporter_destroy+0x3a/0x1b0 mlx5e_vport_rep_unload+0x12d/0x2b0 [mlx5_core] mlx5_eswitch_unregister_vport_reps+0x1b8/0x220 [mlx5_core] ? __esw_offloads_unload_rep+0x190/0x190 [mlx5_core] ? kernfs_remove_by_name_ns+0xc3/0xf0 device_release_driver_internal+0x3b2/0x560 unbind_store+0xce/0xf0
Move the reporter's lifecycle to the eswitch devlink port (un)register paths, which are already serialized by the devlink instance lock, and store the handle on mlx5_devlink_port. Use the port's mlx5_vport as the reporter priv since the diagnose callback only needs a device handle and a vport number, and mlx5_vport carries both and is initialized before any representor driver probes.
--- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 52 +------------------ .../net/ethernet/mellanox/mlx5/core/en_rep.h | 1 - .../mellanox/mlx5/core/esw/devlink_port.c | 37 +++++++++++++ .../net/ethernet/mellanox/mlx5/core/eswitch.h | 1 + 4 files changed, 39 insertions(+), 52 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +1 -51
@@ -56,7 +56,6 @@#include "lib/vxlan.h" #define CREATE_TRACE_POINTS #include "diag/en_rep_tracepoint.h" -#include "diag/reporter_vnic.h" #include "en_accel/ipsec.h" #include "en/tc/int_port.h" #include "en/ptp.h"
@@ -1435,51 +1434,6 @@ static unsigned int mlx5e_ul_rep_stats_grps_num(struct mlx5e_priv *priv)return ARRAY_SIZE (mlx5e_ul_rep_stats_grps); } -static int -mlx5e_rep_vnic_reporter_diagnose (struct devlink_health_reporter *reporter, -struct devlink_fmsg *fmsg, -struct netlink_ext_ack *extack) -{ -struct mlx5e_rep_priv *rpriv =devlink_health_reporter_priv (reporter); -struct mlx5_eswitch_rep *rep = rpriv->rep; - -mlx5_reporter_vnic_diagnose_counters (rep->esw->dev, fmsg, rep->vport, - true); -return 0 ; -} - -static const struct devlink_health_reporter_ops mlx5_rep_vnic_reporter_ops = { - .name ="vnic" , - .diagnose = mlx5e_rep_vnic_reporter_diagnose, -}; - -static void mlx5e_rep_vnic_reporter_create (struct mlx5e_priv *priv, -struct devlink_port *dl_port) -{ -struct mlx5e_rep_priv *rpriv = priv->ppriv; -struct devlink_health_reporter *reporter; - - reporter =devl_port_health_reporter_create (dl_port, - &mlx5_rep_vnic_reporter_ops, - rpriv); -if (IS_ERR (reporter)) { -mlx5_core_err (priv->mdev, -"Failed to create representor vnic reporter, err = %pe\n" , - reporter); -return ; - } - - rpriv->rep_vnic_reporter = reporter; -} - -static void mlx5e_rep_vnic_reporter_destroy (struct mlx5e_priv *priv) -{ -struct mlx5e_rep_priv *rpriv = priv->ppriv; - -if (!IS_ERR_OR_NULL (rpriv->rep_vnic_reporter)) -devl_health_reporter_destroy (rpriv->rep_vnic_reporter); -} -static const struct mlx5e_profile mlx5e_rep_profile = { .init = mlx5e_init_rep, .cleanup = mlx5e_cleanup_rep,
@@ -1603,10 +1557,8 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) dl_port =mlx5_esw_offloads_devlink_port (dev->priv.eswitch, rpriv->rep->vport); -if (!IS_ERR (dl_port)) { +if (!IS_ERR (dl_port))SET_NETDEV_DEVLINK_PORT (netdev, dl_port); -mlx5e_rep_vnic_reporter_create (priv, dl_port); - } err =register_netdev (netdev);if (err) {
@@ -1619,7 +1571,6 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)return 0 ; err_detach_netdev: -mlx5e_rep_vnic_reporter_destroy (priv);mlx5e_detach_netdev (netdev_priv (netdev)); err_cleanup_profile: priv->profile->cleanup (priv);
@@ -1677,7 +1628,6 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep) }unregister_netdev (netdev); -mlx5e_rep_vnic_reporter_destroy (priv);mlx5e_detach_netdev (priv); priv->profile->cleanup (priv);mlx5e_destroy_netdev (netdev);
drivers/net/ethernet/mellanox/mlx5/core/en_rep.h +0 -1
@@ -118,7 +118,6 @@ struct mlx5e_rep_priv {struct rtnl_link_stats64 prev_vf_vport_stats;struct mlx5_flow_handle *send_to_vport_meta_rule;struct rhashtable tc_ht; -struct devlink_health_reporter *rep_vnic_reporter; }; static inline
drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +37 -0
@@ -4,6 +4,26 @@#include <linux/mlx5/driver.h> #include "eswitch.h" #include "devlink.h" +#include "diag/reporter_vnic.h" + +static int +mlx5_esw_rep_vnic_reporter_diagnose (struct devlink_health_reporter *reporter, +struct devlink_fmsg *fmsg, +struct netlink_ext_ack *extack) +{ +struct mlx5_vport *vport =devlink_health_reporter_priv (reporter); + +mlx5_reporter_vnic_diagnose_counters (vport->dev, fmsg, vport->vport, + true); + +return 0 ; +} + +static const +struct devlink_health_reporter_ops mlx5_esw_rep_vnic_reporter_ops = { + .name ="vnic" , + .diagnose = mlx5_esw_rep_vnic_reporter_diagnose, +};static void mlx5_esw_get_port_parent_id (struct mlx5_core_dev *dev,struct netdev_phys_item_id *ppid)
@@ -217,6 +237,7 @@ static void mlx5_esw_devlink_port_res_unregister(struct devlink_port *dl_port)int mlx5_esw_offloads_devlink_port_register (struct mlx5_eswitch *esw,struct mlx5_vport *vport) { +struct devlink_health_reporter *reporter;struct mlx5_core_dev *dev = esw->dev;const struct devlink_port_ops *ops;struct mlx5_devlink_port *dl_port;
@@ -252,6 +273,16 @@ int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlxmlx5_core_dbg (dev,"Failed to register port resources: %d\n" , err); + reporter =devl_port_health_reporter_create ( + &dl_port->dl_port, &mlx5_esw_rep_vnic_reporter_ops, + vport); +if (IS_ERR (reporter)) +mlx5_core_err (dev, +"Failed to create vnic health reporter for vport %d: %pe\n" , + vport_num, reporter); +else + dl_port->vnic_reporter = reporter; +return 0 ; rate_err:
@@ -266,6 +297,12 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport)if (!vport->dl_port)return ; dl_port = vport->dl_port; + +if (dl_port->vnic_reporter) { +devl_health_reporter_destroy (dl_port->vnic_reporter); + dl_port->vnic_reporter =NULL ; + } +mlx5_esw_devlink_port_res_unregister (&dl_port->dl_port);mlx5_esw_qos_vport_update_parent (vport,NULL ,NULL );
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +1 -0
@@ -189,6 +189,7 @@ struct mlx5_vport;struct mlx5_devlink_port {struct devlink_port dl_port;struct mlx5_vport *vport; +struct devlink_health_reporter *vnic_reporter; }; static inline void mlx5_devlink_port_init(struct mlx5_devlink_port *dl_port,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 410/733 powerpc/entry: Fix double accounting of user time on interrupt entry
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
[ Upstream commit 11ae2e1dc58304a48816fc8ca4afa8f2ef9d1bdf ]
Since the switch to generic entry, an interrupt from user mode accounts user time twice: once in arch_interrupt_enter_prepare() and again in arch_enter_from_user_mode(), which irqentry_enter() invokes for the same interrupt:
arch_interrupt_enter_prepare() account_cpu_user_entry() /* first */ irqentry_enter() arch_enter_from_user_mode() account_cpu_user_entry() /* second */
The second call charges the same interval again, because account_cpu_user_entry() accumulates the time spent in user mode since the last return to user space.
The two calls come from the GENERIC_ENTRY preparation series, where each step was a no-op on its own. Commit 09a9d3a8499d ("powerpc: introduce arch_enter_from_user_mode") added the hook with the user-time accounting in it, but nothing called it yet. Commit 893082ac769b ("powerpc: Prepare for IRQ entry exit") copied interrupt_enter_prepare() verbatim into entry-common.h as arch_interrupt_enter_prepare(); that copy was equally unused, as handlers still called interrupt_enter_prepare().
Commit bee25f97ad24 ("powerpc: Enable GENERIC_ENTRY feature") made both live. On the syscall side it did the full conversion:system_call_exception() now accounts once through the hook via syscall_enter_from_user_mode(), rather than calling account_cpu_user_entry() directly. On the interrupt side it switched the handler macros to arch_interrupt_enter_prepare() followed by irqentry_enter(), which also runs the hook, but the accounting in arch_interrupt_enter_prepare() was not removed to match. The double accounting starts with that commit.
With CONFIG_VIRT_CPU_ACCOUNTING_NATIVE=y this roughly doubles the reported user time of any workload that takes interrupts. The other accounting modes compile account_cpu_user_entry() to an empty stub, so they are not affected.
Remove the accounting from arch_interrupt_enter_prepare() and rely on arch_enter_from_user_mode(), which already runs for both syscalls and interrupts. The duplicate account_stolen_time() call is removed the same way.
On a pseries LPAR a busy loop reports 6s user time in 3s elapsed (~210% CPU) before the fix, and 3s (~105% CPU) after it:
$ python3 -c 'while True: pass' & $ sleep 3; ps -p $! -o etime,time,pcpu
ELAPSED TIME %CPU
Before 00:03 00:00:06 210 After 00:03 00:00:03 105
A 50% load reports ~70% usr / 30% idle before the fix, and ~49% usr / 51% idle after it:
$ taskset -c 6 stress-ng --cpu 1 --cpu-load 50 & $ mpstat -P 6 1
CPU %usr %idle Before 6 69.74 30.26 After 6 48.51 50.50
--- arch/powerpc/include/asm/entry-common.h | 2 -- 1 file changed, 2 deletions(-)
arch/powerpc/include/asm/entry-common.h +0 -2
@@ -222,8 +222,6 @@ static inline void arch_interrupt_enter_prepare(struct pt_regs *regs)if (user_mode (regs)) {kuap_lock (); -account_cpu_user_entry (); -account_stolen_time (); }else {kuap_save_and_lock (regs);/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 411/733 selftests/powerpc/tm: Fix tcheck() reading uninitialised CR value
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thibault Ferrante <[email protected]>
[ Upstream commit ed28b16eab705071d28edaace47189c2eb3aa108 ]
tcheck() is used to check the current transaction state (active, suspended, doomed) via the "tcheck" instruction, which writes its result into CR field 0. The inline asm declared a GPR output operand for this result but never actually moved the CR into it.
Every caller (tcheck_doomed(), tcheck_active(), tcheck_suspended(), tcheck_transactional()) has effectively been testing bits of an unrelated, arbitrary register value since this helper was introduced.
The "& 4" mask discards the TDOOMED and TS_lsb (suspended) bits before they ever reach the callers, so tcheck_doomed() and tcheck_suspended() can never return true, and tcheck_transactional() degrades to being equivalent to tcheck_active().
Fix tcheck() to actually move CR into the output register with mfcr, and widen the mask from "& 4" to "& 0xf" so the full CR0 nibble (TDOOMED | TS_msb | TS_lsb | reserved) is preserved for the callers.
This bug has been present since tcheck() was introduced.
--- tools/testing/selftests/powerpc/tm/tm.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
tools/testing/selftests/powerpc/tm/tm.h +6 -2
@@ -105,8 +105,12 @@ static inline bool failure_is_nesting(void)static inline int tcheck (void ) {long cr; - asmvolatile ("tcheck 0" :"=r" (cr) : :"cr0" ); -return (cr >>28 ) &4 ; + asmvolatile ("tcheck 0;" +"mfcr %0;" + :"=r" (cr) + : + :"cr0" ); +return (cr >>28 ) &0xf ; }static inline bool tcheck_doomed (void )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 412/733 drm/i915/dp: Gate UHBR SST SDP splitting on sink capability
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mitul Golani <[email protected]>
[ Upstream commit a894f97318366d12102c15937aa6b63c21aa82b5 ]
SDP splitting for 128b/132b (UHBR) SST audio must only be enabled when the sink advertises support for it. Previously sdp_split_enable was set for every UHBR SST stream carrying audio, regardless of sink capability.
In MST mode SDP splitting is inherently supported, so the sink capability check (DP_SST_SPLIT_SDP_CAP) is applied only to the SST path.
--- .../drm/i915/display/intel_display_types.h | 2 + drivers/gpu/drm/i915/display/intel_dp.c | 44 ++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-)
drivers/gpu/drm/i915/display/intel_display_types.h +2 -0
@@ -1947,6 +1947,8 @@ struct intel_dp {bool colorimetry_support; +bool sst_split_sdp_support; +struct {enum transcoder transcoder;struct mutex lock;
drivers/gpu/drm/i915/display/intel_dp.c +38 -6
93 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 413/733 perf/core: Allow list_del during perf_event_overflow()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Richter <[email protected]>
[ Upstream commit 59e63416f5153e7d58652c616fbdcb7d5e01fff7 ]
A PMU might use perf_sched_cb_inc() and perf_sched_cb_dec() interface to get the PMU call back function pmu::sched_task invoked at schedule in and schedule out. This is achieved by walking along the list anchored by sched_cb_list.
The following scenario might lead to a list corruption.
perf_pmu_sched_task()
for_each_list_entry(..., &sched_cb_list)
+--> __perf_pmu_sched_task()
+--> event->pmu->sched_task())
+--> PMU_push_sample()
+--> perf_event_overflow()
+--> __perf_event_overflow()
+--> pmu->stop()
+--> perf_sched_cb_dec()
remove entry from sched_cb_list
while list node in use.This happens when ioctl(fd, PERF_EVENT_IOC_REFRESH, xxx) has been invoked and perf_event::event_limit hits zero.
Prevent the list corruption and convert for_each_list_entry() to for_each_list_entry_safe().
--- kernel/events/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/events/core.c +2 -2
@@ -3925,13 +3925,13 @@ static void perf_pmu_sched_task(struct task_struct *prev, bool sched_in) {struct perf_cpu_context *cpuctx =this_cpu_ptr (&perf_cpu_context); -struct perf_cpu_pmu_context *cpc; +struct perf_cpu_pmu_context *cpc, *cpc2;/* cpuctx->task_ctx will be handled in perf_event_context_sched_in/out */ if (prev == next || cpuctx->task_ctx)return ; -list_for_each_entry (cpc,this_cpu_ptr (&sched_cb_list), sched_cb_entry) +list_for_each_entry_safe (cpc, cpc2,this_cpu_ptr (&sched_cb_list), sched_cb_entry)__perf_pmu_sched_task (cpc, sched_in ? next : prev, sched_in); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 414/733 perf/x86/intel: Correct pt_regs->flags update for PEBS path
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dapeng Mi <[email protected]>
[ Upstream commit 88aa1223bfffb1a0a98c639e9e1f71058f0d9178 ]
pt_regs->flags holds the saved CPU FLAGS register. In the PEBS path, it was incorrectly set to PERF_EFLAGS_EXACT instead of being populated from the PEBS flags snapshot.
Update pt_regs->flags from PEBS GPR flags if GPRs group is present.
--- arch/x86/events/intel/ds.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
arch/x86/events/intel/ds.c +9 -1
@@ -2445,7 +2445,7 @@ static inline void __setup_pebs_basic_group(struct perf_event *event, {/* The ip in basic is EventingIP */ set_linear_ip (regs, ip); - regs->flags =PERF_EFLAGS_EXACT ; + regs->flags |=PERF_EFLAGS_EXACT ;setup_pebs_time (event, data, tsc);if (sample_type &PERF_SAMPLE_WEIGHT_STRUCT )
@@ -2457,9 +2457,17 @@ static inline void __setup_pebs_gpr_group(struct perf_event *event, struct pebs_gprs *gprs, u64 sample_type) { +/* +* Update flags with PEBS data. PERF_EFLAGS_EXACT must be set +* in previous basic group handling. +*/ + regs->flags = gprs->flags |PERF_EFLAGS_EXACT ; +if (event->attr.precise_ip <2 ) {set_linear_ip (regs, gprs->ip); regs->flags &= ~PERF_EFLAGS_EXACT ; + }else if (regs->flags &X86_VM_MASK ) { + regs->flags ^= (PERF_EFLAGS_VM |X86_VM_MASK ); }if (sample_type & (PERF_SAMPLE_REGS_INTR |PERF_SAMPLE_REGS_USER ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 415/733 perf/x86/intel: Prevent drain_pebs() reentry
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dapeng Mi <[email protected]>
[ Upstream commit a56c03a397e2cd0c4cf8da96dcd6214f7d0e7d8c ]
The PEBS buffer is shared by all events on a CPU, so drain_pebs() must not be reentered. If so, one instance may observe stale buffer state and potentially access out-of-bound memory.
Most invocations happen in NMI context, which naturally prevents reentry. However, drain_pebs() is also reachable from process context via intel_pmu_drain_pebs_buffer().
In those paths, the PMU is often already disabled, but not guaranteed. For example, __intel_pmu_pebs_disable() only disables the target counter, so other active counters can still raise a PMI and interrupt an in-flight drain_pebs(). Here is an example,
__perf_addr_filters_adjust()
perf_event_stop()
__perf_event_stop()
x86_pmu_stop() (event->pmu->stop)
intel_pmu_disable_event()
intel_pmu_pebs_disable()
__intel_pmu_pebs_disable()
intel_pmu_drain_large_pebs()
intel_pmu_drain_pebs_buffer()Introduce __intel_pmu_quiesce() and __intel_pmu_resume() helpers and use them in intel_pmu_drain_large_pebs() to disable the full PMU around the intel_pmu_drain_pebs_buffer() call, preventing reentry.
Also add a warning in intel_pmu_drain_pebs_buffer() when the full PMU is not disabled.
--- arch/x86/events/intel/core.c | 33 ++++++++++++++++++++++++--------- arch/x86/events/intel/ds.c | 8 +++++++- arch/x86/events/perf_event.h | 3 +++ 3 files changed, 34 insertions(+), 10 deletions(-)
arch/x86/events/intel/core.c +24 -9
@@ -3125,6 +3125,27 @@ static void intel_pmu_del_event(struct perf_event *event)this_cpu_ptr (&cpu_hw_events)->n_late_setup--; } +int __intel_pmu_quiesce (void ) +{ +struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); +int pmu_enabled = cpuc->enabled; + + cpuc->enabled =0 ; +if (pmu_enabled) +intel_pmu_disable_all (); + +return pmu_enabled; +} + +void __intel_pmu_resume (int pmu_enabled) +{ +struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); + + cpuc->enabled = pmu_enabled; +if (pmu_enabled) +intel_pmu_enable_all (0 ); +} +static int icl_set_topdown_event_period (struct perf_event *event) {struct hw_perf_event *hwc = &event->hw;
@@ -3316,16 +3337,13 @@ static void intel_pmu_read_event(struct perf_event *event)if (event->hw.flags & (PERF_X86_EVENT_AUTO_RELOAD |PERF_X86_EVENT_TOPDOWN ) ||is_pebs_counter_event_group (event)) {struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); -bool pmu_enabled = cpuc->enabled; +int pmu_enabled;/* Only need to call update_topdown_event() once for group read. */ if (is_metric_event (event) && (cpuc->txn_flags &PERF_PMU_TXN_READ ))return ; - cpuc->enabled =0 ; -if (pmu_enabled) -intel_pmu_disable_all (); - + pmu_enabled =__intel_pmu_quiesce ();/* * If the PEBS counters snapshotting is enabled, * the topdown event is available in PEBS records.
@@ -3334,10 +3352,7 @@ static void intel_pmu_read_event(struct perf_event *event)static_call (intel_pmu_update_topdown_event)(event,NULL ); elseintel_pmu_drain_pebs_buffer (); - - cpuc->enabled = pmu_enabled; -if (pmu_enabled) -intel_pmu_enable_all (0 ); +__intel_pmu_resume (pmu_enabled);return ; }
arch/x86/events/intel/ds.c +7 -1
@@ -1242,8 +1242,11 @@ int intel_pmu_drain_bts_buffer(void)void intel_pmu_drain_pebs_buffer (void ) { +struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events);struct perf_sample_data data; +WARN_ON_ONCE (cpuc->enabled); +static_call (x86_pmu_drain_pebs)(NULL , &data); }
@@ -1877,8 +1880,11 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)static inline void intel_pmu_drain_large_pebs (struct cpu_hw_events *cpuc) {if (cpuc->n_pebs == cpuc->n_large_pebs && - cpuc->n_pebs != cpuc->n_pebs_via_pt) + cpuc->n_pebs != cpuc->n_pebs_via_pt) { +int enabled =__intel_pmu_quiesce ();intel_pmu_drain_pebs_buffer (); +__intel_pmu_resume (enabled); + } }static void __intel_pmu_pebs_enable (struct perf_event *event)
arch/x86/events/perf_event.h +3 -0
@@ -1644,6 +1644,9 @@ static __always_inline void __intel_pmu_lbr_disable(void)wrmsrq (MSR_IA32_DEBUGCTLMSR , debugctl); } +extern int __intel_pmu_quiesce (void ); +extern void __intel_pmu_resume (int pmu_enabled); +int intel_pmu_save_and_restart (struct perf_event *event); struct event_constraint *
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 416/733 sched/eevdf: Fix augmented max_slice
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Guittot <[email protected]>
[ Upstream commit 9a8bc9bb4c3fb3218b4f151f98a722fbeb5b5c34 ]
Similarly to se->min_slice, init se->max_slice with se->slice before enqueueing the entity so the augmented callback computes it correctly at parent level.
--- kernel/sched/fair.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/sched/fair.c +2 -0
@@ -1042,6 +1042,8 @@ static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)sum_w_vruntime_add (cfs_rq, se); se->min_vruntime = se->vruntime; se->min_slice = se->slice; + se->max_slice = se->slice; +rb_add_augmented_cached (&se->run_node, &cfs_rq->tasks_timeline, __entity_less, &min_vruntime_cb); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 417/733 sched/eevdf: Fix rb augmented with multi fields
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Guittot <[email protected]>
[ Upstream commit 51b0e68cfa0ac69e3c3ea9d6753af7e15dfaab22 ]
The eevdf rb tree maintains 3 augmented fields but only one is currently copied when balancing the tree.
Add a more generic define that can be used when there are several augmented fields. In this case, we provide a function that takes care of copying all fields.
--- include/linux/rbtree_augmented.h | 35 +++++++++++++++++++++++++------- kernel/sched/fair.c | 12 +++++++++-- 2 files changed, 38 insertions(+), 9 deletions(-)
include/linux/rbtree_augmented.h +28 -7
@@ -87,18 +87,18 @@ rb_add_augmented_cached(struct rb_node *node, struct rb_root_cached *tree, }/* -* Template for declaring augmented rbtree callbacks (generic case) +* Template for declaring augmented rbtree callbacks (generic multi fields) * * RBSTATIC: 'static' or empty * RBNAME: name of the rb_augment_callbacks structure * RBSTRUCT: struct type of the tree nodes * RBFIELD: name of struct rb_node field within RBSTRUCT -* RBAUGMENTED: name of field within RBSTRUCT holding data for subtree -* RBCOMPUTE: name of function that recomputes the RBAUGMENTED data +* RBCOPY: name of function that copies the RBAUGMENTED datas +* RBCOMPUTE: name of function that recomputes the RBAUGMENTED datas */ -#define RB_DECLARE_CALLBACKS (RBSTATIC ,RBNAME , \ -RBSTRUCT ,RBFIELD ,RBAUGMENTED ,RBCOMPUTE ) \ +#define RB_DECLARE_CALLBACKS_MULTI (RBSTATIC ,RBNAME , \ +RBSTRUCT ,RBFIELD ,RBCOPY ,RBCOMPUTE ) \ static inline void \ RBNAME ## _propagate(struct rb_node *rb, struct rb_node *stop) \ { \
@@ -114,14 +114,14 @@ RBNAME ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ { \RBSTRUCT *old =rb_entry (rb_old,RBSTRUCT ,RBFIELD ); \RBSTRUCT *new =rb_entry (rb_new,RBSTRUCT ,RBFIELD ); \ - new->RBAUGMENTED = old->RBAUGMENTED; \ +RBCOPY (new, old); \ } \static void \ RBNAME ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ { \RBSTRUCT *old =rb_entry (rb_old,RBSTRUCT ,RBFIELD ); \RBSTRUCT *new =rb_entry (rb_new,RBSTRUCT ,RBFIELD ); \ - new->RBAUGMENTED = old->RBAUGMENTED; \ +RBCOPY (new, old); \RBCOMPUTE (old, false); \ } \ RBSTATIC const struct rb_augment_callbacks RBNAME = { \
@@ -130,6 +130,27 @@ RBSTATIC const struct rb_augment_callbacks RBNAME = { \ .rotate = RBNAME ## _rotate \ }; +/* +* Template for declaring augmented rbtree callbacks (generic single field) +* +* RBSTATIC: 'static' or empty +* RBNAME: name of the rb_augment_callbacks structure +* RBSTRUCT: struct type of the tree nodes +* RBFIELD: name of struct rb_node field within RBSTRUCT +* RBAUGMENTED: name of field within RBSTRUCT holding data for subtree +* RBCOMPUTE: name of function that recomputes the RBAUGMENTED data +*/ + +#define RB_DECLARE_CALLBACKS (RBSTATIC ,RBNAME , \ +RBSTRUCT ,RBFIELD ,RBAUGMENTED ,RBCOMPUTE ) \ +static inline void \ +RBNAME ## _copy_single(RBSTRUCT *new, RBSTRUCT *old) \ +{ \ + new->RBAUGMENTED = old->RBAUGMENTED; \ +} \ +RB_DECLARE_CALLBACKS_MULTI(RBSTATIC, RBNAME, \ + RBSTRUCT, RBFIELD, RBNAME ## _copy_single, RBCOMPUTE) +/* * Template for declaring augmented rbtree callbacks, * computing RBAUGMENTED scalar as max(RBCOMPUTE(node)) for all subtree nodes.
kernel/sched/fair.c +10 -2
@@ -1004,6 +1004,13 @@ static inline void __max_slice_update(struct sched_entity *se, struct rb_node *n } } +static inline void min_vruntime_copy (struct sched_entity *new,struct sched_entity *old) +{ + new->min_vruntime = old->min_vruntime; + new->min_slice = old->min_slice; + new->max_slice = old->max_slice; +} +/* * se->min_vruntime = min(se->vruntime, {left,right}->min_vruntime) */
@@ -1031,8 +1038,9 @@ static inline bool min_vruntime_update(struct sched_entity *se, bool exit) se->max_slice == old_max_slice; } -RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity, - run_node, min_vruntime, min_vruntime_update); + +RB_DECLARE_CALLBACKS_MULTI(static, min_vruntime_cb, struct sched_entity, + run_node, min_vruntime_copy, min_vruntime_update);/* * Enqueue an entity into the rb-tree:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 418/733 sched: Account cgroup CPU time to the execution context
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Su <[email protected]>
[ Upstream commit c23810313bdf6b02f39a1f2a1464c4b18bd39e31 ]
Proxy execution separates the scheduling context from the execution context. Commit aa4f74dfd42b ("sched: Fix runtime accounting w/ split exec & sched contexts") made per-task and thread-group runtime accounting follow the task that actually executes, while cgroup CPU usage is charged to the donor.
When the donor and execution task belong to different cgroups, this makes a task's execution time count against a different cgroup from the one the task belongs to.
Cgroup CPU usage should follow the execution context, matching the per-task, thread-group, and cgroup user/system accounting. Keep scheduling state associated with the donor, but charge cgroup CPU usage to rq->curr.
A reproducer with the donor and execution task in separate cgroups showed the execution task accumulating runtime while cgroup CPU usage was charged to the donor's cgroup. With this change, the execution task's cgroup accumulates the CPU usage instead. The same behavior was verified with an RT donor and with legacy cpuacct accounting.
--- kernel/sched/fair.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
kernel/sched/fair.c +1 -3
@@ -1373,7 +1373,6 @@ static s64 update_se(struct rq *rq, struct sched_entity *se) se->exec_start = now;if (entity_is_task (se)) { -struct task_struct *donor =task_of (se);struct task_struct *running = rq->curr;/* * If se is a task, we account the time against the running
@@ -1386,8 +1385,7 @@ static s64 update_se(struct rq *rq, struct sched_entity *se)account_group_exec_runtime (running, delta_exec);account_mm_sched (rq, running, delta_exec); -/* cgroup time is always accounted against the donor */ -cgroup_account_cputime (donor, delta_exec); +cgroup_account_cputime (running, delta_exec); }else {/* If not task, account the time against donor se */ se->sum_exec_runtime += delta_exec;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 419/733 sched/core: Call wq_worker_tick() for the execution context
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Su <[email protected]>
[ Upstream commit f5741d2b34519d387edf6e9798fc7030c20a35f3 ]
wq_worker_tick() accounts CPU time and detects CPU-intensive work for the kworker that is actually running. With proxy execution, rq->donor is the scheduling context while rq->curr is the execution context.
Calling the hook with rq->donor can skip workqueue accounting when a kworker is executing on behalf of a donor task. It can also account a blocked kworker when the donor is a worker but rq->curr is the task actually executing. The former can delay WORKER_CPU_INTENSIVE handling and pool concurrency management, which can delay pending kernel work and userspace operations depending on it.
Use rq->curr for the workqueue tick hook while retaining rq->donor for scheduler accounting.
--- kernel/sched/core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
kernel/sched/core.c +5 -4
@@ -5780,8 +5780,8 @@ void sched_tick(void) {int cpu =smp_processor_id ();struct rq *rq =cpu_rq (cpu); -/* accounting goes to the donor task */ -struct task_struct *donor; +/* scheduler accounting goes to the donor task */ +struct task_struct *curr, *donor;struct rq_flags rf;unsigned long hw_pressure;u64 resched_latency;
@@ -5792,6 +5792,7 @@ void sched_tick(void)sched_clock_tick ();rq_lock (rq, &rf); + curr = rq->curr; donor = rq->donor;psi_account_irqtime (rq, donor,NULL );
@@ -5817,8 +5818,8 @@ void sched_tick(void)perf_event_task_tick (); -if (donor->flags &PF_WQ_WORKER ) -wq_worker_tick (donor); +if (curr->flags &PF_WQ_WORKER ) +wq_worker_tick (curr);if (!scx_switched_all ()) { rq->idle_balance =idle_cpu (cpu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 420/733 net/sched: cls_route: free emptied bucket on filter move
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit 1853f30cf5c84971f99788a76207c6f745380896 ]
route4_change can move an existing filter to a different top-level
bucket: route4_set_parms recomputes the handle from TCA_ROUTE4_TO/ FROM/IIF, and the handle-mismatch check is gated on the 'new' flag, so for an existing filter the new handle may differ from the old one and land in a different bucket. When this happens, the filter is unlinked from the old bucket, but the bucket itself is never freed once it goes empty. The stale empty bucket remains in head->table[], causing route4_delete to report *last=false even after the last live filter is gone. That pins the empty tcf_proto and causes a leak.
Fix this by refcounting the filters linked to a bucket and freeing the bucket when the count drops to zero. The existing scan in route4_delete goes away with it.
The count is updated at all sites that link or unlink a filter during add, change and delete, and the bucket is dropped from head->table[] as soon as it reaches zero.
Conditions to recreate the bug:
CONFIG_NET_CLS_ROUTE4=y, CONFIG_NET_SCH_INGRESS=y, CONFIG_NET_CLS_ACT=y.
tc qdisc replace dev lo clsact
tc filter add dev lo ingress protocol ip pref 100 route from 1 to 1 tc filter change dev lo ingress protocol ip pref 100 handle 0x10001 \
route from 1 to 2
tc filter del dev lo ingress protocol ip pref 100 handle 0x10002 \
route from 1 to 2
tc filter show dev lo ingress | grep -c 'pref 100 route chain 0 '
--- net/sched/cls_route.c | 45 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 23 deletions(-)
net/sched/cls_route.c +22 -23
@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/refcount.h> #include <linux/skbuff.h> #include <net/dst.h> #include <net/route.h>
@@ -41,6 +42,7 @@ struct route4_head {struct route4_bucket {/* 16 FROM buckets + 16 IIF buckets + 1 wildcard bucket */ struct route4_filter __rcu *ht[16 +16 +1 ]; +refcount_t filters_ref;struct rcu_head rcu; };
@@ -336,7 +338,7 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,struct route4_filter *nf;struct route4_bucket *b;unsigned int h =0 ; -int i, h1; +int h1;if (!head || !f)return -EINVAL ;
@@ -362,23 +364,14 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,tcf_exts_get_net (&f->exts);tcf_queue_work (&f->rwork, route4_delete_filter_work); -/* Strip RTNL protected tree */ -for (i =0 ; i <=32 ; i++) { -struct route4_filter *rt; - - rt =rtnl_dereference (b->ht[i]); -if (rt) - goto out; +if (refcount_dec_and_test (&b->filters_ref)) { +RCU_INIT_POINTER (head->table[to_hash (h)],NULL ); +kfree_rcu (b, rcu); } - -/* OK, session has no flows */ -RCU_INIT_POINTER (head->table[to_hash (h)],NULL ); -kfree_rcu (b, rcu);break ; } } -out: *last = true;for (h1 =0 ; h1 <=256 ; h1++) {if (rcu_access_pointer (head->table[h1])) {
@@ -459,6 +452,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,if (b ==NULL )return -ENOBUFS ; +refcount_set (&b->filters_ref,1 );rcu_assign_pointer (head->table[h1], b); }else {unsigned int h2 =from_hash (nhandle >>16 );
@@ -468,6 +462,8 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp, fp = rtnl_dereference(fp->next))if (fp->handle == f->handle)return -EEXIST ; + +refcount_inc (&b->filters_ref); }if (tb[TCA_ROUTE4_TO ])
@@ -500,7 +496,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,struct route4_filter *fold, *f1, *pfp, *f =NULL ;struct route4_bucket *b;struct nlattr *tb[TCA_ROUTE4_MAX +1 ]; -unsigned int h, th; +unsigned int h;int err;bool new = true;
@@ -560,17 +556,20 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,rcu_assign_pointer (*fp, f);if (fold) { - th =to_hash (fold->handle); + b = fold->bkt; h =from_hash (fold->handle >>16 ); - b =rtnl_dereference (head->table[th]); -if (b) { - fp = &b->ht[h]; -for (pfp =rtnl_dereference (*fp); pfp; - fp = &pfp->next, pfp =rtnl_dereference (*fp)) { -if (pfp == fold) { -rcu_assign_pointer (*fp, fold->next); -break ; + fp = &b->ht[h]; +for (pfp =rtnl_dereference (*fp); pfp; + fp = &pfp->next, pfp =rtnl_dereference (*fp)) { +if (pfp == fold) { +rcu_assign_pointer (*fp, fold->next); +if (refcount_dec_and_test (&b->filters_ref)) { +unsigned int th =to_hash (fold->handle); + +RCU_INIT_POINTER (head->table[th],NULL ); +kfree_rcu (b, rcu); } +break ; } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 421/733 net/sched: cls_route: Reject handle aliasing
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit b74a8455a2f271f54695b6a8ec1f113824a46c0e ]
route4_set_parms() rejects a duplicate by scanning the destination chain for f->handle, but f->handle is the handle the filter has before the update, not the one it is about to be linked under. The comparison and the insertion therefore use different handles, which causes breakage.
When a change moves the filter to a chain that already holds nhandle, the scan looks for the old handle instead, misses the collision and links a second filter with the same handle:
tc filter add dev lo ingress protocol ip pref 100 \
route from 1 to 1 classid 1:1 action ok
tc filter add dev lo ingress protocol ip pref 100 \
route from 2 to 2 classid 1:2 action drop
tc filter change dev lo ingress protocol ip pref 100 handle 0x10001 \
route from 2 to 2 classid 1:1 action ok
tc filter show dev lo ingress
... fh 0x00020002 flowid 1:2 to 2 from 2
... fh 0x00020002 flowid 1:1 to 2 from 2
The newcomer is appended after the incumbent, and both end up with the same f->id. route4_get() returns the first match, so the second filter can no longer be addressed by handle, and route4_classify() stops at the first filter whose f->id matches. The second filter is dumped but is effectively dead.
Fix this by comparing against nhandle.
--- net/sched/cls_route.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/sched/cls_route.c +5 -1
@@ -460,8 +460,12 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,for (fp =rtnl_dereference (b->ht[h2]); fp; fp =rtnl_dereference (fp->next)) -if (fp->handle == f->handle) +if (fp->handle == nhandle) { +NL_SET_ERR_MSG_FMT (extack, +"Handle %x is already in use" , + nhandle);return -EEXIST ; + }refcount_inc (&b->filters_ref); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 422/733 net/sched: cls_route: Fix in-place replace
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit 41e85e54e5649a1617698438b0ce64c6f9d83d69 ]
Building on the previous patch, route4_set_parms rejects a duplicate by scanning the destination chain for nhandle, but the scan doesn't exclude the older version it is replacing, so an in-place replace will match the older version's handle and fail.
Fix this by passing the older filter as a parameter to route4_set_parms (replacing "new") and skipping it in the scan.
Excluding the older version is not enough on its own. nhandle is built out of TCA_ROUTE4_TO, TCA_ROUTE4_FROM and TCA_ROUTE4_IIF alone, while the 0x7F00 bits, which only tell apart filters sharing one key, are folded in on the create path. Letting the replace through would therefore rename the filter it replaces: replacing handle 0x10101 stored it back as 0x10001, and a sibling at 0x10201 could then no longer be replaced at all, since its own nhandle collided with the renamed filter.
tc filter add ... handle 0x10101 route from 1 to 1 classid 1:1 tc filter add ... handle 0x10201 route from 1 to 1 classid 1:2 tc filter replace ... handle 0x10101 route from 1 to 1 classid 1:9 ... fh 0x00010001 flowid 1:9 to 1 from 1 ... fh 0x00010201 flowid 1:2 to 1 from 1 tc filter replace ... handle 0x10201 route from 1 to 1 classid 1:8 Error: Handle 10001 is already in use.
So carry those bits over when the key the request builds is the key the older filter already has. An in-place replace then keeps the handle userspace named the filter by, while a request that does change the key still renames it, as it did before.
--- net/sched/cls_route.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-)
net/sched/cls_route.c +13 -14
@@ -393,8 +393,9 @@ static const struct nla_policy route4_policy[TCA_ROUTE4_MAX + 1] = {static int route4_set_parms (struct net *net,struct tcf_proto *tp,unsigned long base,struct route4_filter *f,u32 handle,struct route4_head *head, -struct nlattr **tb,struct nlattr *est,int new, -u32 flags,struct netlink_ext_ack *extack) +struct nlattr **tb,struct nlattr *est, +struct route4_filter *fold,u32 flags, +struct netlink_ext_ack *extack) {u32 id =0 , to =0 , nhandle =0x8000 ;struct route4_filter *fp;
@@ -407,7 +408,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,return err;if (tb[TCA_ROUTE4_TO ]) { -if (new && handle &0x8000 ) { +if (!fold && handle &0x8000 ) {NL_SET_ERR_MSG (extack,"Invalid handle" );return -EINVAL ; }
@@ -430,14 +431,14 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp, }else nhandle |=0xFFFF <<16 ; -if (handle && new) { +if (handle && (!fold || nhandle == (handle & ~0x7F00 ))) nhandle |= handle &0x7F00 ; -if (nhandle != handle) { -NL_SET_ERR_MSG_FMT (extack, -"Handle mismatch constructed: %x (expected: %x)" , - handle, nhandle); -return -EINVAL ; - } + +if (handle && !fold && nhandle != handle) { +NL_SET_ERR_MSG_FMT (extack, +"Handle mismatch constructed: %x (expected: %x)" , + handle, nhandle); +return -EINVAL ; }if (!nhandle) {
@@ -460,7 +461,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,for (fp =rtnl_dereference (b->ht[h2]); fp; fp =rtnl_dereference (fp->next)) -if (fp->handle == nhandle) { +if (fp != fold && fp->handle == nhandle) {NL_SET_ERR_MSG_FMT (extack,"Handle %x is already in use" , nhandle);
@@ -502,7 +503,6 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,struct nlattr *tb[TCA_ROUTE4_MAX +1 ];unsigned int h;int err; -bool new = true;if (!handle) {NL_SET_ERR_MSG (extack,"Creating with handle of 0 is invalid" );
@@ -539,11 +539,10 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, f->tp = fold->tp; f->bkt = fold->bkt; - new = false; } err =route4_set_parms (net, tp, base, f, handle, head, tb, - tca[TCA_RATE ], new, flags, extack); + tca[TCA_RATE ], fold, flags, extack);if (err <0 ) goto errout;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 423/733 net/sched: cls_api: Dont replay RTM_GETCHAIN in tc_ctl_chain().
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit dff39930ad5e53d202bfdfb14687d1d2fd753b4d ]
If a netlink socket sends RTM_GETCHAIN requests repeatedly without recv()ing the responses, tc_ctl_chain() hogs CPU and triggers Hung Task splat. [0]
As caught in the stack trace, netlink_attachskb() could confuse tc_ctl_chain() by returning -EAGAIN when the userspace netlink socket's receive buffer is full.
The replay: label exists since commit 32a4f5ecd738 ("net: sched:
introduce chain object to uapi") but was not used initially.
Since commit 9f407f1768d3 ("net: sched: introduce chain templates"), the label is needed for RTM_NEWCHAIN because tcf_proto_lookup_ops() may release RTNL to call request_module().
However, the replay logic is unnecessary for RTM_GETCHAIN.
Let's apply the replay logic only for RTM_NEWCHAIN.
[0]:
INFO: task repro:1018 is blocked on a mutex likely owned by task repro:1022. task:repro state:R running task stack:14096 pid:1022 tgid:1014 ppid:961 task_flags:0x400040 flags:0x00080000 Call Trace: <TASK> ? clockevents_program_event (kernel/time/clockevents.c:372) ? pskb_expand_head (net/core/skbuff.c:615) ? skb_release_data (net/core/skbuff.c:1122) ? netlink_attachskb (./include/linux/skbuff.h:1323 ./include/linux/skbuff.h:1332 net/netlink/af_netlink.c:1232) ? __netlink_lookup (./include/linux/rcupdate.h:882 ./include/linux/rhashtable.h:711 net/netlink/af_netlink.c:499) ? tc_chain_notify (net/sched/cls_api.c:3045) ? tc_chain_notify (./include/linux/skbuff.h:1384 net/sched/cls_api.c:3041) ? netlink_unicast (net/netlink/af_netlink.c:1335) ? rtnl_unicast (./include/net/netlink.h:1198 net/core/rtnetlink.c:985) ? tc_ctl_chain (net/sched/cls_api.c:3242) ? rtnetlink_rcv_msg (net/core/rtnetlink.c:7146) ? netlink_unicast (net/netlink/af_netlink.c:1354) ? __pfx_rtnetlink_rcv_msg (net/core/rtnetlink.c:7177) ? netlink_rcv_skb (net/netlink/af_netlink.c:2556) ? netlink_unicast (net/netlink/af_netlink.c:1319) ? netlink_sendmsg (net/netlink/af_netlink.c:1900) ? __sock_sendmsg (net/socket.c:800) ? __sys_sendto (net/socket.c:2281) ? __x64_sys_sendto (net/socket.c:2288 net/socket.c:2284 net/socket.c:2284) ? do_syscall_64 (arch/x86/entry/syscall_64.c:61 arch/x86/entry/syscall_64.c:84) ? entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) </TASK>
--- net/sched/cls_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/cls_api.c +1 -1
@@ -3254,7 +3254,7 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,tcf_chain_put (chain); errout_block:tcf_block_release (q, block, true); -if (err == -EAGAIN ) +if (err == -EAGAIN && n->nlmsg_type ==RTM_NEWCHAIN )/* Replay the request. */ goto replay;return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 424/733 net: sun4i-emac: fix missing of_node_put() for phy_node
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Youhong <[email protected]>
[ Upstream commit af406abfecad2f48d8f1fc646d3994f0982bac62 ]
of_parse_phandle() returns a node pointer with an elevated refcount. Add the missing of_node_put() on the probe error path after register_netdev() fails and in emac_remove().
--- drivers/net/ethernet/allwinner/sun4i-emac.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/allwinner/sun4i-emac.c +2 -0
@@ -1067,6 +1067,7 @@ static int emac_probe(struct platform_device *pdev)return 0 ; out_release_sram: +of_node_put (db->phy_node);sunxi_sram_release (&pdev->dev); out_clk_disable_unprepare:clk_disable_unprepare (db->clk);
@@ -1094,6 +1095,7 @@ static void emac_remove(struct platform_device *pdev) }unregister_netdev (ndev); +of_node_put (db->phy_node);sunxi_sram_release (&pdev->dev);clk_disable_unprepare (db->clk);irq_dispose_mapping (ndev->irq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 425/733 net: hinic: fix mailbox segment buffer overflow
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aamir Ahmed <[email protected]>
[ Upstream commit 5d4d985957434867bbe85e4fa5e638f3e48ad522 ]
check_mbox_seq_id_and_seg_len() validates that seq_id does not exceed SEQ_ID_MAX_VAL (42) and seg_len does not exceed MBOX_SEG_LEN (48). However, this allows the last segment (seq_id=42) to carry a full 48-byte payload, writing to offset 42*48=2016 for 48 bytes (ending at byte 2064). The receive buffer is only MBOX_MAX_BUF_SZ (2048) bytes, resulting in a 16-byte heap buffer overflow.
The hinic3 driver already handles this correctly by defining MBOX_LAST_SEG_MAX_LEN and rejecting the last segment when it exceeds the remaining buffer space. Apply the same fix to the hinic driver.
--- drivers/net/ethernet/huawei/hinic/hinic_hw_mbox.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/ethernet/huawei/hinic/hinic_hw_mbox.c +3 -1
@@ -128,6 +128,7 @@ enum hinic_mbox_tx_status {#define SEQ_ID_START_VAL 0#define SEQ_ID_MAX_VAL 42 +#define MBOX_LAST_SEG_MAX_LEN (MBOX_MAX_BUF_SZ - SEQ_ID_MAX_VAL * MBOX_SEG_LEN)#define NO_DMA_ATTRIBUTE_VAL 0
@@ -372,7 +373,8 @@ recv_pf_from_vf_mbox_handler(struct hinic_mbox_func_to_func *func_to_func,static bool check_mbox_seq_id_and_seg_len (struct hinic_recv_mbox *recv_mbox,u8 seq_id,u8 seg_len) { -if (seq_id >SEQ_ID_MAX_VAL || seg_len >MBOX_SEG_LEN ) +if (seq_id >SEQ_ID_MAX_VAL || seg_len >MBOX_SEG_LEN || + (seq_id ==SEQ_ID_MAX_VAL && seg_len >MBOX_LAST_SEG_MAX_LEN ))return false;if (seq_id ==0 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 426/733 net: dsa: mt7530: add EN7528 support
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahmed Naseef <[email protected]>
[ Upstream commit cf23fcc9437e5c383d9f282197d580a5a3fd6e6e ]
The EcoNet EN7528 SoC integrates an MT7530 switch (the chip revision register reads 0x7530), memory-mapped in the SoC register space and reached through the same MMIO glue used for the built-in switches of the MediaTek MT7988 and Airoha EN7581/AN7583 SoCs. Its reset sequence and its PHY indirect access registers are the same as on those switches, so add an ID_EN7528 variant bound with the "econet,en7528-switch" compatible, reusing mt7988_setup() and the indirect PHY accessors.
The switch core, however, is an MT7530 and not an MT7531 derivative: the CPU port to trap frames to is set through the MT7530-style CPU_EN / CPU_PORT fields of the MFC register rather than the MT7531 CFC register, so add it to the MT7530 handling in mt753x_conduit_state_change(). For the same reason the MT7530 mirror and force-mode register layouts already apply to it as the default of the MT753X_*() macros.
The four user ports (1-4) are connected to integrated Gigabit PHYs at MDIO addresses 9-12 of the switch internal MDIO bus. The CPU port (port
6) is connected to the SoC Ethernet MAC at a fixed 1000 Mbps full duplex link, so the port capabilities cannot be shared with the MT7988 and EN7581 switches, whose CPU ports run at 10 Gbps.
The LAN GPHYs advertise EEE by default, but negotiating EEE with some link partners results in an unstable link with dropped frames. Leave the LPI capabilities empty for the EN7528 so that phylink disables EEE on these PHYs and refuses to enable it from userspace.
Stable-dep-of: 3c18e3c9a54e ("net: dsa: mt7530: populate lpi_interfaces to fix EEE support")
--- drivers/net/dsa/mt7530-mmio.c | 1 + drivers/net/dsa/mt7530.c | 58 ++++++++++++++++++++++++++++++----- drivers/net/dsa/mt7530.h | 1 + 3 files changed, 52 insertions(+), 8 deletions(-)
drivers/net/dsa/mt7530-mmio.c +1 -0
@@ -12,6 +12,7 @@static const struct of_device_id mt7988_of_match[] = { { .compatible ="airoha,an7583-switch" , .data = &mt753x_table[ID_AN7583 ], }, { .compatible ="airoha,en7581-switch" , .data = &mt753x_table[ID_EN7581 ], }, + { .compatible ="econet,en7528-switch" , .data = &mt753x_table[ID_EN7528 ], }, { .compatible ="mediatek,mt7988-switch" , .data = &mt753x_table[ID_MT7988 ], }, {/* sentinel */ }, };
drivers/net/dsa/mt7530.c +50 -8
86 lines not on this page · raw message
drivers/net/dsa/mt7530.h +1 -0
@@ -21,6 +21,7 @@ enum mt753x_id {ID_MT7988 =3 ,ID_EN7581 =4 ,ID_AN7583 =5 , + ID_EN7528 = 6, };#define NUM_TRGMII_CTRL 5
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 427/733 net: dsa: mt7530: populate lpi_interfaces to fix EEE support
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksei Sviridkin <[email protected]>
[ Upstream commit 3c18e3c9a54e1239b72849502ca4737604bfbb46 ]
phylink_create() decides once and for all that a MAC supports managed EEE, and it requires the tx_lpi ops plus non-empty lpi_capabilities and lpi_interfaces. mt753x_phylink_get_caps() leaves lpi_interfaces empty.
So ever since the conversion to phylink managed EEE, ethtool has answered "Not supported" on every mt753x port, and phy_disable_eee() has locked userspace out of turning EEE on. That undoes what commit 06dfcd4098cf ("net: dsa: mt7530: fix enabling EEE on MT7531 switch on all boards") arranged: EEE off by default, but reachable with ethtool.
Leave the speeds above 1 Gbps out of both bitmaps. PMCR folds SPEED_2500 and SPEED_10000 onto PMCR_FORCE_SPEED_1000, so PMCR_FORCE_EEE1G would govern LPI on such a link, and that is unvalidated rather than known unsupported: MediaTek's SDK driver sets the EEE force bits for 100 Mbps and 1 Gbps only, and the unit of the wakeup timers is undocumented with the port clock at 2.5 times the rate.
LPI stays off until userspace enables it, but the EEE advertisement of a PHY that advertises it out of reset comes back, since phylink stops force-clearing it.
--- drivers/net/dsa/mt7530.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
drivers/net/dsa/mt7530.c +12 -4
@@ -3118,23 +3118,31 @@ static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port, config->mac_capabilities =MAC_ASYM_PAUSE |MAC_SYM_PAUSE ; + priv->info->mac_port_get_caps (ds, port, config); +/* The EN7528 GPHYs report EEE capability, but negotiating EEE with * common link partners (e.g. Realtek GbE NICs) results in an unstable * link with dropped frames. Leave the LPI capabilities empty so that * phylink disables EEE on these PHYs and refuses to enable it from * userspace. */ -if (priv->id !=ID_EN7528 ) { +if (priv->id !=ID_EN7528 && + config->mac_capabilities & (MAC_100FD |MAC_1000FD )) {u32 eeecr =mt7530_read (priv,MT753X_PMEEECR_P (port)); - config->lpi_capabilities =MAC_100FD |MAC_1000FD |MAC_2500FD ; +/* LPI above 1 Gbps is not supported */ + config->lpi_capabilities = config->mac_capabilities & + (MAC_100FD |MAC_1000FD ); +phy_interface_copy (config->lpi_interfaces, + config->supported_interfaces); +__clear_bit (PHY_INTERFACE_MODE_2500BASEX , + config->lpi_interfaces); +/* tx_lpi_timer should be in microseconds. The time units for * LPI threshold are unspecified. */ config->lpi_timer_default =FIELD_GET (LPI_THRESH_MASK , eeecr); } - - priv->info->mac_port_get_caps (ds, port, config); } static int mt753x_pcs_validate(struct phylink_pcs *pcs,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 428/733 net: ethernet: mtk_eth_soc: populate lpi_interfaces to fix EEE support
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksei Sviridkin <[email protected]>
[ Upstream commit d876c9cb2d16ed259449fe9da08c37a5cb81d724 ]
phylink_create() decides once and for all that a MAC supports managed EEE, and it requires the tx_lpi ops plus non-empty lpi_capabilities and lpi_interfaces. mtk_add_mac() leaves lpi_interfaces empty.
So ever since EEE support was added, ethtool has answered "Not supported" on every MAC that uses mtk_phylink_ops, and phy_disable_eee() has locked userspace out of turning EEE on. MT7628 is unaffected, as rt5350_phylink_ops has no tx_lpi methods.
Leave 2.5 Gbps out of both bitmaps, and the xGMII modes that mtk_mac_enable_tx_lpi() already refuses. MAC_MCR folds SPEED_2500 onto MAC_MCR_SPEED_1000, so MAC_MCR_EEE1G would govern LPI on such a link, and that is unvalidated rather than known unsupported: MediaTek's SDK driver sets the EEE force bits for 100 Mbps and 1 Gbps only, and the unit of the wakeup timers is undocumented with the port clock at 2.5 times the rate.
mtk_mac_enable_tx_lpi() programs wake-up times taken from MT7531's reset values, and the SoC's own field has no reset value to fall back on. Only MT7981 has been seen to exit LPI cleanly with them, so the LPI interfaces sit behind a new MTK_GMAC_EEE capability that only MT7981 sets; every other SoC keeps the current behaviour until it has been confirmed.
LPI stays off until userspace enables it, but the EEE advertisement of a PHY that advertises it out of reset comes back, since phylink stops force-clearing it.
--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 18 +++++++++++++++--- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 +++- 2 files changed, 18 insertions(+), 4 deletions(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +15 -3
@@ -4827,7 +4827,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)phy_interface_t phy_mode;struct phylink *phylink;struct mtk_mac *mac; -int id, err; +int id, err, i;int txqs =1 ;u32 val;
@@ -4906,8 +4906,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) mac->phylink_config.type =PHYLINK_NETDEV ; mac->phylink_config.mac_capabilities =MAC_ASYM_PAUSE |MAC_SYM_PAUSE |MAC_10 |MAC_100 |MAC_1000 |MAC_2500FD ; - mac->phylink_config.lpi_capabilities =MAC_100FD |MAC_1000FD | -MAC_2500FD ; +/* LPI above 1 Gbps is not supported */ + mac->phylink_config.lpi_capabilities =MAC_100FD |MAC_1000FD ; mac->phylink_config.lpi_timer_default =1000 ;/* MT7623 gmac0 is now missing its speed-specific PLL configuration
@@ -4965,6 +4965,18 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)__set_bit (PHY_INTERFACE_MODE_INTERNAL , mac->phylink_config.supported_interfaces); +/* LPI wake-up timing is only verified on MTK_GMAC_EEE SoCs */ +if (MTK_HAS_CAPS (eth->soc->caps,MTK_GMAC_EEE )) { +phy_interface_copy (mac->phylink_config.lpi_interfaces, + mac->phylink_config.supported_interfaces); +__clear_bit (PHY_INTERFACE_MODE_2500BASEX , + mac->phylink_config.lpi_interfaces); +for (i =0 ; i <PHY_INTERFACE_MODE_MAX ; i++) +if (mtk_interface_mode_is_xgmii (eth, i)) +__clear_bit (i, + mac->phylink_config.lpi_interfaces); + } + phylink =phylink_create (&mac->phylink_config,of_fwnode_handle (mac->of_node), phy_mode, mac_ops);
drivers/net/ethernet/mediatek/mtk_eth_soc.h +3 -1
@@ -994,6 +994,7 @@ enum mkt_eth_capabilities {MTK_U3_COPHY_V2_BIT ,MTK_SRAM_BIT ,MTK_36BIT_DMA_BIT , +MTK_GMAC_EEE_BIT ,/* MUX BITS*/ MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
@@ -1034,6 +1035,7 @@ enum mkt_eth_capabilities {#define MTK_U3_COPHY_V2 BIT_ULL(MTK_U3_COPHY_V2_BIT)#define MTK_SRAM BIT_ULL(MTK_SRAM_BIT)#define MTK_36BIT_DMA BIT_ULL(MTK_36BIT_DMA_BIT) +#define MTK_GMAC_EEE BIT_ULL(MTK_GMAC_EEE_BIT)#define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ BIT_ULL(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
@@ -1117,7 +1119,7 @@ enum mkt_eth_capabilities {#define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \ - MTK_RSTCTRL_PPE1 | MTK_SRAM) + MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_GMAC_EEE)#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 429/733 net: phy: mediatek-ge: disable EEE on the MT7530 PHY
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladislav Karmanov <[email protected]>
[ Upstream commit ccbe7540e4aad0d1c3acc249697350b93ccb8025 ]
The MT7530 internal GE PHY advertises EEE by hardware default, but its EEE support is defective: with EEE advertised, some link partners fail to establish a stable link. On a 2-pair (4-wire) cable where both ends advertise gigabit, 1000BASE-T training cannot succeed, and instead of falling back to 100 Mbps the port loops, so no link or DHCP lease is ever obtained. MediaTek confirms the hardware is the root cause (Landen Chao, 2021): "EEE of the 10-year-old MT7530 internal gephy has many IOT problems, so it is recommended to disable its EEE."
mtk_gephy_config_init() used to clear the EEE advertisement early, but commit af3b4b0e59de ("net: phy: mediatek-ge: do not disable EEE advertisement") removed that on the rationale that the DSA subdriver already performs an early disable. That holds for MT7531, whose mt7531_setup() clears MDIO_AN_EEE_ADV on each switch PHY, but not for the MT7530 PHY: neither the MT7621 integrated switch nor the dedicated MT7530 IC ever had such a loop, so removing it left those boards without any working early EEE disable and the link flapping came back.
Since the broken hardware is the PHY, fix it in the PHY driver so it covers all users of this PHY, integrated in a switch or standalone:
- clear MDIO_AN_EEE_ADV in probe(), as early as possible, before
anything can negotiate EEE with the link partner;
- clear it again in config_init() and call phy_disable_eee() there. config_init() is what phy_init_hw() replays after a PHY reset, when the register is back at its EEE-advertising hardware default, and it runs after of_set_phy_eee_broken() in phy_probe(), so the eee_disabled_modes mask survives and neither phylib nor userspace can re-enable EEE. dp83867 disables broken EEE from config_init() the same way.
Auto-negotiation then falls back to a stable 100 Mbps link instead of looping at gigabit. Tested on ASUS RT-AX53U (MT7621): with a 2-pair cable on the WAN port, a single clean 100 Mbps link comes up and a DHCP lease is obtained, where the unpatched driver loops.
--- drivers/net/phy/mediatek/mtk-ge.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
drivers/net/phy/mediatek/mtk-ge.c +29 -0
@@ -62,10 +62,38 @@ static void mtk_gephy_config_init(struct phy_device *phydev) FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3)); } +static int mt7530_phy_probe (struct phy_device *phydev) +{ +/* The MT7530 internal GE PHY has broken EEE: with EEE advertised, +* some link partners fail to establish a stable link (on a 2-pair +* cable, 1000BASE-T training fails and the port loops instead of +* falling back). MediaTek recommends disabling EEE on this PHY. +* Clear the advertisement as early as possible, before anything +* can negotiate EEE with the link partner. +*/ +return phy_write_mmd (phydev,MDIO_MMD_AN ,MDIO_AN_EEE_ADV ,0 ); +} +static int mt7530_phy_config_init (struct phy_device *phydev) { +int ret; +mtk_gephy_config_init (phydev); +/* The probe() clear alone is not durable: phy_init_hw() replays only +* ->config_init after a PHY reset, with the register back at its +* EEE-advertising hardware default, and phy_probe() zeroes +* eee_disabled_modes (of_set_phy_eee_broken()) after ->probe already +* ran. Clear the advertisement again and mark EEE disabled, so that +* neither phylib nor userspace can re-enable it; dp83867 disables +* broken EEE from config_init() the same way. +*/ + ret =phy_write_mmd (phydev,MDIO_MMD_AN ,MDIO_AN_EEE_ADV ,0 ); +if (ret) +return ret; + +phy_disable_eee (phydev); +/* Increase post_update_timer */ phy_write_paged (phydev,MTK_PHY_PAGE_EXTENDED_3 ,MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 ,0x4b );
@@ -100,6 +128,7 @@ static struct phy_driver mtk_gephy_driver[] = { { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530), .name = "MediaTek MT7530 PHY", + .probe = mt7530_phy_probe, .config_init = mt7530_phy_config_init,/* Interrupts are handled by the switch, not the PHY * itself.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 430/733 net: net_failover: Fix the deadlock in net_failover_slave_name_change()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Faicker Mo <[email protected]>
[ Upstream commit 985a663bf00799c1daf1c5789efa6406958780c8 ]
This is a sibling fix of commitb84c5632c7b3 ("net: net_failover: Fix the deadlock in slave register"). There is netdev_lock_ops() in the upper callers, so using netif_open() instead of dev_open().
Call Trace: __schedule+0x2bb/0x650 schedule+0x27/0xb0 schedule_preempt_disabled+0x15/0x30 __mutex_lock.constprop.0+0x550/0xaf0 __mutex_lock_slowpath+0x13/0x20 mutex_lock+0x3b/0x50 dev_open+0x3b/0xe0 net_failover_slave_name_change+0x22/0x40 failover_event+0xd4/0x1e0 notifier_call_chain+0x62/0xf0 raw_notifier_call_chain+0x16/0x30 call_netdevice_notifiers_info+0x50/0x80 netif_change_name+0x200/0x330 do_setlink.isra.0+0xb12/0xdf0 ? security_capable+0x9a/0x1e0 ? ns_capable+0x31/0x60 rtnl_setlink+0x302/0x670 ? netlink_recvmsg+0x296/0x340 ? security_capable+0x9a/0x1e0 ? __pfx_rtnl_setlink+0x10/0x10 rtnetlink_rcv_msg+0x384/0x460 ? __pfx_rtnetlink_rcv_msg+0x10/0x10 netlink_rcv_skb+0x61/0x120 rtnetlink_rcv+0x15/0x30 netlink_unicast+0x28f/0x3c0 netlink_sendmsg+0x216/0x450 __sys_sendto+0x222/0x230 __x64_sys_sendto+0x24/0x40 x64_sys_call+0x1d5d/0x2390 do_syscall_64+0x105/0x5a0 ? do_syscall_64+0x140/0x5a0 ? exc_page_fault+0x94/0x1e0 entry_SYSCALL_64_after_hwframe+0x76/0x7e
--- drivers/net/net_failover.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/net_failover.c +1 -1
@@ -675,7 +675,7 @@ static int net_failover_slave_name_change(struct net_device *slave_dev,/* We need to bring up the slave after the rename by udev in case * open failed with EBUSY when it was registered. */ -dev_open (slave_dev,NULL ); +netif_open (slave_dev,NULL );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 431/733 octeontx2-af: fix PF/CGX debugfs PCI bus lookup
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratheesh Kannoth <[email protected]>
[ Upstream commit 4f4b743c2d2bbc336cb164d9d3d2ed6956ad8437 ]
rvu_dbg_rvu_pf_cgx_map_display() locates each RVU PF PCI device via pci_get_domain_bus_and_slot() when printing the PF-to-CGX map. It assumed PF0 always sits on PCI bus 1 and derived other PF bus numbers as pf + 1, but the AF device can be enumerated on a different bus.
Use rvu->pdev->bus->number as the base bus instead, so each PF lookup uses pf + start on systems where RVU functions are on contiguous buses but do not start at bus 1.
--- .../net/ethernet/marvell/octeontx2/af/rvu_debugfs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +8 -2
@@ -829,19 +829,25 @@ static int rvu_dbg_rvu_pf_cgx_map_display(struct seq_file *filp, void *unused)int pf, domain, blkid;u8 cgx_id, lmac_id;u16 pcifunc; +u8 start; - domain =2 ; + domain =pci_domain_nr (rvu->pdev->bus); mac_ops =get_mac_ops (rvu_first_cgx_pdata (rvu));/* There can be no CGX devices at all */ if (!mac_ops)return 0 ;seq_printf (filp,"PCI dev\t\tRVU PF Func\tNIX block\t%s\tLMAC\tCHAN\n" , mac_ops->name); + +/* All the PF devices are on contiguous PCI bus numbers, but the PF0(AF) +* may not start from 1 always. Hence get domain and bus from PCI device. +*/ + start = rvu->pdev->bus->number;for (pf =0 ; pf < rvu->hw->total_pfs; pf++) {if (!is_pf_cgxmapped (rvu, pf))continue ; - pdev =pci_get_domain_bus_and_slot (domain, pf +1 ,0 ); + pdev =pci_get_domain_bus_and_slot (domain, pf + start,0 );if (!pdev)continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 432/733 net: phy: dp83867: handle the active-high LED polarity mode
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
[ Upstream commit 36a45facedd5c8e73bfb2403f8b0dbff05124c9c ]
Commit a274465cc3be ("net: phy: support 'active-high' property for PHY LEDs") added PHY_LED_ACTIVE_HIGH and made of_phy_led() set the matching bit in the modes mask when a LED node carries the 'active-high' property. dp83867 was not part of that series.
dp83867_led_polarity_set() only recognizes PHY_LED_ACTIVE_LOW, so PHY_LED_ACTIVE_HIGH falls through to the default case and returns -EINVAL. of_phy_led() propagates the error, of_phy_leds() drops the LEDs registered so far and passes it on, and phy_probe() fails. A device tree marking a DP83867 LED as 'active-high', which leds/common.yaml allows and ethernet-phy.yaml references for led@N nodes, thus stops the PHY from probing.
Active high is what the function programs when no polarity mode is requested at all, so the initial value of polarity already satisfies the request and only the case label is missing.
The same series updated mxl-gpy in commit eb89c79c1b8f ("net: phy:
mxl-gpy: correctly describe LED polarity") and aquantia in commit 9d55e68b19f2 ("net: phy: aquantia: correctly describe LED polarity override").
--- drivers/net/phy/dp83867.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/phy/dp83867.c +3 -0
@@ -1150,6 +1150,9 @@ static int dp83867_led_polarity_set(struct phy_device *phydev, int index,case PHY_LED_ACTIVE_LOW : polarity =0 ;break ; +case PHY_LED_ACTIVE_HIGH : + polarity =DP83867_LED_POLARITY (index); +break ;default :return -EINVAL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 433/733 net: mana: restore the XDP program pointer when pre-allocation fails
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <[email protected]>
[ Upstream commit 4c46beb807efcc93f5899ebe1f5958248eb296c6 ]
mana_xdp_set() publishes the new program into apc->bpf_prog before it allocates anything, because mana_pre_alloc_rxbufs() sizes the buffers from it via mana_get_rxbuf_cfg(). When that allocation fails the function returns the error directly, skipping the err_dealloc_rxbuffs label which is the only place that restores the previous pointer.
The attach is reported as failed, so the BPF core drops the reference it held for the caller and the program can be freed, while apc->bpf_prog still points at it. The next consumer of mana_xdp_get() - typically mana_chn_setxdp() from mana_alloc_queues() on the following ifup, or after a TX timeout reset - then calls bpf_prog_add() on freed memory.
This is reachable from an ordinary "ip link set dev ethX xdp obj ..." whenever the per-queue RX buffer pre-allocation cannot be satisfied.
Restore the previous program on that error path.
--- drivers/net/ethernet/microsoft/mana/mana_bpf.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/microsoft/mana/mana_bpf.c +1 -0
@@ -208,6 +208,7 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog,if (err) {NL_SET_ERR_MSG_MOD (extack,"XDP: Insufficient memory for tx/rx re-config" ); + apc->bpf_prog = old_prog;return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 434/733 net/rds: fix tcp stream corruption with large pages
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Marsden <[email protected]>
[ Upstream commit 2ac09b5353fe6858411fdc8c6efa60d832e20f13 ]
rds_message_map_pages() assigns PAGE_SIZE bytes to every scatterlist entry, even when total_len ends in a partial page. The RDS congestion map is defined as 8192 bytes, so on systems with PAGE_SIZE greater than 8192 the scatterlist maps bytes beyond the end of the congestion map. RDS-TCP transmits the SG contents according to those lengths, so the extra bytes become part of the TCP RDS stream and are interpreted as subsequent RDS message headers, corrupting the stream.
Limit the final scatterlist mapping to the number of bytes remaining. This has no effect on systems with a 4K page size and allows RDS-TCP to be used on systems with 16K and larger page sizes.
The RDS selftest, which previously hung on 16K pages, now passes.
--- net/rds/message.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/rds/message.c +3 -1
@@ -405,7 +405,9 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned infor (i =0 ; i < rm->data.op_nents; ++i) {sg_set_page (&rm->data.op_sg[i],virt_to_page ((void *)page_addrs[i]), -PAGE_SIZE ,0 ); + i == rm->data.op_nents -1 + ? total_len - (i *PAGE_SIZE ) + :PAGE_SIZE ,0 ); }return rm;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 435/733 net: stmmac: fix TX descriptor availability check for TSO traffic
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 5e38d732ec67a5b1f9a56e6c73add480c4b6030a ]
stmmac_tso_xmit() estimates the number of free TX descriptors required by a TSO skb as:
(skb->len - proto_hdr_len) / TSO_MAX_BUFF_SIZE + 1
which assumes the payload is split into TSO_MAX_BUFF_SIZE chunks. This underestimates the descriptors actually consumed by stmmac_tso_allocator(), since each fragment is mapped individually and so it needs at least one descriptor regardless of its size. Moreover, one descriptor is used for the L2/L3/L4 headers and, when the MSS changes, one more is consumed for the MSS context descriptor.
For a highly fragmented TSO skb the check can therefore pass even when the ring has too few free slots. stmmac_tso_allocator() then writes past the available descriptors, overwriting descriptors still owned by the DMA engine, corrupting the TX ring.
Add stmmac_tso_get_num_desc() to compute the exact number of descriptors needed for the header, the linear payload and each fragment, plus the MSS context descriptor when required, and use it in the availability check.
--- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +25 -6
@@ -4454,6 +4454,26 @@ static bool stmmac_tso_valid_packet(struct sk_buff *skb) header_len + gso_size <16383 ; } +static int stmmac_tso_get_num_desc (struct stmmac_tx_queue *tx_q, +struct sk_buff *skb,u32 pay_len) +{ +int i, ndesc =1 ; + +/* head payload */ + ndesc +=DIV_ROUND_UP (pay_len,TSO_MAX_BUFF_SIZE ); +/* frag payload */ +for (i =0 ; i <skb_shinfo (skb)->nr_frags; i++) { +const skb_frag_t *frag = &skb_shinfo (skb)->frags[i]; + + ndesc +=DIV_ROUND_UP (skb_frag_size (frag), +TSO_MAX_BUFF_SIZE ); + } +/* MSS update requires a new descriptor */ + ndesc += !!(skb_shinfo (skb)->gso_size != tx_q->mss); + +return ndesc; +} +/** * stmmac_tso_xmit - Tx entry point of the driver for oversized frames (TSO) * @skb : the socket buffer
@@ -4497,10 +4517,10 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)struct stmmac_priv *priv =netdev_priv (dev);unsigned int first_entry, entry, tx_packets;struct stmmac_txq_stats *txq_stats; +int i, first_tx, nfrags, ndesc;struct stmmac_tx_queue *tx_q;bool set_ic, is_last_segment;u32 pay_len, mss, queue; -int i, first_tx, nfrags;u8 proto_hdr_len, hdr;dma_addr_t des;
@@ -4513,14 +4533,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)/* Compute header lengths */ proto_hdr_len =stmmac_tso_header_size (skb); + pay_len =skb_headlen (skb) - proto_hdr_len;/* no frags */ +if (skb_shinfo (skb)->gso_type &SKB_GSO_UDP_L4 ) hdr =sizeof (struct udphdr );else hdr =tcp_hdrlen (skb); -/* Desc availability based on threshold should be enough safe */ -if (unlikely (stmmac_tx_avail (priv, queue) < - (((skb->len - proto_hdr_len) /TSO_MAX_BUFF_SIZE +1 )))) { + ndesc =stmmac_tso_get_num_desc (tx_q, skb, pay_len); +if (unlikely (stmmac_tx_avail (priv, queue) < ndesc)) {if (!netif_tx_queue_stopped (netdev_get_tx_queue (dev, queue))) {netif_tx_stop_queue (netdev_get_tx_queue (priv->dev, queue));
@@ -4532,8 +4553,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)return NETDEV_TX_BUSY ; } - pay_len =skb_headlen (skb) - proto_hdr_len;/* no frags */ - mss =skb_shinfo (skb)->gso_size;/* set new MSS value if needed */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 436/733 net: hsr: enable promiscuous mode on interlink port with fwd offload
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: MD Danish Anwar <[email protected]>
[ Upstream commit a2dc179481d18f6df7274522571b64dd50f31e81 ]
hsr_portdev_setup() skips promiscuous mode on non-master ports when hsr->fwd_offloaded is set. fwd_offloaded is derived only from the ring slaves' NETIF_F_HW_HSR_FWD bit, so this also skips it for the interlink port, which never gets forwarding offload. Without promiscuous mode, the interlink NIC drops unicast frames addressed to hsr_dev's MAC (e.g. SAN traffic to the RedBox), breaking RedBox whenever the ring is HW-offloaded.
--- net/hsr/hsr_slave.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
net/hsr/hsr_slave.c +7 -4
@@ -149,9 +149,12 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev,int res;/* Don't use promiscuous mode for offload since L2 frame forward -* happens at the offloaded hardware. +* happens at the offloaded hardware. The interlink port never +* gets forwarding offload (RedBox forwarding to/from it is done +* by this driver), so it still needs promiscuous mode to receive +* frames addressed to hsr_dev's MAC rather than its own. */ -if (!port->hsr->fwd_offloaded) { +if (!port->hsr->fwd_offloaded || port->type ==HSR_PT_INTERLINK ) { res =dev_set_promiscuity (dev,1 );if (res)return res;
@@ -176,7 +179,7 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev, fail_rx_handler:netdev_upper_dev_unlink (dev, hsr_dev); fail_upper_dev_link: -if (!port->hsr->fwd_offloaded) +if (!port->hsr->fwd_offloaded || port->type ==HSR_PT_INTERLINK )dev_set_promiscuity (dev,-1 );return res;
@@ -240,7 +243,7 @@ void hsr_del_port(struct hsr_port *port)netdev_update_features (master->dev);dev_set_mtu (master->dev,hsr_get_max_mtu (hsr));netdev_rx_handler_unregister (port->dev); -if (!port->hsr->fwd_offloaded) +if (!port->hsr->fwd_offloaded || port->type ==HSR_PT_INTERLINK )dev_set_promiscuity (port->dev,-1 );if (port->type ==HSR_PT_SLAVE_A || port->type ==HSR_PT_SLAVE_B )vlan_vids_del_by_dev (port->dev, master->dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 437/733 openvswitch: fix wrong flag value in get_ipv6_ext_hdrs()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eelco Chaudron <[email protected]>
[ Upstream commit e184a4a6f423550a25adce867036cdb1ff471745 ]
The ESP and AH cases in get_ipv6_ext_hdrs() used IPPROTO_FRAGMENT instead of OFPIEH12_FRAG when checking for out-of-order extension headers, causing the fragment header to not be recognised as a valid predecessor.
The original code used IPPROTO_FRAGMENT (44) as a bitmask constant where OFPIEH12_FRAG (1 << 4 = 16) was intended. IPPROTO_FRAGMENT encodes bits 2, 3 and 5 (OFPIEH12_AUTH | OFPIEH12_DEST | OFPIEH12_ROUTER), but not bit 4 (OFPIEH12_FRAG). This caused incorrect OFPIEH12_UNSEQ verdicts in both the ESP and AH arms: the ESP arm failed to whitelist OFPIEH12_FRAG, while the AH arm accidentally whitelisted OFPIEH12_AUTH.
With the fix, a packet with two AH headers now also gets OFPIEH12_UNSEQ in addition to OFPIEH12_UNREP, matching the ESP arm which already sets UNSEQ on a repeat, which is the intended behavior.
--- net/openvswitch/flow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/openvswitch/flow.c +2 -2
@@ -288,7 +288,7 @@ static void get_ipv6_ext_hdrs(struct sk_buff *skb, struct ipv6hdr *nh,if (*ext_hdrs &OFPIEH12_ESP ) *ext_hdrs |=OFPIEH12_UNREP ;if ((*ext_hdrs & ~(OFPIEH12_HOP |OFPIEH12_DEST | -OFPIEH12_ROUTER |IPPROTO_FRAGMENT | +OFPIEH12_ROUTER |OFPIEH12_FRAG |OFPIEH12_AUTH |OFPIEH12_UNREP )) || dest_options_header_count >=2 ) { *ext_hdrs |=OFPIEH12_UNSEQ ;
@@ -301,7 +301,7 @@ static void get_ipv6_ext_hdrs(struct sk_buff *skb, struct ipv6hdr *nh, *ext_hdrs |=OFPIEH12_UNREP ;if ((*ext_hdrs & ~(OFPIEH12_HOP |OFPIEH12_DEST |OFPIEH12_ROUTER | -IPPROTO_FRAGMENT |OFPIEH12_UNREP )) || +OFPIEH12_FRAG |OFPIEH12_UNREP )) || dest_options_header_count >=2 ) { *ext_hdrs |=OFPIEH12_UNSEQ ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 438/733 block: Fix start and length check added to iov_iter_extract_bvecs()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit b0d8d56b7c93ed767eb4f2be9988e7b9dc023566 ]
Commit 14b007e17881 added an address check using iter_iov_addr() and a length check using iter_iov_len() to iov_iter_extract_bvecs(), but these cannot be used so and are unsafe in this circumstance as the functions have hardwired assumptions about the iterator type. They should only be used with ITER_UBUF or ITER_IOVEC-type iterators; they shouldn't be used with ITER_BVEC, ITER_KVEC, ITER_FOLIOQ, ITER_XARRAY or ITER_DISCARD iterators.
This proves to be a problem for cachefiles as an iterator of type ITER_FOLIOQ is passed and iter_iov_addr() and iter_iov_len() both malfunction because iter->__iov in iter_iov() is not pointing to an iovec array.
Fix this by using iov_iter_alignment() instead.
--- lib/iov_iter.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
lib/iov_iter.c +16 -2
@@ -1920,15 +1920,29 @@ ssize_t iov_iter_extract_bvecs(struct iov_iter *iter, struct bio_vec *bv, unsigned short max_vecs, unsigned mem_align_mask, iov_iter_extraction_t extraction_flags) { - unsigned long start = (unsigned long)iter_iov_addr(iter); unsigned short entries_left = max_vecs - *nr_vecs;unsigned short nr_pages, i =0 ;size_t left, offset, len;struct page **pages;ssize_t size; -if ((start |iter_iov_len (iter)) & mem_align_mask) +/* +* DMA engines typically have both memory address and length alignment +* requirements, so check these against the alignment mask. For UBUF, +* IOVEC and KVEC, only the current segment will be extracted from; for +* everything else we might extract from multiple segments, so we need +* to check those too. +*/ +if (likely (iter_is_ubuf (iter) || +iter_is_iovec (iter) || +iov_iter_is_kvec (iter))) { +unsigned long start = (unsigned long )iter_iov_addr (iter); + +if ((start |iter_iov_len (iter)) & mem_align_mask) +return -EINVAL ; + }else if (iov_iter_alignment (iter) & mem_align_mask) {return -EINVAL ; + }/* * Move page array up in the allocated memory for the bio vecs as far as
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 439/733 sunvdc: unmap LDC cookies when the descriptor send fails
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stian Halseth <[email protected]>
[ Upstream commit 0c6da21fa35e03fc74f09895433ccd6d4a9c3530 ]
__send_request() maps the request's pages into the LDC channel's map table (ldc_map_sg()), fills in the descriptor and marks it VIO_DESC_READY before ringing the doorbell via __vdc_tx_trigger(). When the trigger fails, the error path only prints a message: the descriptor stays READY and the cookies are never unmapped. The mapping is normally released in vdc_end_one() when the peer completes the descriptor - but a descriptor whose doorbell was never sent will never complete, and since dr->prod is not advanced on failure, the reset path (vdc_requeue_inflight(), which walks [cons, prod)) never visits it either. The map table entries are leaked permanently.
Since commit a11f6ca9aef9 ("sunvdc: Do not spin in an infinite loop when vio_ldc_send() returns EAGAIN") trigger failures occur in practice under load, so every resulting I/O error also leaks one request's worth of entries from the fixed-size (8192 entries per channel) map table. Because the allocator hands out contiguous ranges, fragmentation makes large multi-segment requests fail first as the table drains, until ldc_map_sg() fails permanently and the disk is dead until reboot.
It also makes any retry-based recovery unusable: requeuing the request on -EAGAIN remaps the pages on every attempt, overwriting desc->cookies and orphaning the previous mapping, so the table drains at the retry rate. This is the memory exhaustion observed when the requeue approach was first tested in October 2025.
Roll back on failure: unmap the cookies, mark the descriptor FREE again and clear the request entry. If the trigger failed with -ENOTCONN, __vdc_tx_trigger() has already reset the port, which tears down and reallocates both the dring and the LDC channel including its map table - nothing to roll back, and the stale descriptor must not be touched.
--- drivers/block/sunvdc.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
drivers/block/sunvdc.c +17 -0
@@ -525,6 +525,23 @@ static int __send_request(struct request *req) err =__vdc_tx_trigger (port);if (err <0 ) { printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err); +/* +* If the port was reset (-ENOTCONN), the dring and the +* LDC channel including all of its mappings are already +* torn down and reallocated - there is nothing to undo +* and @desc must not be touched. +* +* For any other failure the descriptor was never handed +* to the peer: unmap the cookies and free the descriptor +* again, so that a later retry of the request does not +* leak LDC map table entries. +*/ +if (err != -ENOTCONN ) { +ldc_unmap (port->vio.lp, desc->cookies, + desc->ncookies); + desc->hdr.state =VIO_DESC_FREE ; + rqe->req =NULL ; + } }else { port->req_id++; dr->prod =vio_dring_next (dr, dr->prod);
Signature · 1 line
2.53.0
Re: [PATCH 7.2 439/733] sunvdc: unmap LDC cookies when the descriptor send fails
Hi,
No objection to this patch, but please also queue its companion
5067d4ba7139 ("sunvdc: fix -EIO issue due to lack of retries")
which was applied to mainline together with this one. The same applies to the 6.18 and 6.12 queues, which carry this patch as well.
With both applied, the stable trees match mainline behavior.
Order matters: 0c6da21fa35e must go first (it already is, in the queues).
Best regards
Stian Halseth
Quoted 82 lines · Greg Kroah-Hartman
7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stian Halseth <[email protected]>
[ Upstream commit
0c6da21fa35e03fc74f09895433ccd6d4a9c3530]
__send_request()maps the request's pages into the LDC channel's map table (ldc_map_sg()), fills in the descriptor and marks itVIO_DESC_READYbefore ringing the doorbell via__vdc_tx_trigger(). When the trigger fails, the error path only prints a message: the descriptor stays READY and the cookies are never unmapped. The mapping is normally released invdc_end_one()when the peer completes the descriptor - but a descriptor whose doorbell was never sent will never complete, and sincedr->prodis not advanced on failure, the reset path (vdc_requeue_inflight(), which walks [cons, prod)) never visits it either. The map table entries are leaked permanently.Since commit
a11f6ca9aef9("sunvdc: Do not spin in an infinite loop whenvio_ldc_send()returns EAGAIN") trigger failures occur in practice under load, so every resulting I/O error also leaks one request's worth of entries from the fixed-size (8192 entries per channel) map table. Because the allocator hands out contiguous ranges, fragmentation makes large multi-segment requests fail first as the table drains, untilldc_map_sg()fails permanently and the disk is dead until reboot.It also makes any retry-based recovery unusable: requeuing the request on
-EAGAINremaps the pages on every attempt, overwritingdesc->cookiesand orphaning the previous mapping, so the table drains at the retry rate. This is the memory exhaustion observed when the requeue approach was first tested in October 2025.Roll back on failure: unmap the cookies, mark the descriptor FREE again and clear the request entry. If the trigger failed with
-ENOTCONN,__vdc_tx_trigger()has already reset the port, which tears down and reallocates both the dring and the LDC channel including its map table - nothing to roll back, and the stale descriptor must not be touched.Fixes a11f6ca9aef9 ("sunvdc: Do not spin in an infinite loop when
vio_ldc_send()returns EAGAIN")Reported-by John Paul Adrian Glaubitz <[email protected]>Signed-off-by Stian Halseth <[email protected]>Signed-off-by Jens Axboe <[email protected]>Signed-off-by Sasha Levin <[email protected]>---
drivers/block/sunvdc.c | 17 +++++++++++++++++1 file changed, 17 insertions(+)drivers/block/sunvdc.c +17
-0@@ -525,6 +525,23 @@ static int __send_request(struct request *req) err = __vdc_tx_trigger(port); if (err < 0) { printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err); +/* +* If the port was reset (-ENOTCONN), the dring and the +* LDC channel including all of its mappings are already +* torn down and reallocated - there is nothing to undo +* and @desc must not be touched. +* +* For any other failure the descriptor was never handed +* to the peer: unmap the cookies and free the descriptor +* again, so that a later retry of the request does not +* leak LDC map table entries. +*/ +if (err != -ENOTCONN ) { +ldc_unmap (port->vio.lp, desc->cookies, + desc->ncookies); + desc->hdr.state =VIO_DESC_FREE ; + rqe->req =NULL ; + } } else { port->req_id++; dr->prod = vio_dring_next(dr, dr->prod);
Re: [PATCH 7.2 439/733] sunvdc: unmap LDC cookies when the descriptor send fails
Quoted 6 lines
No objection to this patch, but please also queue its companion
5067d4ba7139("sunvdc: fix-EIOissue due to lack of retries")which was applied to mainline together with this one. The same applies to the 6.18 and 6.12 queues, which carry this patch as well.
Queued for 7.2, 6.18, 6.12, 6.6, 6.1, 5.15 and 5.10, thanks.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 440/733 ublk: clear force_abort in ublk_queue_reset_io_flags()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Xiuwei <[email protected]>
[ Upstream commit 8a14be55bdc6d5a25cd7b0ac5d4d884fcc727b49 ]
Quiesce sets ubq->force_abort for batch I/O. Recovery never clears it, so batch fetch keeps failing with -ENODEV and the device stays QUIESCED.
--- drivers/block/ublk_drv.c | 1 + 1 file changed, 1 insertion(+)
drivers/block/ublk_drv.c +1 -0
@@ -3040,6 +3040,7 @@ static void ublk_queue_reset_io_flags(struct ublk_queue *ubq) ubq->canceling = false;spin_unlock (&ubq->cancel_lock); ubq->fail_io = false; + ubq->force_abort = false; }/* device can only be started after all IOs are ready */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 441/733 erofs: add missing buf->off in erofs_bread()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Binglei Wang <[email protected]>
[ Upstream commit 135d84c66f85426299db01a09d93a79a87af18ba ]
erofs_bread() locates the target folio with
index = (buf->off + offset) >> PAGE_SHIFT;
but computes the in-folio offset without taking buf->off into account:
return buf->base + (offset & ~PAGE_MASK);
If buf->off is not page-aligned, the returned pointer misses the in-page component of buf->off, so callers end up fetching data from a wrong offset.
buf->off is set to sbi->dif0.fsoff in erofs_init_metabuf(), and fsoff can be specified via the "fsoffset=" mount option, which only requires block-size alignment. Therefore, on an image with a sub-page block size (e.g. 512 bytes), a non-page-aligned fsoff (e.g. 512) triggers the issue, since 512 is a multiple of the block size but not of PAGE_SIZE.
It can be reproduced by mounting an image that is placed at a non-page-aligned offset:
mkfs.erofs -b512 -zlz4hc sub.erofs src/
# prepend 512 bytes of padding to the image mount -t erofs -o loop,fsoffset=512 padded.erofs /mnt
which fails with
erofs (device loop0): cannot find valid erofs superblock
because the on-disk superblock (at offset 1024 within the image, i.e. 1536 within the padded file) is read from a wrong in-folio offset. With this fixed, the very same image mounts successfully and its file contents match those read from the unpadded image.
Fix it by including buf->off in the in-folio offset calculation, so that it is consistent with the folio index calculation.
--- fs/erofs/data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/erofs/data.c +1 -1
@@ -61,7 +61,7 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)return NULL ;if (!buf->base) buf->base =kmap_local_page (buf->page); -return buf->base + (offset & ~PAGE_MASK ); +return buf->base + ((buf->off + offset) & ~PAGE_MASK ); } int erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 442/733 tracing: Fix ring_buffer_read_page_size() kernel-doc
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 7e645147dfba67edb3ed3090a1ed1d89df77fc27 ]
ring_buffer_read_page_size() takes a parameter named rpage, but its kernel-doc describes page. As a result, kernel-doc reports rpage as undescribed and page as an excess parameter description.
Rename the documentation entry to match the function.
--- kernel/trace/ring_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/ring_buffer.c +1 -1
@@ -7368,7 +7368,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_read_page_data);/** * ring_buffer_read_page_size - get size of the read page. -* @page: the page to get the size from +* @rpage: the page to get the size from * * Returns size of the page in bytes. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 443/733 scripts/mksysmap: drop the MODULE_INFO() symbols from kallsyms
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <[email protected]>
[ Upstream commit 281b61d408d4c39544583e393c6707af0ef5ee50 ]
Commit 3e86e4d74c04 ("kbuild: keep .modinfo section in vmlinux.unstripped") keeps .modinfo symbols out of System.map and kallsyms, which assumes unique IDs have a format like '__UNIQUE_ID_modinfo123'.
However, commit afb026b6d35c ("compiler: Tweak __UNIQUE_ID() naming"), sent in the same cycle, changes this to '__UNIQUE_ID_modinfo_123'.
As a result this regexp has never matched and every kernel since v6.18 has carried one kallsyms entries for every MODULE_INFO() declaration in the kernel whether the modules are compiled or not.
That's 5,810 entries for an x86 defconfig build and 15,200 for arm64.
On x86 defconfig that is 113 KiB of kallsyms tables and 32 KiB of bzImage, and every lookup walks past them.
Fix the pattern.
--- scripts/mksysmap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/mksysmap +1 -1
@@ -83,7 +83,7 @@ / _SDA2_BASE_$/d # MODULE_INFO() -/ __UNIQUE_ID_modinfo[0-9]*$/d +/ __UNIQUE_ID_modinfo_[0-9]*$/d # --------------------------------------------------------------------------- # Ignored patterns
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 444/733 scripts/mksysmap: fix escape of $ in the __pi_ pattern
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <[email protected]>
[ Upstream commit 59351365ac271b5e0eb180f211c531476a36221f ]
Commit b18b047002b7 ("kbuild: change scripts/mksysmap into sed script") converted scripts/mksysmap from a shell script to a sed script.
However an error was made - escaping of '$' required \\ escaping in shell but only \ in a sed script.
This was mostly corrected in commit 7a6c355b55c0 ("scripts/mksysmap: Fix escape chars '$'"), but this fix missed arm64 PIE namespace local symbols like __pi_$x and __pi_$d which appear in System.map and /proc/kallsyms:
$ grep __pi_\\$ /proc/kallsyms | sort -u 0000000000000000 d __pi_$d 0000000000000000 t __pi_$x
Fix the escaping properly.
--- scripts/mksysmap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/mksysmap +1 -1
@@ -35,7 +35,7 @@ / __efistub_/d # arm64 local symbols in PIE namespace -/ __pi_\\$/d +/ __pi_\$/d / __pi_\.L/d # arm64 local symbols in non-VHE KVM namespace
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 445/733 tracing/remotes: Account for ring buffer page header in size calculation
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Donnefort <[email protected]>
[ Upstream commit 442ffa742daa65a0e8fe003abe9fbe472366e4de ]
trace_buffer_desc_size() and trace_remote_alloc_buffer() undercount the required pages because every ring buffer page contains a header (BUF_PAGE_HDR_SIZE). Account for that header to ensure allocated remote ring buffers aren't smaller than requested by the user.
The newly introduced helper __calc_nr_pages_ring_buffer_desc() can return a value that overflows the descriptor nr_pages field (32 bits).
--- include/linux/ring_buffer.h | 15 +++++++++++++-- kernel/trace/trace_remote.c | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-)
include/linux/ring_buffer.h +13 -2
@@ -3,8 +3,9 @@#define _LINUX_RING_BUFFER_H#include <linux/mm.h> -#include <linux/seq_file.h> #include <linux/poll.h> +#include <linux/ring_buffer_types.h> +#include <linux/seq_file.h> #include <uapi/linux/trace_mmap.h>
@@ -279,9 +280,19 @@ static inline struct ring_buffer_desc *__first_ring_buffer_desc(struct trace_bufreturn (struct ring_buffer_desc *)(&desc->__data[0 ]); } +/* +* Returns the number of pages for a ring_buffer_desc. The caller must ensure it +* does not overflow ring_buffer_desc::nr_page_va. +*/ +static inline unsigned long __calc_nr_pages_ring_buffer_desc (size_t size) +{ +/* Takes into account the reader page */ +return max (DIV_ROUND_UP (size,PAGE_SIZE -BUF_PAGE_HDR_SIZE ),2UL ) +1 ; +} +static inline size_t trace_buffer_desc_size (size_t buffer_size,unsigned int nr_cpus) { -unsigned int nr_pages =max (DIV_ROUND_UP (buffer_size,PAGE_SIZE ),2UL ) +1 ; +unsigned long nr_pages =__calc_nr_pages_ring_buffer_desc (buffer_size);struct ring_buffer_desc *rbdesc; return size_add(offsetof(struct trace_buffer_desc, __data),
kernel/trace/trace_remote.c +1 -1
@@ -980,7 +980,7 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, const struct cpumask *cpumask) {size_t min_desc_size =trace_buffer_desc_size (buffer_size,cpumask_weight (cpumask)); -unsigned int nr_pages =max (DIV_ROUND_UP (buffer_size,PAGE_SIZE ),2UL ) +1 ; +unsigned int nr_pages =__calc_nr_pages_ring_buffer_desc (buffer_size);struct ring_buffer_desc *rb_desc;int cpu, ret = -ENOMEM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 446/733 tracing/remotes: Catch nr_page_va overflow in ring_buffer_desc sizing
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Donnefort <[email protected]>
[ Upstream commit d059d8bf2c9b5d563d15e7552d73e17d7535013a ]
The number of pages per remote ring buffer is capped by ring_buffer_desc::nr_page_va (32 bits). A buffer_size large enough to overflow that field would silently allocate a descriptor smaller than what was asked for.
Return SIZE_MAX from trace_buffer_desc_size() on nr_page_va overflow.
--- include/linux/ring_buffer.h | 4 ++++ kernel/trace/trace_remote.c | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-)
include/linux/ring_buffer.h +4 -0
@@ -295,6 +295,10 @@ static inline size_t trace_buffer_desc_size(size_t buffer_size, unsigned int nr_unsigned long nr_pages =__calc_nr_pages_ring_buffer_desc (buffer_size);struct ring_buffer_desc *rbdesc; +/* Capped by ring_buffer_desc::nr_page_va */ +if (nr_pages >UINT_MAX ) +return SIZE_MAX ; +return size_add (offsetof(struct trace_buffer_desc , __data),size_mul (nr_cpus,struct_size (rbdesc, page_va, nr_pages))); }
kernel/trace/trace_remote.c +5 -1
@@ -980,9 +980,12 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, const struct cpumask *cpumask) {size_t min_desc_size =trace_buffer_desc_size (buffer_size,cpumask_weight (cpumask)); -unsigned int nr_pages =__calc_nr_pages_ring_buffer_desc (buffer_size);struct ring_buffer_desc *rb_desc;int cpu, ret = -ENOMEM ; +unsigned int nr_pages; + +if (min_desc_size ==SIZE_MAX ) +return -E2BIG ;if (desc_size < min_desc_size)return -EINVAL ;
@@ -991,6 +994,7 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, desc->struct_len = min_desc_size; rb_desc =__first_ring_buffer_desc (desc); + nr_pages =__calc_nr_pages_ring_buffer_desc (buffer_size);for_each_cpu (cpu, cpumask) {unsigned int id;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 447/733 scsi: target: iscsi: Fix hang for aborted WRITE_PENDING commands
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maurizio Lombardi <[email protected]>
[ Upstream commit d5869dae5080e976d4b03cc33eb7ceb527f242bf ]
When a LUN_RESET aborts a WRITE command that is in the TRANSPORT_WRITE_PENDING state, the target core sets CMD_T_ABORTED and waits for the frontend to finish processing.
If the initiator subsequently sends the remaining dataout PDUs, __iscsit_check_dataout_hdr() catches the payload, stops the dataout timer if the sequence is final and finally dumps the data. However, the iSCSI target doesn't trigger the completion process for these aborted commands. Because of this, the abort path hangs indefinitely in target_put_cmd_and_wait(), leading to a deadlocked target worker thread.
Fix this by explicitly calling target_complete_cmd() when the final dataout PDU is received for an aborted WRITE command. target_complete_cmd() detects the CMD_T_ABORTED flag and cleanly routes the command into target_abort_work, allowing the abort completion to successfully unblock.
--- drivers/target/iscsi/iscsi_target.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/target/iscsi/iscsi_target.c +3 -1
@@ -1533,8 +1533,10 @@ __iscsit_check_dataout_hdr(struct iscsit_conn *conn, void *buf,*/ if (se_cmd->transport_state &CMD_T_ABORTED ) {if (hdr->flags &ISCSI_FLAG_CMD_FINAL && - --cmd->outstanding_r2ts <1 ) + --cmd->outstanding_r2ts <1 ) {iscsit_stop_dataout_timer (cmd); +target_complete_cmd (se_cmd,SAM_STAT_TASK_ABORTED ); + }return iscsit_dump_data_payload (conn, payload_length,1 ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 448/733 configfs: pin the symlink targets dirent instead of chasing ->ci_dentry
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasileios Almpanis <[email protected]>
commit a7c1290eef60711c10289c056ad32ed1f2b47b12 upstream.
create_link() reads the target's configfs_dirent from item->ci_dentry->d_fsdata, relying on the item reference taken by get_target(). That reference pins the item, not its dentry: the dentry is pinned by DCACHE_PERSISTENT, which configfs_remove_dir() releases via simple_rmdir() while the item is still alive. A symlink racing with rmdir of its target can therefore find ->ci_dentry freed and its dirent released, triggering WARN_ON(!atomic_read(&sd->s_count)) in configfs_get().
Take the dirent in get_target() as well, under ->d_lock and atomically with the item reference, and pass it down to create_link(). A hashed dentry has not been killed yet, so its ->d_fsdata reference keeps the dirent alive there.
--- fs/configfs/symlink.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
fs/configfs/symlink.c +20 -4
@@ -76,9 +76,9 @@ static int configfs_get_target_path(strustatic int create_link (struct config_item *parent_item,struct config_item *item, +struct configfs_dirent *target_sd,struct dentry *dentry) { -struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata;char *body;int ret;
@@ -115,6 +115,7 @@ static int create_link(struct config_itestatic int get_target (const char *symname,struct config_item **target, +struct configfs_dirent **target_sd,struct super_block *sb) { struct path path __free(path_put) = {};
@@ -125,7 +126,20 @@ static int get_target(const char *symnamreturn ret;if (path.dentry->d_sb != sb)return -EPERM ; - *target =configfs_get_config_item (path.dentry); +/* +* A hashed dentry guarantees that neither the item nor the dirent +* have been released yet, as removals unhash before dropping. +* Grab both references here. An item reference alone would not keep +* ->ci_dentry alive. +*/ +spin_lock (&path.dentry->d_lock); +if (!d_unhashed (path.dentry)) { +struct configfs_dirent *sd = path.dentry->d_fsdata; + + *target =config_item_get (sd->s_element); + *target_sd =configfs_get (sd); + } +spin_unlock (&path.dentry->d_lock);if (!*target)return -ENOENT ;return 0 ;
@@ -139,6 +153,7 @@ int configfs_symlink(struct mnt_idmap *istruct configfs_dirent *sd;struct config_item *parent_item;struct config_item *target_item =NULL ; +struct configfs_dirent *target_sd =NULL ;const struct config_item_type *type; sd = dentry->d_parent->d_fsdata;
@@ -182,7 +197,7 @@ int configfs_symlink(struct mnt_idmap *i* AV, a thoroughly annoyed bastard. */ inode_unlock (dir); - ret =get_target (symname, &target_item, dentry->d_sb); + ret =get_target (symname, &target_item, &target_sd, dentry->d_sb);inode_lock (dir);if (ret) goto out_put;
@@ -196,13 +211,14 @@ int configfs_symlink(struct mnt_idmap *i ret = type->ct_item_ops->allow_link (parent_item, target_item);if (!ret) {mutex_lock (&configfs_symlink_mutex); - ret =create_link (parent_item, target_item, dentry); + ret =create_link (parent_item, target_item, target_sd, dentry);mutex_unlock (&configfs_symlink_mutex);if (ret && type->ct_item_ops->drop_link) type->ct_item_ops->drop_link (parent_item, target_item); } +configfs_put (target_sd);config_item_put (target_item); out_put:
Greg Kroah-Hartman
maintainerPATCH 449/733 configfs: unhash the dentry before dropping the item in rmdir
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasileios Almpanis <[email protected]>
commit f06c2d26d1999d37e93299db0ecead04ca7d0b9f upstream.
configfs_get_config_item() treats a hashed dentry as proof that sd->s_element is a live config_item. configfs_rmdir() breaks that:simple_rmdir() leaves the dentry hashed, the last reference to the item is dropped right after, and the dentry is only unhashed by d_delete() once ->rmdir() has returned. configfs_symlink() resolves its target holding no lock on it, so get_target() can land in that window:
BUG: KASAN: slab-use-after-free in config_item_get+0x26/0x90 get_target fs/configfs/symlink.c:128 [inline] configfs_symlink+0x4ab/0x1030 fs/configfs/symlink.c:185
Unhash in configfs_remove_dir(), while the item is still guaranteed to be there. A reference obtained just before that stays harmless, as create_link() rechecks CONFIGFS_USET_DROPPING, already set by configfs_detach_prep(). Both configfs_unregister_subsystem() paths d_drop() after detaching, so this only makes rmdir match them.
--- fs/configfs/dir.c | 9 +++++++++ 1 file changed, 9 insertions(+)
fs/configfs/dir.c +9 -0
@@ -416,6 +416,15 @@ static void configfs_remove_dir(struct dif (d_really_is_positive (d)) {if (unlikely (simple_rmdir (d_inode (parent), d)))pr_warn ("remove_dir (%pd): attributes remain" , d); +else +/* +* configfs_get_config_item() takes a hashed dentry as +* proof that ->s_element is still alive. Our caller +* is about to drop the last reference to the item and +* the VFS will not unhash until after we return, so +* unhash it here. +*/ +d_drop (d); }pr_debug (" o %pd removing done (%d)\n" , d,d_count (d));
Greg Kroah-Hartman
maintainerPATCH 450/733 powerpc/ps3: Fix repository.c build failure
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit 5ba79d37403d86082ab4083b0f51ec3008a942cb upstream.
GCC fails to build ps3_defconfig with the following errors:
arch/powerpc/platforms/ps3/repository.c: In function ‘make_first_field.constprop’:
arch/powerpc/platforms/ps3/repository.c:78:9: error: ‘strnlen’ specified bound 8 exceeds source size 3 [-Werror=stringop-overread]
78 | memcpy((char *)&n, text, strnlen(text, sizeof(n)));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arch/powerpc/platforms/ps3/repository.c: In function ‘make_first_field.constprop’:
arch/powerpc/platforms/ps3/repository.c:78:9: error: ‘strnlen’ specified bound 8 exceeds source size 4 [-Werror=stringop-overread]
78 | memcpy((char *)&n, text, strnlen(text, sizeof(n)));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~The current use of strnlen(text, sizeof(n)) triggers -Wstringop-overread when text is a short string literal that is smaller than sizeof(n), such as "bi" or "bus". Use strlen(text) instead and clamp the copy length to sizeof(n) before memcpy().
Drop the redundant char * cast while at it.
--- arch/powerpc/platforms/ps3/repository.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
arch/powerpc/platforms/ps3/repository.c +4 -1
@@ -6,6 +6,8 @@* Copyright 2006 Sony Corp. */ +#include <linux/minmax.h> +#include <asm/lv1call.h> #include "platform.h"
@@ -74,8 +76,9 @@ static void _dump_node(unsigned int lparstatic u64 make_first_field (const char *text,u64 index) {u64 n =0 ; +size_t len =min (strlen (text),sizeof (n)); -memcpy ((char *)&n, text,strnlen (text,sizeof (n))); +memcpy (&n, text, len);return PS3_VENDOR_ID_NONE + (n >>32 ) + index; }
Greg Kroah-Hartman
maintainerPATCH 451/733 powerpc/eeh: Fix recursive locking on devices without EEH sensitive driver
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivaprasad G Bhat <[email protected]>
commit c5e68706527968282e49de205cc2b935823cb88a upstream.
The commit 1010b4c012b0 ("powerpc/eeh: Make EEH driver device hotplug safe") refactored the EEH code such that the pci_rescan_remove_lock is held at the beginning of eeh_handle_normal_event() and the eeh_reset_device() is called with that lock being held. Looks like the commit missed to remove the existing lock/unlock inside eeh_rmv_device() which is no longer necessary. This is causing the eehd to hang on the lock which it actually holds when that code path is taken.
[<0>] 0xc00000011c78f870
[<0>] __switch_to+0xfc/0x1a0 [<0>] pci_lock_rescan_remove+0x30/0x44 [<0>] eeh_rmv_device+0x290/0x2e0 [<0>] eeh_pe_dev_traverse+0x80/0x130 [<0>] eeh_reset_device+0xcc/0x23c [<0>] eeh_handle_normal_event+0x830/0xa80 [<0>] eeh_event_handler+0xf8/0x190 [<0>] kthread+0x194/0x1b0 [<0>] start_kernel_thread+0x14/0x18
The issue is seen for cases where the errors are detected on the PHB directly AND|OR for devices where the driver error_detected() returns PCI_ERS_RESULT_NEED_RESET, and driver being not EEH sensitive(i.e no error handlers like slot_reset(), resume() etc defined).
--- arch/powerpc/kernel/eeh_driver.c | 2 -- 1 file changed, 2 deletions(-)
arch/powerpc/kernel/eeh_driver.c +0 -2
@@ -533,9 +533,7 @@ static void eeh_rmv_device(struct eeh_deif (rmv_data)list_add (&edev->rmv_entry, &rmv_data->removed_vf_list); }else { -pci_lock_rescan_remove ();pci_stop_and_remove_bus_device (dev); -pci_unlock_rescan_remove (); } }
Greg Kroah-Hartman
maintainerPATCH 452/733 powerpc: pci-ioda: Fix the stale irq chip reference
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivaprasad G Bhat <[email protected]>
commit d96171d911e3b89ca2957c04264019cf2f96287b upstream.
The commit f0ac60e6e311 ("powerpc/powernv/pci: Switch to use msi_create_parent_irq_domain()") removed the legacy MSI irq chip pnv_pci_msi_irq_chip but left behind the static definition of it and its reference in is_pnv_opal_msi().
The KVM IRQ bypass for vfio devices is broken because the comparision in is_pnv_opal_msi() fails on the comparision with stale unused variable showing the below errors in dmesg.
kvmppc_set_passthru_irq_hv: Could not assign IRQ map for (X,Y) kvmppc_set_passthru_irq (irq X, gsi Y) fails: -2
vfio-pci A:B:C.D irq bypass producer (eventfd Z) registration fails: -2
The patch removes the stale variable definition and fixes the is_pnv_opal_msi() by comparing against the chip name prefix.
--- arch/powerpc/platforms/powernv/pci-ioda.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/powerpc/platforms/powernv/pci-ioda.c +2 -4
@@ -1623,15 +1623,13 @@ int64_t pnv_opal_pci_msi_eoi(struct irq_return opal_pci_msi_eoi (phb->opal_id, d->parent_data->hwirq); } -static struct irq_chip pnv_pci_msi_irq_chip; -/* * Returns true iff chip is something that we could call * pnv_opal_pci_msi_eoi for. */ bool is_pnv_opal_msi (struct irq_chip *chip) { -return chip == &pnv_pci_msi_irq_chip; +return chip && chip->name &&str_has_prefix (chip->name,"PNV-" ); }EXPORT_SYMBOL_GPL (is_pnv_opal_msi);
@@ -1728,7 +1726,7 @@ static const struct msi_parent_ops pnv_m .chip_flags = MSI_CHIP_FLAG_SET_EOI, .bus_select_token = DOMAIN_BUS_NEXUS, .bus_select_mask = MATCH_PCI_MSI, - .prefix = "PNV-", + .prefix = "PNV-", /* Note: is_pnv_opal_msi() uses this */ .init_dev_msi_info = pnv_init_dev_msi_info, };
Greg Kroah-Hartman
maintainerPATCH 453/733 x86/amd_node: Avoid divide by zero on virtualized systems
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Andryuk <[email protected]>
commit 72bd92bd8190d7869ecb462649ca40f297822a33 upstream.
On a virtualized system, the number of nodes does not have a relationship to the number of roots. A Xen PVH dom0 can calculate roots_per_node as 0, which crashes with a divide by zero in:
if (count++ % roots_per_node)
because the underlying topology code on Xen ends up making num_nodes 2 and num_roots 1 and the integer division result is 0.
The issue is seen with Xen, but it could affect other systems.
Set roots_per_node to 1 in this case. Print a firmware bug when this is performed for non-virtualized systems.
[ bp: Massage commit message. ]
--- arch/x86/kernel/amd_node.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/x86/kernel/amd_node.c +5 -0
@@ -287,6 +287,11 @@ static int __init amd_smn_init(void)return -ENOMEM ; roots_per_node = num_roots / num_nodes; +if (!roots_per_node) { +if (!cpu_feature_enabled (X86_FEATURE_HYPERVISOR )) +pr_warn (FW_BUG "Error detecting roots per node.\n" ); + roots_per_node =1 ; + } count =0 ; node =0 ;
Greg Kroah-Hartman
maintainerPATCH 454/733 x86/MCE/AMD: Fix inverted interrupt enablement during storm handling
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jasjeet Rangi <[email protected]>
commit d2929113b15bfc06793b852aeba3d2db6d79fcc9 upstream.
mce_amd_handle_storm() currently does the opposite of what storm handling needs: it enables thresholding interrupts when a storm is detected and disables them when the storm subsides.
Flip the "on" function argument before passing it to threshold_restart_bank() as it should have been done.
To clarify: "on" to mce_handle_storm() means, the storm is on now when "on" is true, and off when "on" is false.
[ bp: Simplify. ]
--- arch/x86/kernel/cpu/mce/amd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/cpu/mce/amd.c +1 -1
@@ -864,7 +864,7 @@ static void amd_deferred_error_interruptvoid mce_amd_handle_storm (unsigned int bank,bool on) { -threshold_restart_bank (bank, on); +threshold_restart_bank (bank, !on); }static void amd_reset_thr_limit (unsigned int bank)
Greg Kroah-Hartman
maintainerPATCH 455/733 x86/amd_node: Fix potential NULL pointer dereference
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Andryuk <[email protected]>
commit aefdbd574a362dcf7569bada6d72f64a006b9fb9 upstream.
amd_smn_read/write() are exported functions around __amd_smn_rw(), so they are always available even if amd_smn_init() fails. In that case, 'amd_roots' is NULL and __amd_smn_rw() will access uninitialized memory.
Then, commit:
83518453074d ("x86/amd_node: Add SMN offsets to exclusive region access")
added the 'smn_exclusive' flag, which indicated the calls to pci_request_config_region_exclusive() succeeded, to prevent concurrent userspace access.
Commit:
0a4b61d9c2e4 ("x86/amd_node: Fix AMD root device caching")
re-ordered initialization so pci_request_config_region_exclusive() is called earlier and a failure exits amd_smn_init() before allocating 'amd_roots'. The setting of 'smn_exclusive' moved to the end of amd_smn_init(), after 'amd_roots' is allocated. It became redundant and can be removed.
Replace 'smn_exclusive' with directly checking 'amd_roots', to fix a potential NULL pointer dereference and to simplify the logic.
[ bp: Reorg commit message, touchup comment. ]
[ mingo: Rebase & further touchups. ]
--- arch/x86/kernel/amd_node.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
arch/x86/kernel/amd_node.c +8 -6
@@ -38,7 +38,6 @@ static struct pci_dev **amd_roots;/* Protect the PCI config register pairs used for SMN. */ static DEFINE_MUTEX (smn_mutex); -static bool smn_exclusive;#define SMN_INDEX_OFFSET 0x60#define SMN_DATA_OFFSET 0x64
@@ -91,11 +90,16 @@ static int __amd_smn_rw(u8 i_off, u8 d_oif (node >=amd_num_nodes ())return err; - root = amd_roots[node]; -if (!root) +/* +* Uninitialized amd_roots indicates pci_request_config_region_exclusive() +* didn't run or failed and thus the kernel cannot rely on having +* exclusive access to SMN registers so prevent that. +*/ +if (!amd_roots)return err; -if (!smn_exclusive) + root = amd_roots[node]; +if (!root)return err;guard (mutex)(&smn_mutex);
@@ -313,8 +317,6 @@ static int __init amd_smn_init(void)debugfs_create_file ("value" ,0600 , debugfs_dir,NULL , &smn_value_fops); } - smn_exclusive = true; -return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 456/733 crypto: x86/aria - add missing vzeroupper in AVX2 code
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit ac53977611428db3bc0b4ac0225e19c3e08ae50b upstream.
Since the AVX2 optimized ARIA code uses YMM registers, execute vzeroupper before returning from it. This is needed to avoid degrading the performance of any later SSE code that may happen to be executed.
--- arch/x86/crypto/aria-aesni-avx2-asm_64.S | 6 ++++++ 1 file changed, 6 insertions(+)
arch/x86/crypto/aria-aesni-avx2-asm_64.S +6 -0
@@ -982,6 +982,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_enc %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_encrypt_32way)
@@ -1007,6 +1008,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_dec %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_decrypt_32way)
@@ -1209,6 +1211,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_ctr %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %r10); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_ctr_crypt_32way)
@@ -1359,6 +1362,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfn %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_gfni_encrypt_32way)
@@ -1384,6 +1388,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfn %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_gfni_decrypt_32way)
@@ -1428,6 +1433,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfn %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %r10); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_gfni_ctr_crypt_32way)
Greg Kroah-Hartman
maintainerPATCH 457/733 crypto: x86/aria - add missing vzeroupper in AVX-512 code
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 60892a384aa1e65d0e703e1c513417bdf0c80777 upstream.
Since the AVX-512 optimized ARIA code uses ZMM registers, execute vzeroupper before returning from it. This is needed to avoid degrading the performance of any later SSE code that may happen to be executed.
--- arch/x86/crypto/aria-gfni-avx512-asm_64.S | 3 +++ 1 file changed, 3 insertions(+)
arch/x86/crypto/aria-gfni-avx512-asm_64.S +3 -0
@@ -800,6 +800,7 @@ SYM_TYPED_FUNC_START(aria_gfni_avx512_en %zmm9, %zmm8, %zmm11, %zmm10, %zmm12, %zmm13, %zmm14, %zmm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_gfni_avx512_encrypt_64way)
@@ -825,6 +826,7 @@ SYM_TYPED_FUNC_START(aria_gfni_avx512_de %zmm9, %zmm8, %zmm11, %zmm10, %zmm12, %zmm13, %zmm14, %zmm15, %rax); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_gfni_avx512_decrypt_64way)
@@ -966,6 +968,7 @@ SYM_TYPED_FUNC_START(aria_gfni_avx512_ct %zmm9, %zmm8, %zmm11, %zmm10, %zmm12, %zmm13, %zmm14, %zmm15, %r10); + vzeroupper; FRAME_END RET; SYM_FUNC_END(aria_gfni_avx512_ctr_crypt_64way)
Greg Kroah-Hartman
maintainerPATCH 458/733 x86/amd_node: Fix PCI device reference counting in amd_smn_init()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yazen Ghannam <[email protected]>
commit 27600805e62f800bacf990354632eae4e487d34c upstream.
The local "root" pointer is a temporary variable used during the device search. Therefore, refcount related to the search iterators should be cleaned up after the search is complete.
Use the __free() cleanup macro to ensure the refcount is decremented when the temporary pointer goes out of scope.
Additionally, increment the refcount when caching a root pointer. This ensures the in-use refcount is separate from the temporary search refcounting.
Finally, drop the redundant "root = NULL" before the second search loop. The pci_get_class() iterator always decrements the refcount of its "from" argument, so the first loop can only fall through with "root" already NULL.
--- arch/x86/kernel/amd_node.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/x86/kernel/amd_node.c +2 -4
@@ -251,7 +251,7 @@ __setup("amd_smn_debugfs_enable", amd_smstatic int __init amd_smn_init (void ) {u16 count, num_roots, roots_per_node, node, num_nodes; -struct pci_dev *root; + struct pci_dev *root __free(pci_dev_put) = NULL;if (!cpu_feature_enabled (X86_FEATURE_ZEN ))return 0 ;
@@ -262,7 +262,6 @@ static int __init amd_smn_init(void)return 0 ; num_roots =0 ; - root =NULL ;while ((root =get_next_root (root))) {pci_dbg (root,"Reserving PCI config space\n" );
@@ -299,14 +298,13 @@ static int __init amd_smn_init(void) count =0 ; node =0 ; - root =NULL ;while (node < num_nodes && (root =get_next_root (root))) {/* Use one root for each node and skip the rest. */ if (count++ % roots_per_node)continue ;pci_dbg (root,"is root for AMD node %u\n" , node); - amd_roots[node++] = root; + amd_roots[node++] =pci_dev_get (root); }if (enable_dfs) {
Greg Kroah-Hartman
maintainerPATCH 459/733 x86/mm: Fix user-space data loss with MADV_FREE and THP
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vernon Yang <[email protected]>
commit f7491d7c81db0e7c304a7bd757a76d2fbeaff80e upstream.
Some of users of Polars (a data analytics library) have lost production data from this bug. They seem to have just the right combination of huge pages, MADV_FREE and heavy reclaim pressure.
pmd_modify() masks the old value with (_HPAGE_CHG_MASK & ~_PAGE_DIRTY), silently discarding the hardware dirty bit. The subsequent pmd_mksaveddirty() call is supposed to transfer _PAGE_DIRTY into _PAGE_SAVED_DIRTY when write-protecting, but the dirty bit was already stripped from the value, so there is nothing left to transfer.
Contrast with pte_modify(), which keeps _PAGE_DIRTY_BITS in its mask, and pud_modify(), which keeps _HPAGE_CHG_MASK untouched: pmd_modify() is the odd one out. Any pmd_modify() on a writable, dirty PMD loses the dirty state.
One visible consequence is data loss with MADV_FREE on PMD-mapped THP:
memset(buf, 0x5A, size); // PMD-mapped THP, PMD dirty
madvise(buf, size, MADV_FREE); // PMD cleaned but left writable,
// folio marked lazyfree
memset(buf, 0x5A, size); // hardware sets _PAGE_DIRTY again
mprotect(buf, size, PROT_READ); // pmd_modify() drops the dirty bit
mprotect(buf, size, PROT_READ|PROT_WRITE);
// ... memory pressure ...Reclaim (e.g. under memcg pressure) then finds the lazyfree folio with no dirty bit set anywhere and frees it in __discard_anon_folio_pmd_locked(), even though the data was rewritten after MADV_FREE; subsequent reads fault in fresh zero pages. NUMA hinting alone can trigger the same loss, as do_huge_pmd_numa_page() restores the PMD through pmd_modify() as well.
PMD-mapped file THPs are affected too: mprotect()/NUMA hinting dropping the dirty bit means rewritten data is never written back.
Fix it by keeping _PAGE_DIRTY in the preserved mask, exactly like pte_modify() and pud_modify() do. The existing pmd_mksaveddirty()/pmd_clear_saveddirty() pair then performs the hardware-dirty <-> saved-dirty transition based on the write bit, preserving the shadow-stack encoding rules.
--- arch/x86/include/asm/pgtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/pgtable.h +1 -1
@@ -806,7 +806,7 @@ static inline pmd_t pmd_modify(pmd_t pmdpmdval_t val =pmd_val (pmd), oldval = val;pmd_t pmd_result; - val &= (_HPAGE_CHG_MASK & ~_PAGE_DIRTY); + val &= _HPAGE_CHG_MASK; val |=check_pgprot (newprot) & ~_HPAGE_CHG_MASK; val =flip_protnone_guard (oldval, val,PHYSICAL_PMD_PAGE_MASK );
Greg Kroah-Hartman
maintainerPATCH 460/733 x86/cfi: Fix FineIBT hash offset in cfi_get_func_hash()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Soheil Hassas Yeganeh <[email protected]>
commit 5a5d26f2cfe13467166219f6bf58099326912ddb upstream.
The switch of the FineIBT preamble from "subl $hash, %r10d" to the shorter "subl $hash, %eax" moved the hash immediate from offset 7 to offset 5 of the preamble. fineibt_preamble_hash was updated to match, but the open-coded offset in cfi_get_func_hash() was missed and it still reads the hash at offset 7.
cfi_get_func_hash() is used by the BPF JIT to give a struct_ops trampoline the CFI hash of the stub function it stands in for. With FineIBT the trampoline now gets the upper half of the real hash followed by the first two bytes of the next instruction, so the first indirect call from the kernel into a struct_ops program, tcp_init_congestion_control() calling ->init() of a BPF congestion control for example, fails the FineIBT check and the kernel dies with a CFI failure.
Move the FineIBT preamble template and its offset defines above cfi_get_func_hash() and use fineibt_preamble_hash there, so every reader of the preamble shares one definition of its layout. The CFI_FINEIBT arm is only built with CONFIG_FINEIBT, the only configuration in which cfi_mode can take that value. cfi_get_func_arity() does not need the same treatment: the __bhi_args call whose displacement it reads still ends at the function address.
--- arch/x86/kernel/alternative.c | 72 ++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 34 deletions(-)
arch/x86/kernel/alternative.c +38 -34
@@ -1207,6 +1207,41 @@ static bool cfi_debug __ro_after_init;bool cfi_bhi__ro_after_init = false;#endif +#ifdef CONFIG_FINEIBT +/* +* <fineibt_preamble_start>: +* 0: f3 0f 1e fa endbr64 +* 4: 2d 78 56 34 12 sub $0x12345678, %eax +* 9: 2e 0f 85 03 00 00 00 jne,pn 13 <fineibt_preamble_start+0x13> +* 10: 0f 1f 40 d6 nopl -0x2a(%rax) +* +* Note that the JNE target is the 0xD6 byte inside the NOPL, this decodes as +* UDB on x86_64 and raises #UD. +*/ +asm(".pushsection .rodata \n" +"fineibt_preamble_start: \n" +" endbr64 \n" +" subl $0x12345678, %eax \n" +"fineibt_preamble_bhi: \n" +" cs jne.d32 fineibt_preamble_start+0x13 \n" +"#fineibt_func: \n" +" nopl -42(%rax) \n" +"fineibt_preamble_end: \n" +".popsection\n" +); + +extern u8 fineibt_preamble_start[]; +extern u8 fineibt_preamble_bhi[]; +extern u8 fineibt_preamble_end[]; + +#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start) +#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start) +#define fineibt_preamble_ud 0x13 +#define fineibt_preamble_hash 5 + +#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE) +#endif /* CONFIG_FINEIBT */ +#ifdef CONFIG_CFI u32 cfi_get_func_hash (void *func) {
@@ -1214,9 +1249,11 @@ u32 cfi_get_func_hash(void *func) func -=cfi_get_offset ();switch (cfi_mode) { +#ifdef CONFIG_FINEIBT case CFI_FINEIBT : - func +=7 ; + func += fineibt_preamble_hash;break ; +#endif case CFI_KCFI : func +=1 ;break ;
@@ -1359,39 +1396,6 @@ early_param("cfi", cfi_parse_cmdline);*/ /* -* <fineibt_preamble_start>: -* 0: f3 0f 1e fa endbr64 -* 4: 2d 78 56 34 12 sub $0x12345678, %eax -* 9: 2e 0f 85 03 00 00 00 jne,pn 13 <fineibt_preamble_start+0x13> -* 10: 0f 1f 40 d6 nopl -0x2a(%rax) -* -* Note that the JNE target is the 0xD6 byte inside the NOPL, this decodes as -* UDB on x86_64 and raises #UD. -*/ -asm(".pushsection .rodata \n" -"fineibt_preamble_start: \n" -" endbr64 \n" -" subl $0x12345678, %eax \n" -"fineibt_preamble_bhi: \n" -" cs jne.d32 fineibt_preamble_start+0x13 \n" -"#fineibt_func: \n" -" nopl -42(%rax) \n" -"fineibt_preamble_end: \n" -".popsection\n" -); - -extern u8 fineibt_preamble_start[]; -extern u8 fineibt_preamble_bhi[]; -extern u8 fineibt_preamble_end[]; - -#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start) -#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start) -#define fineibt_preamble_ud 0x13 -#define fineibt_preamble_hash 5 - -#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE) - -/* * <fineibt_caller_start>: * 0: b8 78 56 34 12 mov $0x12345678, %eax * 5: 4d 8d 5b f0 lea -0x10(%r11), %r11
Greg Kroah-Hartman
maintainerPATCH 461/733 x86/mm/pat: Acquire init_mm write lock on collapse to avoid UAF
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <[email protected]>
commit a1c7570cedd03372812a5b693732880867babbca upstream.
x86 implements page attribute modification using its Change Page Attributes (CPA) mechanism.
This tracks properties of ranges such as cache mode through x86 page attributes, and as part of that logic manipulates kernel page tables.
Since commit:
41d88484c71c ("x86/mm/pat: restore large ROX pages after fragmentation")
ranges of kernel page table entries can be collapsed into huge page table entries as part of this logic.
As part of this collapse, it frees the page tables which the collapsed entries previously pointed to, and it does so without any relevant locks being held to preclude concurrent kernel page table walkers.
The only way this code can be reached is if CPA_COLLAPSE is specified, and this is only set in set_memory_rox() via:
set_memory_rox()
-> change_page_attr_set_clr()
-> cpa_flush()
-> cpa_collapse_large_pages()
Notable users of this are execmem and BPF when manipulating executable mappings.
However, this is problematic for ptdump as it walks ranges it does not own and thus runs the risk of a use-after-free on page tables freed underneath it.
In addition, concurrent CPA collapse operations are possible which can also cause races.
Resolve the issue by acquiring the mmap write lock on init_mm across the whole operation.
It is safe to acquire a sleeping lock as all the callers invoke set_memory_rox() from process context and in any case, change_page_attr_set_clr() calls vm_unmap_alias() which ultimately takes a mutex, disallowing atomic context here.
--- arch/x86/mm/pat/set_memory.c | 15 ++++++++++++++- include/linux/mmap_lock.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-)
arch/x86/mm/pat/set_memory.c +14 -1
@@ -22,6 +22,7 @@#include <linux/cc_platform.h> #include <linux/set_memory.h> #include <linux/memregion.h> +#include <linux/cleanup.h> #include <asm/e820/api.h> #include <asm/processor.h>
@@ -410,7 +411,7 @@ static void __cpa_flush_tlb(void *data)static int collapse_large_pages (unsigned long addr,struct list_head *pgtables); -static void cpa_collapse_large_pages (struct cpa_data *cpa) +static void __cpa_collapse_large_pages (struct cpa_data *cpa) {unsigned long start, addr, end;struct ptdesc *ptdesc, *tmp;
@@ -448,6 +449,18 @@ static void cpa_collapse_large_pages(strspin_unlock (&cpa_lock); } +static void cpa_collapse_large_pages (struct cpa_data *cpa) +{ +/* +* Take the mmap write lock on init_mm to: +* - Avoid a use-after-free if raced by ptdump (which takes its own +* write lock on init_mm). +* - Serialise concurrent CPA walkers. +*/ + scoped_guard(mmap_write_lock, &init_mm) +__cpa_collapse_large_pages (cpa); +} +static void cpa_flush (struct cpa_data *cpa,int cache) {unsigned int i;
include/linux/mmap_lock.h +2 -0
@@ -622,6 +622,8 @@ static inline void mmap_read_unlock(stru DEFINE_GUARD(mmap_read_lock, struct mm_struct *, mmap_read_lock(_T), mmap_read_unlock(_T)) DEFINE_GUARD_COND(mmap_read_lock, _try, mmap_read_trylock(_T)) +DEFINE_GUARD(mmap_write_lock, struct mm_struct *, + mmap_write_lock(_T), mmap_write_unlock(_T))static inline void mmap_read_unlock_non_owner (struct mm_struct *mm) {
Greg Kroah-Hartman
maintainerPATCH 462/733 x86/alternatives: Exclude text poking against change_page_attr()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pedro Falcato <[email protected]>
commit 1587d3394e254639cc36516256031334095e6ef3 upstream.
Quoted 1 line
From time to time, the following BUG can be observed
in the x86 alternatives patching code [0]:
Quoted 12 lines
kernel BUG at
arch/x86/kernel/alternative.c:2576!Oops: invalid opcode: 0000 [#1] SMP NOPTI CPU: 0 UID: 0 PID: 355 Comm: (udev-worker) Not tainted 7.1.3-1-default #1 PREEMPT(full) openSUSE Tumbleweed 8c1795b03ec64f997e57a8ad38b1161e3b98da64 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS unknown 02/02/2022 RIP: 0010:__text_poke+0x2aa/0x450 Call Trace: <TASK> smp_text_poke_batch_finish+0x2a7/0x320 __static_call_transform+0xb7/0x220 arch_static_call_transform+0x5b/0xb0 __static_call_init+0xe9/0x270 static_call_module_notify+0x11f/0x150
Quoted 8 lines
notifier_call_chain+0x61/0xe0 blocking_notifier_call_chain_robust+0x63/0xc0 load_module+0x1c92/0x20c0 init_module_from_file+0xd8/0x140 idempotent_init_module+0x100/0x2f0 __x64_sys_finit_module+0x71/0xe0 do_syscall_64+0xe1/0x610 entry_SYSCALL_64_after_hwframe+0x76/0x7e
which matches the following BUG_ON() in alternative.c:
/* * If something went wrong, crash and burn since recovery paths are not * implemented. */ BUG_ON(!pages[0] || (cross_page_boundary && !pages[1]));
This can happen if vmalloc_to_page() fails, for any reason. Such can happen if text poking races with CPA, which can possibly result in the collapsing of page tables (or breaking of PMD hugepages). It is not a problem for most users of vmalloc_to_page() (they solely own the vmalloc'd range) but, when CONFIG_ARCH_HAS_EXECMEM_ROX=y, various modules own a single execmem vmalloc range, and can call set_memory_*() in parallel on it. This can happen to race against __text_poke and cause havoc in vmalloc_to_page().
Fix it by excluding against CPA using the init_mm mmap read lock.
[ dhansen: Fix up SoB ordering. The actual code flow here was:
Pedro=>Lorenzo=>Mike=>Me which is reflected in the SoB chain now. I *believe* Mike simply picked up Lorenzo's update to Pedro's post from the Link ]
--- arch/x86/kernel/alternative.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)
arch/x86/kernel/alternative.c +36 -3
@@ -6,6 +6,9 @@#include <linux/vmalloc.h> #include <linux/memory.h> #include <linux/execmem.h> +#include <linux/cleanup.h> +#include <linux/kgdb.h> +#include <linux/mmap_lock.h> #include <asm/text-patching.h> #include <asm/insn.h>
@@ -2547,6 +2550,38 @@ static void text_poke_memset(void *dst,typedef void text_poke_f (void *dst,const void *src,size_t len); +static void __poke_vmalloc_pages (struct page **pages,void *addr, +bool cross_page_boundary) +{ + pages[0 ] =vmalloc_to_page (addr); +if (cross_page_boundary) + pages[1 ] =vmalloc_to_page (addr +PAGE_SIZE ); +} + +static void poke_vmalloc_pages (struct page **pages,void *addr, +bool cross_page_boundary) +{ +if (in_dbg_master ()) { +/* +* If called from kgdb cannot sleep, but all other CPUs stopped +* anyway so safe to proceed without locks +*/ +__poke_vmalloc_pages (pages, addr, cross_page_boundary); + }else { +/* +* execmem ROX ranges are shared between modules and can be +* collapsed to huge PMD entries, and this collapse can happen +* concurrently with a racing set_memory_rox(). +* +* Prevent vmalloc_to_page() from racing by acquiring an +* init_mm read lock which pairs with the init_mm write lock in +* cpa_collapse_large_pages(). +*/ +guard (mmap_read_lock)(&init_mm); +__poke_vmalloc_pages (pages, addr, cross_page_boundary); + } +} +static void *__text_poke (text_poke_f func,void *addr,const void *src,size_t len) {bool cross_page_boundary =offset_in_page (addr) + len >PAGE_SIZE ;
@@ -2564,9 +2599,7 @@ static void *__text_poke(text_poke_f funBUG_ON (!after_bootmem);if (!core_kernel_text ((unsigned long )addr)) { - pages[0 ] =vmalloc_to_page (addr); -if (cross_page_boundary) - pages[1 ] =vmalloc_to_page (addr +PAGE_SIZE ); +poke_vmalloc_pages (pages, addr, cross_page_boundary); }else { pages[0 ] =virt_to_page (addr);WARN_ON (!PageReserved (pages[0 ]));
Greg Kroah-Hartman
maintainerPATCH 463/733 mm/slab: take n->list_lock in __slab_try_return_freelist() to avoid race
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Yoo (Meta) <[email protected]>
commit 4a724bcf5d703e18957397914d79156fa2cf1174 upstream.
Commit ba7425312607 ("mm, slab: add an optimistic __slab_try_return_freelist()") incorrectly assumed that nobody has freed an object to the slab as long as slab->freelist is NULL and cmpxchg succeeds.
However, as reported by Hyunwoo Kim [1], other CPUs might have freed an object to the slab, insert the slab to the partial list, then allocated an object from the slab, and be in the middle of removing the slab from the list under n->list_lock.
Since __refill_objects_node() puts the slab back on pc.slabs outside n->list_lock, it might insert the slab into that list while the slab is concurrently being removed from n->partial. This led to a list corruption [1]:
list_add corruption. next->prev should be prev
(ffff888100000248), but was dead000000000122.
(next=ffffea000416e410).
kernel BUG at lib/list_debug.c:29!
Oops: invalid opcode: 0000 [#1] SMP NOPTI CPU: 1 UID: 65534 PID: 144 Comm: poc Not tainted 7.2.0-16172-gcf72cbb39da8-dirty #1 PREEMPT(lazy) RIP: 0010:__list_add_valid_or_report+0x80/0xd0 ... Call Trace: alloc_from_new_slab+0x183/0x300 ___slab_alloc+0x31c/0x890 __kmalloc_noprof+0x3d4/0x800 lsm_blob_alloc+0x2d/0x50 security_msg_msg_alloc+0x26/0x90 load_msg+0x1aa/0x210 do_msgsnd+0x91/0x800 do_syscall_64+0x109/0x5d0 entry_SYSCALL_64_after_hwframe+0x77/0x7f ... Kernel panic - not syncing: Fatal exception
This is a classic ABA problem where cmpxchg succeeds but the state has changed since __refill_objects_node() took the freelist from the slab.
As Vlastimil Babka mentioned [2], it should be rare to return more than one slab (due to the racy read of slab->counters in get_partial_node_bulk()). Therefore, instead of introducing additional complexity, acquire and release n->list_lock twice in the worst case.
Return the slab directly to the partial list and hold n->list_lock across the cmpxchg and add_partial(). This is similar to the initial version of commit ba7425312607 [3]. This is enough to avoid the race as the list manipulation is serialized by n->list_lock. While at it, bring back unlikely() hint now that the condition is unlikely.
--- mm/slub.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
mm/slub.c +13 -7
@@ -5612,10 +5612,12 @@ static noinline void free_to_partial_lis* * Fail if the slab isn't full anymore due to a concurrent free. */ -static bool __slab_try_return_freelist (struct kmem_cache *s,struct slab *slab, -void *head,int cnt) +static bool __slab_try_return_freelist (struct kmem_cache *s, +struct kmem_cache_node *n, +struct slab *slab,void *head,int cnt) {struct freelist_counters old, new; +unsigned long flags; old.freelist = slab->freelist; old.counters = slab->counters;
@@ -5627,9 +5629,15 @@ static bool __slab_try_return_freelist(s new.counters = old.counters; new.inuse -= cnt; -if (!slab_update_freelist (s, slab, &old, &new,"__slab_try_return_freelist" )) +spin_lock_irqsave (&n->list_lock, flags); + +if (!slab_update_freelist (s, slab, &old, &new,"__slab_try_return_freelist" )) { +spin_unlock_irqrestore (&n->list_lock, flags);return false; + } +add_partial (n, slab,ADD_TO_TAIL ); +spin_unlock_irqrestore (&n->list_lock, flags);return true; }
@@ -7202,10 +7210,8 @@ __refill_objects_node(struct kmem_cachevoid *head = object;void *tail; -if (__slab_try_return_freelist (s, slab, head, count)) { -list_add (&slab->slab_list, &pc.slabs); +if (__slab_try_return_freelist (s, n, slab, head, count))break ; - } do { tail = object;
@@ -7218,7 +7224,7 @@ __refill_objects_node(struct kmem_cachebreak ; } -if (!list_empty (&pc.slabs)) { +if (unlikely (!list_empty (&pc.slabs))) {spin_lock_irqsave (&n->list_lock, flags);list_for_each_entry (slab, &pc.slabs, slab_list)
Greg Kroah-Hartman
maintainerPATCH 464/733 ipv6: fix fib6 walker UAF on seq stop
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit 19b4ed644d68098cc62ab612727f40d30f43476c upstream.
ipv6_route_iter_active() treats a walker in FWS_U at the table root as already unlinked. fib6_del_route() can move a still-linked walker into that same state when the current leaf is the last route at the root, so ipv6_route_native_seq_stop() skips fib6_walker_unlink(). The seq private object can then be freed while it remains on net->ipv6.fib6_walkers. A later route deletion walks the dangling list and uses the freed walker.
Use the list head as membership state and reinitialize it when unlinking. Keep the existing w->node check so a never-started iterator with a zeroed private object is not treated as linked.
The same stop helper is used by /proc/net/ipv6_route and by the BPF ipv6_route iterator. The BPF show path only widens the race.
--- net/ipv6/ip6_fib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/ipv6/ip6_fib.c +2 -2
@@ -85,7 +85,7 @@ static void fib6_walker_link(struct netstatic void fib6_walker_unlink (struct net *net,struct fib6_walker *w) {write_lock_bh (&net->ipv6.fib6_walker_lock); -list_del (&w->lh); +list_del_init (&w->lh);write_unlock_bh (&net->ipv6.fib6_walker_lock); }
@@ -2758,7 +2758,7 @@ static void *ipv6_route_seq_start(structstatic bool ipv6_route_iter_active (struct ipv6_route_iter *iter) {struct fib6_walker *w = &iter->w; -return w->node && !(w->state ==FWS_U && w->node == w->root); +return w->node && !list_empty (&w->lh); }static void ipv6_route_native_seq_stop (struct seq_file *seq,void *v)
Greg Kroah-Hartman
maintainerPATCH 465/733 ipmr: account multicast table and route memory
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit b7ee18725f2292ab554aa96a101ae42d45f008bd upstream.
A netadmin in a user+net namespace can create many IPv4 and IPv6 multicast routing tables with MRT_TABLE and MRT6_TABLE. Each unseen id allocates an mr_table via the shared mr_table_alloc(), links it into the per-net list, and leaves it until netns teardown. Those objects were not charged to memcg, so the host unreclaimable slab grows with the table count.
Account mr_table allocations with GFP_KERNEL_ACCOUNT and mark the IPv4/IPv6 MFC caches SLAB_ACCOUNT. This matches the established handling of IP addresses, routes and alternate interface names.
Unresolved MFC entries are still allocated from softIRQ with GFP_ATOMIC and are not charged. They expire after 10 seconds and are bounded by the socket receive queue; see commit 0079ad8e8dc3 ("ipmr: remove hard code cache_resolve_queue_len limit").
--- net/ipv4/ipmr.c | 3 ++- net/ipv4/ipmr_base.c | 2 +- net/ipv6/ip6mr.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-)
net/ipv4/ipmr.c +2 -1
@@ -3376,7 +3376,8 @@ int __init ip_mr_init(void) {int err; - mrt_cachep =KMEM_CACHE (mfc_cache,SLAB_HWCACHE_ALIGN |SLAB_PANIC ); + mrt_cachep =KMEM_CACHE (mfc_cache, +SLAB_HWCACHE_ALIGN |SLAB_PANIC |SLAB_ACCOUNT ); err =register_pernet_subsys (&ipmr_net_ops);if (err)
net/ipv4/ipmr_base.c +1 -1
@@ -52,7 +52,7 @@ mr_table_alloc(struct net *net, u32 id,struct mr_table *mrt;int err; - mrt =kzalloc_obj (*mrt); + mrt =kzalloc_obj (*mrt,GFP_KERNEL_ACCOUNT );if (!mrt)return ERR_PTR (-ENOMEM ); mrt->id = id;
net/ipv6/ip6mr.c +1 -1
@@ -1427,7 +1427,7 @@ int __init ip6_mr_init(void) {int err; - mrt_cachep =KMEM_CACHE (mfc6_cache,SLAB_HWCACHE_ALIGN ); + mrt_cachep =KMEM_CACHE (mfc6_cache,SLAB_HWCACHE_ALIGN |SLAB_ACCOUNT );if (!mrt_cachep)return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 466/733 reboot: fix cad_pid use-after-free race
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft) <[email protected]>
commit 5a88f78df753993469dab4d1831f8fb4256a9468 upstream.
cad_pid is a single kernel-wide struct pid pointer. proc_do_cad_pid() reads it and passes it to pid_vnr() without protecting the lifetime of the referenced struct pid. A concurrent writer can replace cad_pid and drop the final reference to the old struct pid after the reader has loaded the pointer but before pid_vnr() has finished dereferencing it, causing a use-after-free.
kill_cad_pid() has the same lifetime race when it passes cad_pid to kill_pid().
At the time this issue was reported, an unprivileged user could reach the sysctl through user and PID namespaces because cad_pid was registered in pid_table[]. Moving cad_pid back to the global reboot sysctl table corrected that namespace and permission mismatch, but did not fix the underlying lifetime race.
Fix this by treating cad_pid as an RCU-protected pointer at both read sites and by waiting for a grace period before dropping the old reference on the write side.
call_rcu(&old_pid->rcu, ...) cannot be used here because free_pid() also queues pid->rcu; queueing the same rcu_head twice can corrupt the RCU callback list.
Original KASAN crash stack:
kernel/pid.c:545 pid_nr_ns() # reads freed pid->level kernel/pid.c:556 pid_vnr() # calls pid_nr_ns() kernel/pid.c:775 proc_do_cad_pid() # calls pid_vnr(cad_pid)
--- include/linux/sched.h | 2 +- include/linux/sched/signal.h | 5 +---- init/main.c | 2 +- kernel/reboot.c | 19 +++++++++++++++---- kernel/signal.c | 12 ++++++++++++ 5 files changed, 30 insertions(+), 10 deletions(-)
include/linux/sched.h +1 -1
@@ -1775,7 +1775,7 @@ static inline bool is_lazy_mmu_mode_acti }#endif -extern struct pid *cad_pid; +extern struct pid __rcu *cad_pid;/* * Per process flags
include/linux/sched/signal.h +1 -4
@@ -562,10 +562,7 @@ static inline sigset_t *sigmask_to_save(return res; } -static inline int kill_cad_pid (int sig,int priv) -{ -return kill_pid (cad_pid, sig, priv); -} +int kill_cad_pid (int sig,int priv);/* These can be the second arg to send_sig_info/send_group_sig_info. */ #define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0)
init/main.c +1 -1
@@ -1636,7 +1636,7 @@ static noinline void __init kernel_init_*/ set_mems_allowed (node_states[N_MEMORY ]); - cad_pid =get_pid (task_pid (current)); +rcu_assign_pointer (cad_pid,get_pid (task_pid (current)));smp_prepare_cpus (setup_max_cpus);
kernel/reboot.c +15 -4
@@ -13,7 +13,9 @@#include <linux/kexec.h> #include <linux/kmod.h> #include <linux/kmsg_dump.h> +#include <linux/rcupdate.h> #include <linux/reboot.h> +#include <linux/sched/signal.h> #include <linux/suspend.h> #include <linux/syscalls.h> #include <linux/syscore_ops.h>
@@ -24,8 +26,7 @@*/ static int C_A_D =1 ; -struct pid *cad_pid; -EXPORT_SYMBOL (cad_pid); +struct pid __rcu *cad_pid;#if defined(CONFIG_ARM )#define DEFAULT_REBOOT_MODE = REBOOT_HARD
@@ -1371,10 +1372,14 @@ static int proc_do_cad_pid(const struct {struct ctl_table tmp_table = *table;struct pid *new_pid; +struct pid *old_pid;pid_t tmp_pid;int r; - tmp_pid =pid_vnr (cad_pid); +rcu_read_lock (); + tmp_pid =pid_vnr (rcu_dereference (cad_pid)); +rcu_read_unlock (); + tmp_table.data = &tmp_pid; r =proc_dointvec (&tmp_table, write, buffer, lenp, ppos);
@@ -1385,7 +1390,13 @@ static int proc_do_cad_pid(const structif (!new_pid)return -ESRCH ; -put_pid (xchg (&cad_pid, new_pid)); + old_pid =unrcu_pointer (xchg (&cad_pid,RCU_INITIALIZER (new_pid))); +/* +* Wait for cad_pid readers before put_pid(). We cannot use +* call_rcu() here because free_pid() already owns pid->rcu. +*/ +synchronize_rcu (); +put_pid (old_pid);return 0 ; }
kernel/signal.c +12 -0
@@ -1903,6 +1903,18 @@ int kill_pid(struct pid *pid, int sig, i }EXPORT_SYMBOL (kill_pid); +int kill_cad_pid (int sig,int priv) +{ +int ret; + +rcu_read_lock (); + ret =kill_pid (rcu_dereference (cad_pid), sig, priv); +rcu_read_unlock (); + +return ret; +} +EXPORT_SYMBOL (kill_cad_pid); +#ifdef CONFIG_POSIX_TIMERS /* * These functions handle POSIX timer signals. POSIX timers use
Greg Kroah-Hartman
maintainerPATCH 467/733 ftrace: Use rcu_assign_pointer() for tmp_ops filter hash
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Hwang <[email protected]>
commit b4dcc18b97913888e8d009624e07c8014ce41b84 upstream.
tmp_ops.func_hash->filter_hash is annotated __rcu, but update_ftrace_direct_mod() assigns hash to it directly. Sparse reports an address-space mismatch.
Use rcu_assign_pointer() for the assignment.
--- kernel/trace/ftrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/ftrace.c +1 -1
@@ -6675,7 +6675,7 @@ int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, b/* Enable the tmp_ops to have the same functions as the hash object. */ ftrace_ops_init (&tmp_ops); - tmp_ops.func_hash->filter_hash = hash; +rcu_assign_pointer (tmp_ops.func_hash->filter_hash, hash); err =register_ftrace_function_nolock (&tmp_ops);if (err)
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 468/733 ftrace: fork: Initialize function graph state before copy_exec_state()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Jean <[email protected]>
commit 08cacffeef8f64f1a222c93467ca84f24a46c953 upstream.
dup_task_struct() copies the parent's task_struct, including ret_stack. ftrace_graph_init_task() clears the copied function graph state, but it currently runs after copy_exec_state().
For non-CLONE_VM forks, copy_exec_state() allocates a new task_exec_state. If that allocation fails, copy_process() reaches bad_fork_free and free_task() calls ftrace_graph_exit_task(). Since the child still carries the parent's ret_stack pointer, the unwind frees the parent's active function graph return stack. The parent subsequently accesses freed memory from function_graph_enter_regs().
KASAN reports:
[ 22.190920] ================================================================== [ 22.195899] BUG: KASAN: slab-use-after-free in function_graph_enter_regs+0xa76/0xb90 [ 22.200747] Write of size 8 at addr ff110000054dc0a8 by task repro/1 [ 22.205134] [ 22.210770] CPU: 0 UID: 0 PID: 1 Comm: repro Not tainted 7.2.0-07732-g9328b3b03bdc-dirty #3 PREEMPT(lazy) [ 22.212576] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 22.213750] Call Trace: [ 22.215271] <TASK> [ 22.216242] ? ftrace_stub_direct_tramp+0x10/0x10 [ 22.217774] dump_stack_lvl+0x4e/0x70 [ 22.220531] print_report+0x157/0x4b4 [ 22.223202] ? fixup_red_left+0x9/0x30 [ 22.224407] ? complete_report_info+0x83/0x110 [ 22.226679] ? function_graph_enter_regs+0xa76/0xb90 [ 22.228084] kasan_report+0xce/0x100 [ 22.230109] ? function_graph_enter_regs+0xa76/0xb90 [ 22.232860] ? stack_trace_save+0x4/0xd0 [ 22.234156] function_graph_enter_regs+0xa76/0xb90 [ 22.236090] ? kasan_save_stack+0x30/0x50 [ 22.237752] ? __pfx_function_graph_enter_regs+0x10/0x10 [ 22.238694] ? ring_buffer_lock_reserve+0x345/0xf80 [ 22.239628] ? stack_trace_save+0x4/0xd0 [ 22.242121] ? stack_trace_save+0x4/0xd0 [ 22.243588] ftrace_graph_func+0xda/0x160 [ 22.245362] ? ftrace_stub_direct_tramp+0x10/0x10 [ 22.246520] 0xffffffffa0000095 [ 22.250528] ? stack_trace_save+0x9/0xd0 [ 22.251757] ? ring_buffer_unlock_commit+0x11d/0x5c0 [ 22.253152] stack_trace_save+0x9/0xd0 [ 22.254264] kasan_save_stack+0x30/0x50 [ 22.273631] kasan_save_track+0x14/0x30 [ 22.276763] kasan_save_free_info+0x3b/0x70 [ 22.278296] __kasan_slab_free+0x43/0x70 [ 22.280157] kmem_cache_free+0xbf/0x3b0 [ 22.282963] ? ftrace_stub_direct_tramp+0x10/0x10 [ 22.284001] free_task+0xa2/0x160 [ 22.285699] ? ftrace_stub_direct_tramp+0x10/0x10 [ 22.286752] copy_process+0x2aae/0x7bc0
Initialize the child function graph state immediately after dup_task_struct(), before the first fallible operation.
--- kernel/fork.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
kernel/fork.c +5 -2
@@ -2114,6 +2114,11 @@ __latent_entropy struct task_struct *cop p =dup_task_struct (current, node);if (!p) goto fork_out; +/* +* Must run before the first fallible op, so error paths never +* free the parent's ret_stack. +*/ +ftrace_graph_init_task (p); retval =copy_exec_state (clone_flags, p);if (retval) goto bad_fork_free;
@@ -2140,8 +2145,6 @@ __latent_entropy struct task_struct *cop*/ p->clear_child_tid = (clone_flags &CLONE_CHILD_CLEARTID ) ? args->child_tid :NULL ; -ftrace_graph_init_task (p); -rt_mutex_init_task (p);raw_spin_lock_init (&p->blocked_lock);
Greg Kroah-Hartman
maintainerPATCH 469/733 tracing: Fix memory corruption from the histogram stacktrace modifier
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit a5e70ba87ca8ebc79b4e63de302d03b0625fe153 upstream.
parse_field() sets HIST_FIELD_FL_STACKTRACE from the ".stacktrace" modifier before it looks the field name up, and nothing afterwards checks that the name resolved to a field which holds a stacktrace. create_hist_field() picks HIST_FIELD_FN_STACK on the strength of the field pointer alone, which reads a __data_loc word from the record and follows its low 16 bits as an offset into the same record. event_hist_trigger() takes the first word there as an entry count and copies that many longs into a 31 entry array:
n_entries = *stack; memcpy(entries, ++stack, n_entries * sizeof(unsigned long));
Neither end of that copy is bounded, and the count is whatever the event holds at the offset, so any field will do:
# cd /sys/kernel/tracing/events/sched/sched_process_fork # echo 'hist:keys=parent_pid.stacktrace' > trigger # (true)
BUG: kernel NULL pointer dereference, address: 0000000000000008 RIP: 0010:rb_insert_color+0x18/0x130 timerqueue_linked_add+0x7e/0xd0 enqueue_hrtimer+0x39/0xb0 __hrtimer_run_queues+0x10f/0x1f0 </IRQ> RIP: 0010:memcpy+0xc/0x30 event_hist_trigger+0x165/0x690
The timer interrupt landed on the rbtree the copy had already run over. No debug options are needed for this; KASAN reports the same write as an out-of-bounds read of 13835058055416381440 bytes.
Documentation/trace/histogram.rst already states the rule, "must be a long[] type", so enforce it once the name has been resolved. Names which resolve to no field at all, "hitcount.stacktrace" and the common_* pseudo-fields, are refused for the same reason: they hold no stacktrace to read.
--- kernel/trace/trace_events_hist.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
kernel/trace/trace_events_hist.c +10 -2
@@ -2325,6 +2325,7 @@ parse_field(struct hist_trigger_data *histruct ftrace_event_field *field =NULL ;char *field_name, *modifier, *str;struct trace_array *tr = file->tr; +bool stack_modifier = false; modifier = str =kstrdup (field_str,GFP_KERNEL );if (!modifier)
@@ -2347,9 +2348,10 @@ parse_field(struct hist_trigger_data *hi *flags |=HIST_FIELD_FL_EXECNAME ; else if (strcmp(modifier, "syscall") == 0) *flags |= HIST_FIELD_FL_SYSCALL; - else if (strcmp(modifier, "stacktrace") == 0) + else if (strcmp(modifier, "stacktrace") == 0) { *flags |= HIST_FIELD_FL_STACKTRACE; - else if (strcmp(modifier, "log2") == 0) + stack_modifier = true; + } else if (strcmp(modifier, "log2") == 0) *flags |= HIST_FIELD_FL_LOG2; else if (strcmp(modifier, "usecs") == 0) *flags |= HIST_FIELD_FL_TIMESTAMP_USECS;
@@ -2420,6 +2422,12 @@ parse_field(struct hist_trigger_data *hi } } } + +if (stack_modifier && + (!field || field->filter_type !=FILTER_STACKTRACE )) { +hist_err (tr,HIST_ERR_BAD_FIELD_MODIFIER ,errpos (field_str)); + field =ERR_PTR (-EINVAL ); + } out:kfree (str);
Greg Kroah-Hartman
maintainerPATCH 470/733 tracing: Restore :mod: trailer after parsing in ftrace_set_clr_event()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Weißschuh <[email protected]>
commit 911002e99e15f640f1fdc6d276206beaef59e790 upstream.
While ftrace_set_clr_event() modifies its input buffer during parsing, before returning to the caller the buffer is supposed to be restored to its original state.
This works correctly for the colon between the subsystem and event but not the colon at the beginning of :mod:.
Restore the colon, so the :mod: trailer is not stripped after ftrace_set_clr_event().
--- kernel/trace/trace_events.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/trace/trace_events.c +2 -0
@@ -1462,6 +1462,8 @@ int ftrace_set_clr_event(struct trace_ar/* Put back the colon to allow this to be called again */ if (buf) *(buf -1 ) =':' ; +if (mod) + *(mod -5 ) =':' ;return ret; }
Greg Kroah-Hartman
maintainerPATCH 471/733 tracing: Set the trace clock before registering the histogram trigger
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit 6ede78d0563a2a3ae3e46f9c07cedb5d79645429 upstream.
hist_register_trigger() puts the trigger on the global named_triggers list in cmd_ops->init(), and only then sets the trace clock:
if (data->cmd_ops->init) {
ret = data->cmd_ops->init(data);
if (ret < 0)
goto out;
}
if (hist_data->enable_timestamps) {
ret = tracing_set_clock(file->tr, hist_data->attrs->clock);
if (ret) {
hist_err(tr, HIST_ERR_SET_CLOCK_FAIL, errpos(clock));
goto out;
}The clock string is not checked anywhere before that call, so a named trigger using common_timestamp with an unknown clock fails after it has already become findable. event_hist_trigger_parse() then frees it without taking it off the list, and the next lookup by name reads the freed object:
~# cd /sys/kernel/tracing/events/sched/sched_switch
~# echo 'hist:name=foo:keys=common_pid:ts=common_timestamp:clock=bogus' > trigger
bash: echo: write error: Invalid argument
~# echo 'hist:name=foo:keys=common_pid' > trigger
BUG: KASAN: slab-use-after-free in find_named_trigger+0xac/0xc0 Read of size 8 at addr ffff88800915d760 by task init/1 find_named_trigger+0xac/0xc0 hist_register_trigger+0xc1/0x900 event_hist_trigger_parse+0x3146/0x6af0 event_trigger_write+0xce/0x160 Freed by task 63: kfree+0x154/0x420 trigger_kthread_fn+0xfd/0x160
Set the clock before the trigger is registered, so that nothing which can fail runs after it is published, the way commit 6f86bdeab633 ("tracing: Fix bad hist from corrupting named_triggers list") moved the registration below the rest of the setup.
tracing_set_filter_buffering() is reference counted, so the init failure path has to drop the reference that the clock block now takes first.
--- kernel/trace/trace_events_hist.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
kernel/trace/trace_events_hist.c +9 -6
@@ -6631,12 +6631,6 @@ static int hist_register_trigger(char *g data->cmd_ops = cmd_ops; } -if (data->cmd_ops->init) { - ret = data->cmd_ops->init (data); -if (ret <0 ) - goto out; - } -if (hist_data->enable_timestamps) {char *clock = hist_data->attrs->clock;
@@ -6649,6 +6643,15 @@ static int hist_register_trigger(char *gtracing_set_filter_buffering (file->tr, true); } +if (data->cmd_ops->init) { + ret = data->cmd_ops->init (data); +if (ret <0 ) { +if (hist_data->enable_timestamps) +tracing_set_filter_buffering (file->tr, false); + goto out; + } + } +if (named_data) {remove_hist_vars (hist_data);destroy_hist_data (hist_data);
Greg Kroah-Hartman
maintainerPATCH 472/733 tracing: Fix memory corruption from a "STACKTRACE" histogram key
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit 7f711e62355bb3123a2ca2f97a2facbfebc678c6 upstream.
"cpu", "CPU", "stacktrace" and "STACKTRACE" are generic fields, defined with an offset and a size of zero so that the filter code can match them by name. parse_field() maps them onto their common_* equivalents for backward compatibility, but unlike the common_* names it hands the placeholder back to the caller instead of NULL.
create_hist_field() takes a non-NULL field as a promise that the record carries a stacktrace and picks HIST_FIELD_FN_STACK, so the __data_loc word is read from offset 0, that is from common_type, and its low 16 bits are followed as an offset into the record. What is found there becomes the length of an unbounded memcpy. Pick an event whose id is small enough that the offset stays inside its own record and the length is a kernel text address:
# cd /sys/kernel/tracing # echo 'hist:keys=STACKTRACE' > events/ftrace/print/trigger # echo hello > trace_marker
Oops: general protection fault, probably for non-canonical address RIP: 0010:rb_next+0x23/0x60 </IRQ> RIP: 0010:memcpy+0xc/0x30 event_hist_trigger+0x2e7/0x12c0 Kernel panic - not syncing: Fatal exception in interrupt
Leave the field NULL, which is what the comment above the branch says the code does and what common_stacktrace already does. FILTER_CPU and FILTER_COMM are left alone, their create_hist_field() branches never look at the field.
--- kernel/trace/trace_events_hist.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/trace_events_hist.c +1 -0
@@ -2412,6 +2412,7 @@ parse_field(struct hist_trigger_data *hi *flags |=HIST_FIELD_FL_CPU ; }else if (field && field->filter_type ==FILTER_STACKTRACE ) { *flags |=HIST_FIELD_FL_STACKTRACE ; + field =NULL ; }else if (field && field->filter_type ==FILTER_COMM ) { *flags |=HIST_FIELD_FL_COMM |HIST_FIELD_FL_STRING ; }else {
Greg Kroah-Hartman
maintainerPATCH 473/733 tracing: Take trace_array reference when opening a tracer options file
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
commit ed0aff60f83a9bdc2f6556376ac79c96b3ce7e80 upstream.
When a tracer option file is opened, it is passed a descriptor that points to an element on the trace_array's topts array. This element has information to find the trace array and other information. It uses this element to take a reference of the trace_array so that the trace_array does not get removed while this file is opened.
Unfortunately, there's a race condition where the element itself could be freed by the removal of the instance the trace_array represents causing a use-after-free as this element that is used to find the trace_array to increment its reference counter is also freed when the instance is removed.
To solve this, add a trace_array_tracer_options_get() helper function that will take the address of the element that is passed to the open function by the inode->i_private pointer and search all the trace_arrays under a lock to find the one that the element's address is in the range of the trace_arrays topts array elements. When a match happens, that trace_array's reference would be increased.
Note, there's a race where if an admin was deleting and creating trace instances at the same time and the memory of the old trace_array's array matched the memory of the new trace_array that it could in theory open the option from the wrong trace array. But we do not care because it would be stupid to perform that kind of action. As long as the only thing that can happen is that the option from the wrong trace array is used and doesn't crash the kernel it will only make the user confused. But if they are doing something stupid like this, they are already confused, so no harm done.
--- kernel/trace/trace.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- kernel/trace/trace.h | 1 + 2 files changed, 46 insertions(+), 1 deletion(-)
kernel/trace/trace.c +45 -1
@@ -7715,12 +7715,55 @@ trace_options_write(struct file *filp, creturn cnt; } +static bool tr_option_match (struct trace_array *tr,void *topt) +{ +for (int i =0 ; i < tr->nr_topts; i++) { +struct trace_options *tr_topts = &tr->topts[i]; + +if (topt >= (void *)&tr_topts->topts[0 ] && + topt < (void *)&tr_topts->topts[tr_topts->nr_topts]) +return true; + } +return false; +} + +/* +* The topt is the address of a trace_array->topts[] element that holds the +* the tracer options descriptor. But since the trace_array reference has not +* been taken yet, it cannot be dereferenced as it could have been freed by +* a rmdir of the instance the trace_array represents. +* +* Search the list of trace_arrays and compare the topt to the address of +* the entire trace_array topts array for each trace_array in the list. +* If one is matched, then take the reference and return it. If not, the +* trace_array no longer exits. +*/ +static int trace_array_tracer_options_get (void *topt) +{ +struct trace_array *tr; +int ret; + + ret =security_locked_down (LOCKDOWN_TRACEFS ); +if (ret) +return ret; + +if (tracing_disabled) +return -ENODEV ; + +guard (mutex)(&trace_types_lock); +list_for_each_entry (tr, &ftrace_trace_arrays, list) { +if (tr_option_match (tr, topt)) +return __trace_array_get (tr); + } +return -ENODEV ; +} +static int tracing_open_options (struct inode *inode,struct file *filp) {struct trace_option_dentry *topt = inode->i_private;int ret; - ret =tracing_check_open_get_tr (topt->tr); + ret =trace_array_tracer_options_get (topt);if (ret)return ret;
@@ -7982,6 +8025,7 @@ create_trace_option_files(struct trace_a tr->topts = tr_topts; tr->topts[tr->nr_topts].tracer = tracer; tr->topts[tr->nr_topts].topts = topts; + tr->topts[tr->nr_topts].nr_topts = cnt; tr->nr_topts++;for (cnt =0 ; opts[cnt].name; cnt++) {
kernel/trace/trace.h +1 -0
@@ -227,6 +227,7 @@ struct array_buffer {struct trace_options {struct tracer *tracer;struct trace_option_dentry *topts; +int nr_topts; };struct trace_pid_list *trace_pid_list_alloc (void );
Greg Kroah-Hartman
maintainerPATCH 474/733 tracing: Dont dereference trace_event_file in deferred trigger free
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memiş <[email protected]>
commit bcfe2816e6ec46c3f4c58aa4264476665ddb3f69 upstream.
The enable_event trigger defers trace_event_put_ref() to the trigger free kthread, but the trace_event_file can already be freed when the instance is removed.
Keep the trace_event_call directly in enable_trigger_data so the deferred free does not access the freed trace_event_file.
--- kernel/trace/trace.h | 1 + kernel/trace/trace_events_trigger.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)
kernel/trace/trace.h +1 -0
@@ -1953,6 +1953,7 @@ struct event_trigger_data {struct enable_trigger_data {struct trace_event_file *file; +struct trace_event_call *call;bool enable;bool hist; };
kernel/trace/trace_events_trigger.c +3 -1
@@ -1728,7 +1728,8 @@ static void enable_trigger_private_data_ {struct enable_trigger_data *enable_data = data->private_data; -trace_event_put_ref (enable_data->file->event_call); +/* The file may already be freed here, only the call is kept alive */ +trace_event_put_ref (enable_data->call);kfree (enable_data); }
@@ -1801,6 +1802,7 @@ int event_enable_trigger_parse(struct ev enable_data->hist = hist; enable_data->enable = enable; enable_data->file = event_enable_file; + enable_data->call = event_enable_file->event_call; trigger_data =trigger_data_alloc (cmd_ops, cmd, param, enable_data);if (!trigger_data) {
Greg Kroah-Hartman
maintainerPATCH 475/733 rust: num: seal Integer
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Younes Akhouayri <[email protected]>
commit c6709d5e14072d0e3d02f291daee46a199e5dad3 upstream.
Bounded relies on Integer implementations to describe primitive integer semantics correctly. In particular, it uses Integer::BITS and Signedness to justify unchecked operations.
Integer is currently safe and externally implementable, so an implementation can violate those assumptions and make safe Bounded operations reach undefined behavior.
For example, an Integer implementation for a u8 wrapper can report BITS = 16. Safe code can then cast a Bounded<u16, 9> containing 256 to that wrapper. Its TryFrom<u16> implementation returns Err, and Bounded::cast() calls unwrap_unchecked() on it, causing undefined behavior.
Seal Integer so only the primitive implementations provided by the kernel crate can satisfy it.
--- rust/kernel/num.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
rust/kernel/num.rs +8 -1
@@ -13,9 +13,14 @@ pub enum Unsigned {}/// Designates signed primitive types. pub enum Signed {} +mod private { +pub trait Sealed {} +} +/// Describes core properties of integer types. pub trait Integer: - Sized + private::Sealed + + Sized + Copy + Clone + PartialEq
@@ -54,6 +59,8 @@ pub trait Integer:macro_rules! impl_integer { ($($type:ty: $signedness:ty), *) => { $( + impl private::Sealed for $type {} + impl Integer for $type { type Signedness = $signedness;
Greg Kroah-Hartman
maintainerPATCH 476/733 rust: pin-init: use irrefutable pattern for `stack_pin_init`
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gary Guo <[email protected]>
commit b6b9e6d4abe87b16ab55990b887c6fad8e7a01af upstream.
In Rust 1.100.0, Infallible will become an alias of !. The let binding in stack_pin_init will thus become unreachable and produce an "unreachable expression" warning for the subsequent match, and thus will fail a -Dwarnings build. For this macro, all we need to know is that the error type is uninhabited, so replace this with an irrefutable pattern instead.
[ The error looks like (dummy reproducer):
error: unreachable expression
--> rust/kernel/sync.rs:177:5
|
177 | pin_init::stack_pin_init!(let num = 42u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| unreachable expression
| any code following this expression is unreachable
|
= note: -D unreachable-code implied by -D warnings
= help: to override -D warnings add #[allow(unreachable_code)]
= note: this error originates in the macro pin_init::stack_pin_init (in Nightly builds, run with -Z macro-backtrace for more info)
- Miguel ]
--- rust/pin-init/src/lib.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
rust/pin-init/src/lib.rs +1 -7
@@ -493,13 +493,7 @@ macro_rules! stack_pin_init { (let $var:ident $(: $t:ty)? = $val:expr) => {let val = $val; let mut $var = ::core::pin::pin!($crate::__internal::StackInit$(::<$t>)?::uninit()); - let mut $var = match $crate::__internal::StackInit::init($var, val) { -Ok (res) => res, -Err (x) => { -let x: ::core::convert::Infallible = x; -match x {} - } - }; + let Ok(mut $var) = $crate::__internal::StackInit::init($var, val); }; }
Greg Kroah-Hartman
maintainerPATCH 477/733 rust: allow `clippy::as_underscore` in the generated bindings
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Hubbard <[email protected]>
commit 2ac74c6db40adaa29c50cbb281ae9a6f63de18e1 upstream.
A CLIPPY=1 build emitted about 15000 as _ conversion warnings, all of them in bindgen's generated output and none in hand-written code.
[ The lint messages look like:
error: using as _ conversion
--> rust/bindings/bindings_generated.rs:18947:9
|
18947 | self._bitfield_1.get_const::<0usize, 16u8>() as u32 as _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| help: consider giving the type explicitly: u32
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#as_underscore
= note: -D clippy::as-underscore implied by -D warnings
= help: to override -D warnings add #[allow(clippy::as_underscore)]
- Miguel ]
bindgen 0.73 returns each bitfield read through a trailing as _, and 0.72 returns it through a transmute, which the lint ignores. The bindings and uapi crates allow clippy::all over the generated code. That group does not cover clippy::as_underscore, a restriction lint.
Allow clippy::as_underscore by name in the bindings and uapi crates.
--- rust/bindings/lib.rs | 1 + rust/uapi/lib.rs | 1 + 2 files changed, 2 insertions(+)
rust/bindings/lib.rs +1 -0
@@ -22,6 +22,7 @@#![feature(cfi_encoding)] #[allow(dead_code)] +#[allow(clippy::as_underscore)] #[allow(clippy::cast_lossless)] #[allow(clippy::ptr_as_ptr)] #[allow(clippy::ref_as_ptr)]
rust/uapi/lib.rs +1 -0
@@ -10,6 +10,7 @@#![no_std] #![allow( clippy::all, + clippy::as_underscore, clippy::cast_lossless, clippy::ptr_as_ptr, clippy::ref_as_ptr,
Greg Kroah-Hartman
maintainerPATCH 478/733 rust: allow `unknown_lints` in generated bindings for Rust < 1.88
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miguel Ojeda <[email protected]>
commit f4c3e38111fd84c2c7ae5785755f4a4d476e1cba upstream.
Starting with bindgen 0.73.2 [1], #[allow(unnecessary_transmutes)] are used, even when --rust-target 1.85 is passed.
However, the lint was introduced in Rust 1.88.0. Thus building with older Rust versions warns like:
error: unknown lint: `unnecessary_transmutes`
--> rust/uapi/uapi_generated.rs:26294:13
|
26294 | #[allow(unnecessary_transmutes)]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D unknown-lints` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(unknown_lints)]`Thus allow unknown_lints in the generated bindings -- only when building with older Rust versions.
I have asked upstream if this is intentional [1], i.e. if we are supposed to always allow unknown lints in case bindgen uses such attributes, or whether it is an oversight.
[ Emilio said it wasn't intentional -- we will work around it for now
on the kernel side. - Miguel ]
[ Removed the cfg for allow(unnecessary_transmutes) as suggested by
Gary. - Miguel ]
--- rust/bindings/lib.rs | 3 ++- rust/uapi/lib.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
rust/bindings/lib.rs +2 -1
@@ -27,7 +27,8 @@#[allow(clippy::ptr_as_ptr)] #[allow(clippy::ref_as_ptr)] #[allow(clippy::undocumented_unsafe_blocks)] -#[cfg_attr( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES , allow(unnecessary_transmutes))] +#[cfg_attr(not( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES ), allow(unknown_lints))] +#[allow(unnecessary_transmutes)] #[cfg_attr( CONFIG_RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS, allow(suspicious_runtime_symbol_definitions)
rust/uapi/lib.rs +2 -1
@@ -24,7 +24,8 @@ unreachable_pub, unsafe_op_in_unsafe_fn )] -#![cfg_attr( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES , allow(unnecessary_transmutes))] +#![cfg_attr(not( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES ), allow(unknown_lints))] +#![allow(unnecessary_transmutes)] #![cfg_attr( CONFIG_RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS, allow(suspicious_runtime_symbol_definitions)
Greg Kroah-Hartman
maintainerPATCH 479/733 drm/panic: clean new `clippy::needless_range_loop` lint for Rust 1.100.0
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miguel Ojeda <[email protected]>
commit 97f8cb91a8c5658fe2ae6f5c2ff6e95474a5eb2f upstream.
Starting with Rust 1.100.0 (expected 2026-11-12), Clippy warns:
warning: the loop variable `i` is only used to index `self.decimals`
--> drivers/gpu/drm/drm_panic_qr.rs:410:18
|
410 | for i in 0..len {
| ^^^^^^
|
note: for this index operation
--> drivers/gpu/drm/drm_panic_qr.rs:411:13
|
411 | self.decimals[i] = (chunk % 10) as u8;
| ^^^^^^^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/main/index.html#needless_range_loop
= note: `-W clippy::needless-range-loop` implied by `-W clippy::all`
= help: to override `-W clippy::all` add `#[allow(clippy::needless_range_loop)]`
help: consider using an iterator
|
410 - for i in 0..len {
410 + for <item> in self.decimals.iter_mut().take(len) {
|The lint did not trigger here before because it could not handle arrays behind a field access such as self.decimals -- Clippy was improved to catch those cases [1][2].
Thus clean the warning by iterating over a slice rather than using take() so that an out-of-range len still triggers the same bounds check as the indexed loop.
--- drivers/gpu/drm/drm_panic_qr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/drm_panic_qr.rs +2 -2
@@ -407,8 +407,8 @@ impl DecFifo {for iin (0 ..self.len).rev () { self.decimals[i + len] = self.decimals[i]; } -for iin 0 ..len { - self.decimals[i] = (chunk %10 )as u8 ; +for decimalin &mut self.decimals[..len] { + *decimal = (chunk %10 )as u8 ; chunk =div10 (chunk); } self.len += len;
Greg Kroah-Hartman
maintainerPATCH 480/733 ALSA: ctxfi: Fix CA20K2 S/PDIF passthrough
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Roman Prucha <[email protected]>
commit b26a7a80e6bbf8dd17dacb127d12435d79375cf2 upstream.
dao_rsc_init() encodes the DAIO configuration as
conf = (desc->msr & 0x7) | (desc->passthru << 3);
S/PDIF passthrough uses msr=1 and passthru=1, resulting in conf=9.
daio_mgr_dao_init() masks conf with 0xf, but handles only values 1, 2, 4 and 8 when programming ATXCTL_NUC. As a result, conf=9 falls through to the default case and leaves NUC at its previous setting.
On a Creative X-Fi Titanium HD SB1270 (CA20K2), this breaks AC3 IEC61937 passthrough when snd_ctxfi runs with reference_rate=48000,multiple=2. The receiver detects a non-audio stream but cannot decode the AC3 payload.
With the unmodified driver, multiple=1 makes the same stream work. Handle conf=9 through the same NUC=0 path as conf=1.
The change was runtime tested on the SB1270 with multiple=2 using IEC958 stereo PCM, pre-encoded AC3 IEC61937 passthrough and ALSA A52 live 5.1 encoding.
--- sound/pci/ctxfi/cthw20k2.c | 1 + 1 file changed, 1 insertion(+)
sound/pci/ctxfi/cthw20k2.c +1 -0
@@ -994,6 +994,7 @@ static int daio_mgr_dao_init(struct hw */* S/PDIF output */ switch ((conf &0xf )) {case 1 : +case 9 :set_field (&ctl->txctl[idx],ATXCTL_NUC ,0 );break ;case 2 :
Greg Kroah-Hartman
maintainerPATCH 481/733 ALSA: us122l: Prevent write upgrades for read mappings
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kazuki Hanai <[email protected]>
commit 71c610aeb1770302ac9c9e0b9a4ecd37f1311928 upstream.
The hwdep mmap callback rejects read-buffer mappings that are initially writable, but leaves VM_MAYWRITE set on mappings created with PROT_READ. A process that can open the hwdep node O_RDWR can later use mprotect() to make the mapping writable.
The read allocation begins with struct usb_stream. Its read_size member is used by the fault handler to decide which pages belong to the read buffer. The read VMA intentionally remains expandable because pcm_usb_stream uses mremap() after reading that size. Changing read_size first can therefore map and access pages beyond the allocation. The same member is also consumed by usb_stream_free(), where changing it can make free_pages_exact() release pages outside the allocation.
Clear VM_MAYWRITE for read-buffer mappings after rejecting an initially writable VMA. This keeps the separate output-buffer mapping writable while preventing later permission upgrades.
--- sound/usb/usx2y/us122l.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
sound/usb/usx2y/us122l.c +5 -2
@@ -180,8 +180,11 @@ static int usb_stream_hwdep_mmap(structguard (mutex)(&us122l->mutex); s = us122l->sk.s; read = offset < s->read_size; -if (read && area->vm_flags &VM_WRITE ) -return -EPERM ; +if (read) { +if (area->vm_flags &VM_WRITE ) +return -EPERM ; +vm_flags_clear (area,VM_MAYWRITE ); + }/* if userspace tries to mmap beyond end of our buffer, fail */ if (size >PAGE_ALIGN (read ? s->read_size : s->write_size)) { dev_warn(hw->card->dev, "%s: size %lu > %u\n", __func__,
Greg Kroah-Hartman
maintainerPATCH 482/733 ALSA: usbusx2y: fix in04_last array size mismatch with in04_buf
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 861111a14740e12c36d363e9830f8daa734279c9 upstream.
The in04_last array in struct usx2ydev is declared as char[24], but in04_buf is allocated as sizeof(struct us428_ctls) which is 21 bytes. In i_usx2y_in04_int(), when ctl_snapshot_last == -2 (initialization path):
memcpy(usx2y->in04_last, usx2y->in04_buf, sizeof(usx2y->in04_last));
This copies 24 bytes from a 21-byte slab allocation, reading 3 bytes past the end of the source object.
Introduce a USX2Y_IN04_SIZE constant defined as sizeof(struct us428_ctls) and use it consistently for the in04_last array, the in04_buf allocation, the URB transfer length, and the comparison loop, replacing the bare 24 and 21 literals throughout.
--- sound/usb/usx2y/usbusx2y.c | 6 +++--- sound/usb/usx2y/usbusx2y.h | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-)
sound/usb/usx2y/usbusx2y.c +3 -3
@@ -196,7 +196,7 @@ static void i_usx2y_in04_int(struct urbmemcpy (usx2y->in04_last, usx2y->in04_buf,sizeof (usx2y->in04_last)); us428ctls->ctl_snapshot_last =-1 ; }else { -for (i =0 ; i <21 ; i++) { +for (i =0 ; i <USX2Y_IN04_SIZE ; i++) {if (usx2y->in04_last[i] != ((char *)usx2y->in04_buf)[i]) {if (diff <0 ) diff = i;
@@ -305,7 +305,7 @@ int usx2y_in04_init(struct usx2ydev *usx goto error; } - usx2y->in04_buf =kmalloc (21 ,GFP_KERNEL ); + usx2y->in04_buf =kmalloc (USX2Y_IN04_SIZE ,GFP_KERNEL );if (!usx2y->in04_buf) { err = -ENOMEM ; goto error;
@@ -313,7 +313,7 @@ int usx2y_in04_init(struct usx2ydev *usxinit_waitqueue_head (&usx2y->in04_wait_queue);usb_fill_int_urb (usx2y->in04_urb, usx2y->dev,usb_rcvintpipe (usx2y->dev,0x4 ), - usx2y->in04_buf,21 , + usx2y->in04_buf,USX2Y_IN04_SIZE , i_usx2y_in04_int, usx2y,10 );if (usb_urb_ep_type_check (usx2y->in04_urb)) {
sound/usb/usx2y/usbusx2y.h +3 -1
@@ -5,6 +5,8 @@#include "../midi.h" #include "usbus428ctldefs.h" +#define USX2Y_IN04_SIZE sizeof(struct us428_ctls) +#define NRURBS 2/* Default value used for nr of packs per urb.
@@ -55,7 +57,7 @@ struct usx2ydev {int stride;struct urb *in04_urb;void *in04_buf; -char in04_last[24 ]; +char in04_last[USX2Y_IN04_SIZE ];unsigned int in04_int_calls;struct snd_usx2y_urb_seq *us04;wait_queue_head_t in04_wait_queue;
Greg Kroah-Hartman
maintainerPATCH 483/733 ALSA: usbusx2y: validate URB actual_length in interrupt callback
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 8f5ef203abda9dd36b2af473c7b737d544f807bd upstream.
i_usx2y_in04_int() processes the interrupt URB data without checking urb->actual_length. A short transfer from a malfunctioning device would cause the handler to process uninitialized heap data from the kmalloc-allocated in04_buf, which is then copied to the mmap-accessible ctl_snapshot[] array.
Fix by using kzalloc() for in04_buf to zero-initialize the buffer, and adding an actual_length check to skip processing on short transfers while still resubmitting the URB.
--- sound/usb/usx2y/usbusx2y.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
sound/usb/usx2y/usbusx2y.c +5 -1
@@ -189,6 +189,9 @@ static void i_usx2y_in04_int(struct urbreturn ; } +if (urb->actual_length <USX2Y_IN04_SIZE ) + goto resubmit; +if (us428ctls) { diff =-1 ;if (us428ctls->ctl_snapshot_last ==-2 ) {
@@ -253,6 +256,7 @@ static void i_usx2y_in04_int(struct urbif (err)dev_err (&urb->dev->dev,"in04_int() usb_submit_urb err=%i\n" , err); +resubmit: urb->dev = usx2y->dev;usb_submit_urb (urb,GFP_ATOMIC ); }
@@ -305,7 +309,7 @@ int usx2y_in04_init(struct usx2ydev *usx goto error; } - usx2y->in04_buf =kmalloc (USX2Y_IN04_SIZE ,GFP_KERNEL ); + usx2y->in04_buf =kzalloc (USX2Y_IN04_SIZE ,GFP_KERNEL );if (!usx2y->in04_buf) { err = -ENOMEM ; goto error;
Greg Kroah-Hartman
maintainerPATCH 484/733 Revert "riscv: Reset pmm when PR_TAGGED_ADDR_ENABLE is not set"
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Holland <[email protected]>
commit 2d2184ac90365a4af3274e23c98d469f09f91749 upstream.
This reverts commit 3033b2b1e3949274f33a140e2a97571b5a307298.
The reverted patch is userspace-visible behavior change, not a bug fix. The two variables here (pmm and pmlen) control two independent features:
pmm is the _hardware_ pointer masking mode that applies while executing in userspace. pmlen is the shift amount that the _kernel_ uses when untagging addresses; PMLEN_0 means no untagging occurs, so the kernel does not accept tagged addresses in syscall arguments.
It is valid (as documented and tested by the self test) to enable pointer masking without enabling the tagged address ABI. This separation is necessary to allow userspace to create an execution environment similar to what the kernel supports on arm64 by default, where TBI is enabled but the tagged address ABI is not. (On arm64, there is no equivalent to PR_PMLEN_MASK because TBI is always enabled.)
--- arch/riscv/kernel/process.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/riscv/kernel/process.c +1 -3
@@ -349,10 +349,8 @@ long set_tagged_addr_ctrl(struct task_stif (arg &PR_TAGGED_ADDR_ENABLE && (tagged_addr_disabled || !pmlen))return -EINVAL ; -if (!(arg &PR_TAGGED_ADDR_ENABLE )) { +if (!(arg &PR_TAGGED_ADDR_ENABLE )) pmlen =PMLEN_0 ; - pmm =ENVCFG_PMM_PMLEN_0 ; - }if (mmap_write_lock_killable (mm))return -EINTR ;
Greg Kroah-Hartman
maintainerPATCH 485/733 riscv: hwprobe: initialize pair->value in hwprobe_one_pair()
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Chiu <[email protected]>
commit d0fc6fab20460add1f27402cd8b945d094a56b21 upstream.
The vendor-extension handlers reached from hwprobe_one_pair() (hwprobe_isa_vendor_ext_thead_0() and friends) only OR the present bits into pair->value via VENDOR_EXTENSION_SUPPORTED() and clear their own missing bits; they assume the caller has already zeroed pair->value.
That holds for hwprobe_get_values() (it zeroes each pair) and hwprobe_get_cpus() (it re-initializes its scratch pair per key), but not for complete_hwprobe_vdso_data(), which reuses a single pair across all keys without re-zeroing. A vendor key therefore inherits stale bits from the previously probed key, and the wrong value is cached in the vDSO all_cpu_hwprobe_values[] and handed to userspace on the fast patih.
Zero pair->value once at the top of hwprobe_one_pair() so every handler starts from a clean value regardless of the caller, and drop the now redundant zeroing in the *_BLOCK_SIZE cases. hwprobe_isa_ext0() keeps its own zeroing because hwprobe_ext0_has() calls it directly, bypassing hwprobe_one_pair().
--- arch/riscv/kernel/sys_hwprobe.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
arch/riscv/kernel/sys_hwprobe.c +2 -3
@@ -295,6 +295,8 @@ static u64 hwprobe_vec_misaligned(conststatic void hwprobe_one_pair (struct riscv_hwprobe *pair,const struct cpumask *cpus) { + pair->value =0 ; +switch (pair->key) {case RISCV_HWPROBE_KEY_MVENDORID :case RISCV_HWPROBE_KEY_MARCHID :
@@ -329,17 +331,14 @@ static void hwprobe_one_pair(struct riscbreak ;case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE : - pair->value =0 ;if (hwprobe_ext0_has (cpus,RISCV_HWPROBE_EXT_ZICBOZ )) pair->value = riscv_cboz_block_size;break ;case RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE : - pair->value =0 ;if (hwprobe_ext0_has (cpus,RISCV_HWPROBE_EXT_ZICBOM )) pair->value = riscv_cbom_block_size;break ;case RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE : - pair->value =0 ;if (hwprobe_ext0_has (cpus,RISCV_HWPROBE_EXT_ZICBOP )) pair->value = riscv_cbop_block_size;break ;
Greg Kroah-Hartman
maintainerPATCH 486/733 dm/amdgpu: fix malformed link_settings debugfs output
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit 622b4e8505aa7453a53d17fa3a288871f270fc8b upstream.
[Why]dp_link_settings_read() passed strlen() of each format string as the size argument to snprintf() and then advanced rd_buf_ptr by that same fixed amount. The format-string length has no relation to the formatted output length, so snprintf() truncated each field at a NUL it wrote inside the buffer while the pointer was advanced past it. The result is a buffer peppered with embedded NUL bytes and fields that are silently cut short, so the data read back from the debugfs node does not reflect the actual link settings.
[How]
Use scnprintf() with the real remaining buffer size (rd_buf_size - (rd_buf_ptr - rd_buf)) and advance rd_buf_ptr by its return value, which is the number of characters actually written. This both bounds each write to the space left in rd_buf and keeps the output a single, properly terminated string. The now-unused str_len local is removed.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 20 +++++--------- 1 file changed, 8 insertions(+), 12 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +8 -12
@@ -196,7 +196,6 @@ static ssize_t dp_link_settings_read(strchar *rd_buf_ptr =NULL ;const uint32_t rd_buf_size =100 ;uint32_t result =0 ; -uint8_t str_len =0 ;int r;if (*pos &3 || size &3 )
@@ -208,29 +207,26 @@ static ssize_t dp_link_settings_read(str rd_buf_ptr = rd_buf; - str_len =strlen ("Current: %d 0x%x %d " ); -snprintf (rd_buf_ptr, str_len,"Current: %d 0x%x %d " , + rd_buf_ptr +=scnprintf (rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), +"Current: %d 0x%x %d " , link->cur_link_settings.lane_count, link->cur_link_settings.link_rate, link->cur_link_settings.link_spread); - rd_buf_ptr += str_len; - str_len =strlen ("Verified: %d 0x%x %d " ); -snprintf (rd_buf_ptr, str_len,"Verified: %d 0x%x %d " , + rd_buf_ptr +=scnprintf (rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), +"Verified: %d 0x%x %d " , link->verified_link_cap.lane_count, link->verified_link_cap.link_rate, link->verified_link_cap.link_spread); - rd_buf_ptr += str_len; - str_len =strlen ("Reported: %d 0x%x %d " ); -snprintf (rd_buf_ptr, str_len,"Reported: %d 0x%x %d " , + rd_buf_ptr +=scnprintf (rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), +"Reported: %d 0x%x %d " , link->reported_link_cap.lane_count, link->reported_link_cap.link_rate, link->reported_link_cap.link_spread); - rd_buf_ptr += str_len; - str_len =strlen ("Preferred: %d 0x%x %d " ); -snprintf (rd_buf_ptr, str_len,"Preferred: %d 0x%x %d\n" , + rd_buf_ptr +=scnprintf (rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), +"Preferred: %d 0x%x %d\n" , link->preferred_link_setting.lane_count, link->preferred_link_setting.link_rate, link->preferred_link_setting.link_spread);
Greg Kroah-Hartman
maintainerPATCH 487/733 drm/amdgpu: skip gfx switch_power_profile during GPU reset
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prike Liang <[email protected]>
commit 1f1d43418d61c8511779e0f63a954a78b9433b43 upstream.
During resume from GPU reset, the gfx idle work may invoke switch_power_profile before the reset completes. This causes the following assert error because the register access occurs without first releasing the GPU reset semaphore:
[ 1576.768935] CR2: 0000559ea133ead0 CR3: 00000002e6c42000 CR4: 0000000000350ef0 [ 1576.768940] Call Trace: [ 1576.768944] <TASK> [ 1576.768953] amdgpu_device_rreg+0x21/0x50 [amdgpu] [ 1576.769158] smu_msg_v1_send_msg+0x1a4/0x6e0 [amdgpu] [ 1576.769437] smu_cmn_send_smc_msg_with_params_ext+0xba/0x120 [amdgpu] [ 1576.769721] smu_cmn_send_smc_msg_with_param+0x33/0x40 [amdgpu] [ 1576.769993] smu_v13_0_0_set_power_profile_mode+0x192/0x2b0 [amdgpu] [ 1576.770267] smu_bump_power_profile_mode+0x5d/0x80 [amdgpu] [ 1576.770538] smu_switch_power_profile+0xa4/0xf0 [amdgpu] [ 1576.770839] amdgpu_dpm_switch_power_profile+0x6f/0x90 [amdgpu] [ 1576.771210] amdgpu_gfx_profile_idle_work_handler+0xe9/0x130 [amdgpu] [ 1576.771460] process_one_work+0x23e/0x6f0 [ 1576.771491] worker_thread+0x1c4/0x380 [ 1576.771506] kthread+0x10c/0x150 [ 1576.771512] ? __pfx_worker_thread+0x10/0x10 [ 1576.771518] ? __pfx_kthread+0x10/0x10 [ 1576.771530] ret_from_fork+0x314/0x390 [ 1576.771537] ? __pfx_kthread+0x10/0x10 [ 1576.771546] ret_from_fork_asm+0x1a/0x30
--- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/pm/amdgpu_dpm.c +4 -2
@@ -348,7 +348,8 @@ int amdgpu_dpm_switch_power_profile(struconst struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;int ret =0 ; -if (amdgpu_sriov_vf (adev)) +if (amdgpu_sriov_vf (adev) || +amdgpu_in_reset (adev))return 0 ;if (pp_funcs && pp_funcs->switch_power_profile) {
@@ -367,7 +368,8 @@ int amdgpu_dpm_pause_power_profile(strucconst struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;int ret =0 ; -if (amdgpu_sriov_vf (adev)) +if (amdgpu_sriov_vf (adev) || +amdgpu_in_reset (adev))return 0 ;if (pp_funcs && pp_funcs->pause_power_profile) {
Greg Kroah-Hartman
maintainerPATCH 488/733 drm/amdgpu: skip the VMID 0 flush for VRAM
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arunpravin Paneer Selvam <[email protected]>
commit 87ceb8cba73d0b3c4025ff42495bccd8164acaed upstream.
Clear-on-release only runs on VRAM, which amdgpu_ttm_map_buffer() reaches via its direct MC address without programming a GART window, yet the wipe still forces a VMID 0 flush. On GFX11 (e.g. Navi33) that spurious SDMA flush can wedge the engine; only flush when a GART window is actually used.
v2: Let amdgpu_ttm_map_buffer() return whether the VMID 0 flush is needed,
and drive the clear and copy paths from that. (Christian)
v3: Make the vm_needs_flush output parameter mandatory instead of
allowing NULL. (Christian)
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +14 -6
@@ -190,6 +190,8 @@ amdgpu_ttm_job_submit(struct amdgpu_devi* @tmz: if we should setup a TMZ enabled mapping * @size: in number of bytes to map, out number of bytes mapped * @addr: resulting address inside the MC address space +* @vm_needs_flush: out, set true if a GART window was programmed (VMID 0 flush +* needed) or false for a direct address * * Setup one of the GART windows to access a specific piece of memory or return * the physical address for local memory.
@@ -199,7 +201,8 @@ static int amdgpu_ttm_map_buffer(structstruct ttm_resource *mem, struct amdgpu_res_cursor *mm_cur, unsigned int window, - bool tmz, uint64_t *size, uint64_t *addr) + bool tmz, uint64_t *size, uint64_t *addr, + bool *vm_needs_flush) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);unsigned int offset, num_pages, num_dw, num_bytes;
@@ -220,9 +223,12 @@ static int amdgpu_ttm_map_buffer(structif (!tmz && mem->start !=AMDGPU_BO_INVALID_OFFSET ) { *addr =amdgpu_ttm_domain_start (adev, mem->mem_type) + mm_cur->start; + *vm_needs_flush = false;return 0 ; } +/* A GART window is programmed below, so its VMID 0 TLB needs a flush */ + *vm_needs_flush = true;/* * If start begins at an offset inside the page, then adjust the size
@@ -322,6 +328,7 @@ static int amdgpu_ttm_copy_mem_to_mem(stwhile (src_mm.remaining) {uint64_t from, to, cur_size, tiling_flags;uint32_t num_type, data_format, max_com, write_compress_disable; +bool src_vm_flush, dst_vm_flush;struct dma_fence *next;/* Never copy more than 256MiB at once to avoid a timeout */
@@ -329,12 +336,12 @@ static int amdgpu_ttm_copy_mem_to_mem(st/* Map src to window 0 and dst to window 1. */ r =amdgpu_ttm_map_buffer (entity, src->bo, src->mem, &src_mm, -0 , tmz, &cur_size, &from); +0 , tmz, &cur_size, &from, &src_vm_flush);if (r) goto error; r =amdgpu_ttm_map_buffer (entity, dst->bo, dst->mem, &dst_mm, -1 , tmz, &cur_size, &to); +1 , tmz, &cur_size, &to, &dst_vm_flush);if (r) goto error;
@@ -362,7 +369,7 @@ static int amdgpu_ttm_copy_mem_to_mem(st } r =amdgpu_copy_buffer (adev, entity, from, to, cur_size, resv, - &next, true, copy_flags); + &next, src_vm_flush || dst_vm_flush, copy_flags);if (r) goto error;
@@ -2580,6 +2587,7 @@ int amdgpu_ttm_clear_buffer(struct amdgpstruct amdgpu_device *adev =amdgpu_ttm_adev (bo->tbo.bdev);struct dma_fence *fence =NULL ;struct amdgpu_res_cursor dst; +bool vm_needs_flush = false;int r;if (!entity)
@@ -2601,13 +2609,13 @@ int amdgpu_ttm_clear_buffer(struct amdgp cur_size =min (dst.size,256ULL <<20 ); r =amdgpu_ttm_map_buffer (entity, &bo->tbo, bo->tbo.resource, &dst, -0 , false, &cur_size, &to); +0 , false, &cur_size, &to, &vm_needs_flush);if (r) goto error; r =amdgpu_ttm_fill_mem (adev, entity,0 , to, cur_size, resv, - &next, true, k_job_id); + &next, vm_needs_flush, k_job_id);if (r) goto error;
Greg Kroah-Hartman
maintainerPATCH 489/733 watchdog: sunxi_wdt: preserve boot-enabled watchdog
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Hilliard <[email protected]>
commit aab55360fa11a2c054798a484ac67ad606f563e4 upstream.
sunxi_wdt_probe() unconditionally stops the watchdog even when firmware left it running. This opens an unprotected interval during boot and prevents CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED from taking over the active watchdog.
Detect an enabled watchdog and decode its programmed interval. Preserve representable timeouts, and round the 0.5-second interval up to the minimum representable one-second timeout. Use the configured timeout for reserved interval encodings. Set the Linux reset mode and ping the watchdog without clearing its enable bit, then mark it hardware-running before registration so the watchdog core services it until userspace takes control. Leave disabled watchdogs untouched.
--- drivers/watchdog/sunxi_wdt.c | 45 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-)
drivers/watchdog/sunxi_wdt.c +44 -1
@@ -128,6 +128,38 @@ static int sunxi_wdt_ping(struct watchdoreturn 0 ; } +static bool sunxi_wdt_is_running (struct watchdog_device *wdt_dev) +{ +struct sunxi_wdt_dev *sunxi_wdt =watchdog_get_drvdata (wdt_dev); +const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs; + +return readl (sunxi_wdt->wdt_base + regs->wdt_mode) &WDT_MODE_EN ; +} + +static unsigned int sunxi_wdt_get_timeout (struct watchdog_device *wdt_dev) +{ +struct sunxi_wdt_dev *sunxi_wdt =watchdog_get_drvdata (wdt_dev); +const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs; +unsigned int timeout; +u32 interval; + + interval =readl (sunxi_wdt->wdt_base + regs->wdt_mode); + interval >>= regs->wdt_timeout_shift; + interval &=WDT_TIMEOUT_MASK ; +/* Round the 0.5-second interval up to the minimum representable timeout. */ +if (!interval) +return WDT_MIN_TIMEOUT ; + +for (timeout =WDT_MIN_TIMEOUT ; + timeout <ARRAY_SIZE (wdt_timeout_map); timeout++) { +if (wdt_timeout_map[timeout] == interval) +return timeout; + } + +/* Reserved interval encoding. */ +return 0 ; +} +static int sunxi_wdt_set_timeout (struct watchdog_device *wdt_dev,unsigned int timeout) {
@@ -259,6 +291,7 @@ static int sunxi_wdt_probe(struct platfo {struct device *dev = &pdev->dev;struct sunxi_wdt_dev *sunxi_wdt; +unsigned int running_timeout;int err; sunxi_wdt =devm_kzalloc (dev,sizeof (*sunxi_wdt),GFP_KERNEL );
@@ -286,7 +319,17 @@ static int sunxi_wdt_probe(struct platfowatchdog_set_drvdata (&sunxi_wdt->wdt_dev, sunxi_wdt); -sunxi_wdt_stop (&sunxi_wdt->wdt_dev); +if (sunxi_wdt_is_running (&sunxi_wdt->wdt_dev)) { + running_timeout =sunxi_wdt_get_timeout (&sunxi_wdt->wdt_dev); +if (running_timeout) + sunxi_wdt->wdt_dev.timeout = running_timeout; + + err =sunxi_wdt_start (&sunxi_wdt->wdt_dev); +if (err) +return err; + +set_bit (WDOG_HW_RUNNING , &sunxi_wdt->wdt_dev.status); + }watchdog_stop_on_reboot (&sunxi_wdt->wdt_dev); err =devm_watchdog_register_device (dev, &sunxi_wdt->wdt_dev);
Greg Kroah-Hartman
maintainerPATCH 490/733 virtio_mmio: disable IRQ wake before free_irq
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiong Weimin <[email protected]>
commit d14d693adb055e98ca705822ba6daebc18602d9a upstream.
When the DT node has "wakeup-source", vm_find_vqs() calls enable_irq_wake() on the shared IRQ, but vm_del_vqs() freed that IRQ without a matching disable_irq_wake(). That leaves a wake reference behind and can warn on later free_irq()/request_irq() cycles.
Record whether enable_irq_wake() succeeded, and disable it in vm_del_vqs() before free_irq().
Message-ID: <[email protected]>
--- drivers/virtio/virtio_mmio.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
drivers/virtio/virtio_mmio.c +13 -3
@@ -87,6 +87,9 @@ struct virtio_mmio_device {void __iomem *base;unsigned long version; + +/* True if enable_irq_wake() succeeded for the shared IRQ. */ +bool wake_irq_enabled; };/* Configuration interface */
@@ -329,11 +332,17 @@ static void vm_del_vqs(struct virtio_dev {struct virtio_mmio_device *vm_dev =to_virtio_mmio_device (vdev);struct virtqueue *vq, *n; +int irq =platform_get_irq (vm_dev->pdev,0 );list_for_each_entry_safe (vq, n, &vdev->vqs, list)vm_del_vq (vq); -free_irq (platform_get_irq (vm_dev->pdev,0 ), vm_dev); +if (vm_dev->wake_irq_enabled) { +disable_irq_wake (irq); + vm_dev->wake_irq_enabled = false; + } + +free_irq (irq, vm_dev); }static void vm_synchronize_cbs (struct virtio_device *vdev)
@@ -460,8 +469,9 @@ static int vm_find_vqs(struct virtio_devif (err)return err; -if (of_property_read_bool (vm_dev->pdev->dev.of_node,"wakeup-source" )) -enable_irq_wake (irq); +if (of_property_read_bool (vm_dev->pdev->dev.of_node,"wakeup-source" ) && + !enable_irq_wake (irq)) + vm_dev->wake_irq_enabled = true;for (i =0 ; i < nvqs; ++i) {struct virtqueue_info *vqi = &vqs_info[i];
Greg Kroah-Hartman
maintainerPATCH 491/733 ufs: create the root dentry after loading cylinder metadata
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
commit 55a4c98abb9694b067c6a031d11501f06b6b523c upstream.
ufs_fill_super() installed sb->s_root before it loaded the cylinder group structures for a writable mount:
sb->s_root = d_make_root(inode); ... if (!sb_rdonly(sb)) if (!ufs_read_cylinder_structures(sb)) goto failed;
When ufs_read_cylinder_structures() failed, the error path freed the in-core superblock information and set sb->s_fs_info to NULL while sb->s_root stayed installed. get_tree_bdev() then reached deactivate_locked_super(), and because s_root was present, generic_shutdown_super() called sync_filesystem() and the put_super operation. Both dereference UFS_SB(sb), which is now NULL, so a mount that fails only while reading the cylinder groups oopses during teardown. A crafted image whose first cylinder group cannot be read reaches this path.
Load the cylinder group metadata first and create the root dentry last, so the superblock is published to the VFS only once it is fully set up. ufs_setup_cstotal() and ufs_read_cylinder_structures() take only the super_block and do not use the root inode, so the reordering is safe.
--- fs/ufs/super.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
fs/ufs/super.c +9 -8
@@ -1199,6 +1199,15 @@ magic_found: sb->s_maxbytes =ufs_max_bytes (sb); sb->s_max_links =UFS_LINK_MAX ; +ufs_setup_cstotal (sb); +/* +* Read cylinder group structures +*/ +if (!sb_rdonly (sb)) +if (!ufs_read_cylinder_structures (sb)) + goto failed; + +/* create the root dentry last, once UFS_SB(sb) is fully set up */ inode =ufs_iget (sb,UFS_ROOTINO );if (IS_ERR (inode)) { ret =PTR_ERR (inode);
@@ -1210,14 +1219,6 @@ magic_found: goto failed; } -ufs_setup_cstotal (sb); -/* -* Read cylinder group structures -*/ -if (!sb_rdonly (sb)) -if (!ufs_read_cylinder_structures (sb)) - goto failed; -UFSD ("EXIT\n" );return 0 ;
Greg Kroah-Hartman
maintainerPATCH 492/733 ufs: validate cylinder group metadata before caching it
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
commit c9d263be26806d388129fab8c6904bed197fc6af upstream.
ufs_read_cylinder() copies the cylinder group index and the rotor positions straight from the on-disk group and caches them without any check:
ucpi->c_cgx = fs32_to_cpu(sb, ucg->cg_cgx); ucpi->c_rotor = fs32_to_cpu(sb, ucg->cg_rotor); ucpi->c_frotor = fs32_to_cpu(sb, ucg->cg_frotor); ucpi->c_irotor = fs32_to_cpu(sb, ucg->cg_irotor);
They are then used as indices during allocation and free:
- c_cgx indexes the cylinder summary array as UFS_SB(sb)->fs_cs(ucpi->c_cgx), so a value past s_ncg writes a 32 bit count outside the s_csp allocation.
- c_frotor becomes a bitmap scan start, start = c_frotor >> 3, and then length = ((s_fpg + 7) >> 3) - start. A start beyond the block bitmap wraps the unsigned length to a huge value, so ubh_scanc() walks far past the cylinder group buffers. c_irotor drives the inode bitmap the same way.
A crafted image can set any of these freely, turning an ordinary allocation into an out of bounds access.
Reject a cylinder group whose recorded index does not match the group being read, or whose rotors fall outside the group, before the metadata is cached. Valid filesystems keep cg_cgx equal to the group number and the rotors within the group, so only malformed images are rejected.
--- fs/ufs/cylinder.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
fs/ufs/cylinder.c +10 -0
@@ -68,6 +68,16 @@ static bool ufs_read_cylinder(struct sup ucpi->c_clustersumoff =fs32_to_cpu (sb, ucg->cg_u.cg_44.cg_clustersumoff); ucpi->c_clusteroff =fs32_to_cpu (sb, ucg->cg_u.cg_44.cg_clusteroff); ucpi->c_nclusterblks =fs32_to_cpu (sb, ucg->cg_u.cg_44.cg_nclusterblks); + +/* these on-disk values become array and bitmap indices */ +if (ucpi->c_cgx != cgno || + ucpi->c_rotor >= uspi->s_fpg || + ucpi->c_frotor >= uspi->s_fpg || + ucpi->c_irotor >= uspi->s_ipg) { +ufs_error (sb, __func__, +"inconsistent metadata in cylinder group %u\n" , cgno); + goto failed; + }UFSD ("EXIT\n" );return true;
Greg Kroah-Hartman
maintainerPATCH 493/733 tunnels: Drop stale dst when building an ICMP error for PMTUD
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
commit b58d749633203d92c265317b45fccee555090352 upstream.
Bridged UDP tunnels such as VXLAN and GENEVE build an ICMP error packet around an overlay packet if the packet is going to exceed the underlay path MTU. The ICMP error packet is then injected back into the Rx path with the source and destination addresses swapped, so that it will be delivered to the overlay source.
If the overlay packet was routed to the UDP tunnel or locally generated, then it is already carrying a valid dst entry and this entry is not dropped when transforming the packet to an ICMP error packet. This causes the IP layer to reuse the dst entry, leading to the ICMP error packet being dropped or routed out of the UDP tunnel interface in case of forwarding.
Prior to the blamed commit this could not happen, as skb_tunnel_check_pmtu() did not build ICMP errors for PACKET_HOST packets. Such packets were instead encapsulated and, unless the DF bit was set in the outer header, fragmented by the underlay.
Fix this by making sure that the ICMP error packet does not have a valid dst entry, thereby forcing the IP layer to perform a route lookup.
Adjust the bridged PMTU exception selftests accordingly. When the local sender in ns_a pings the overlay destination with a deadline (-w), ping exits on the first socket error before any reply is received and returns a non-zero exit code. The test therefore only passed because the ICMP error was never delivered. Use a packet count (-c) like the ns_c line above it, so that the ICMP error counts against the packet budget and the exit code depends on whether echo replies were received. This passes with and without the fix.
--- net/ipv4/ip_tunnel_core.c | 6 ++++++ tools/testing/selftests/net/pmtu.sh | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-)
net/ipv4/ip_tunnel_core.c +6 -0
@@ -268,6 +268,9 @@ static int iptunnel_pmtud_build_icmp(streth_header (skb, skb->dev,ntohs (eh.h_proto), eh.h_source, eh.h_dest,0 );skb_reset_mac_header (skb); +if (skb_valid_dst (skb)) +skb_dst_drop (skb); +return skb->len; }
@@ -371,6 +374,9 @@ static int iptunnel_pmtud_build_icmpv6(seth_header (skb, skb->dev,ntohs (eh.h_proto), eh.h_source, eh.h_dest,0 );skb_reset_mac_header (skb); +if (skb_valid_dst (skb)) +skb_dst_drop (skb); +return skb->len; }
tools/testing/selftests/net/pmtu.sh +1 -1
@@ -1457,7 +1457,7 @@ test_pmtu_ipvX_over_bridged_vxlanY_or_ge mtu "${ns_b}" ${type}_b $((${ll_mtu} + 1000)) run_cmd ${ns_c} ${ping} -q -M want -i 0.1 -c 10 -s $((${ll_mtu} + 500)) ${dst} || return 1 - run_cmd ${ns_a} ${ping} -q -M want -i 0.1 -w 1 -s $((${ll_mtu} + 500)) ${dst} || return 1 + run_cmd ${ns_a} ${ping} -q -M want -i 0.1 -c 10 -s $((${ll_mtu} + 500)) ${dst} || return 1 # Check that exceptions were created pmtu="$(route_get_dst_pmtu_from_exception "${ns_c}" ${dst})"
Greg Kroah-Hartman
maintainerPATCH 494/733 tick/broadcast: Plug clockevents replacement race
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit 113a9796effe3376d2ec5aabcca1fef4fef4cd62 upstream.
朱恺乾 reported and decoded the following race condition when a broadcast device is replaced:
CPUA CPUB
__tick_broadcast_oneshot_control()
bc = tick_broadcast_device.evtdev;
tick_install_broadcast_device(dev)
clockevents_exchange_device(cur, dev)
shutdown(cur);
detach(cur);
cur->handler = noop;
tick_broadcast_device.evtdev = dev; tick_broadcast_set_event(bc, next_event); <- FAIL: arms a detached device.
If the original broadcast device has a restricted interrupt affinity mask and the last CPU in that mask goes offline then the BUG() in tick_cleanup_dead_cpu() triggers because the clockevent device is not in detached state.
The reason for this is that tick_install_broadcast_device() is not serialized vs. tick broadcast operations.
The obvious cure is to serialize tick_install_broadcast_device() with tick_broadcast_lock against a concurrent tick broadcast operation.
That requires to split clockevents_exchange_device() into two parts, one which does the exchange, shutdown and detach operation and the other which drops the module reference count. This is required because the module reference cannot be dropped while holding tick_broadcast_lock.
Let clockevents_exchange_device() do both operations as before, but let the broadcast device code take the two step approach and do the device exchange under tick_broadcast_lock and drop the module reference count after releasing it.
--- kernel/time/clockevents.c | 33 ++++++++++++++++++++------------- kernel/time/tick-broadcast.c | 36 ++++++++++++++++++++++-------------- kernel/time/tick-internal.h | 2 ++ 3 files changed, 44 insertions(+), 27 deletions(-)
kernel/time/clockevents.c +20 -13
@@ -615,34 +615,41 @@ void clockevents_handle_noop(struct cloc { } -/** -* clockevents_exchange_device - release and request clock devices -* @old: device to release (can be NULL) -* @new: device to request (can be NULL) -* -* Called from various tick functions with clockevents_lock held and -* interrupts disabled. -*/ -void clockevents_exchange_device (struct clock_event_device *old, -struct clock_event_device *new) +void __clockevents_exchange_device (struct clock_event_device *old, +struct clock_event_device *new) {/* * Caller releases a clock event device. We queue it into the * released list and do a notify add later. */ if (old) { -module_put (old->owner);clockevents_switch_state (old,CLOCK_EVT_STATE_DETACHED );list_move (&old->list, &clockevents_released); }if (new) { -BUG_ON (!clockevent_state_detached (new)); +WARN_ON (!clockevent_state_detached (new));clockevents_shutdown (new); } }/** +* clockevents_exchange_device - release and request clock devices +* @old: device to release (can be NULL) +* @new: device to request (can be NULL) +* +* Called from various tick functions with clockevents_lock held and +* interrupts disabled. +*/ +void clockevents_exchange_device (struct clock_event_device *old, +struct clock_event_device *new) +{ +__clockevents_exchange_device (old, new); +if (old) +module_put (old->owner); +} + +/** * clockevents_suspend - suspend clock devices */ void clockevents_suspend (void )
@@ -699,7 +706,7 @@ void tick_offline_cpu(unsigned int cpu)if (cpumask_test_cpu (cpu, dev->cpumask) &&cpumask_weight (dev->cpumask) ==1 && !tick_is_broadcast_device (dev)) { -BUG_ON (!clockevent_state_detached (dev)); +WARN_ON (!clockevent_state_detached (dev));list_del (&dev->list); } }
kernel/time/tick-broadcast.c +22 -14
@@ -165,23 +165,31 @@ static bool tick_set_oneshot_wakeup_devi*/ void tick_install_broadcast_device (struct clock_event_device *dev,int cpu) { -struct clock_event_device *cur = tick_broadcast_device.evtdev; +struct clock_event_device *cur; -if (tick_set_oneshot_wakeup_device (dev, cpu)) -return ; + scoped_guard(raw_spinlock_irqsave, &tick_broadcast_lock) { -if (!tick_check_broadcast_device (cur, dev)) -return ; +if (tick_set_oneshot_wakeup_device (dev, cpu)) +return ; -if (!try_module_get (dev->owner)) -return ; + cur = tick_broadcast_device.evtdev; +if (!tick_check_broadcast_device (cur, dev)) +return ; -clockevents_exchange_device (cur, dev); +if (!try_module_get (dev->owner)) +return ; + +__clockevents_exchange_device (cur, dev); +if (cur) + cur->event_handler = clockevents_handle_noop; +WRITE_ONCE (tick_broadcast_device.evtdev, dev); +if (!cpumask_empty (tick_broadcast_mask)) +tick_broadcast_start_periodic (dev); + } + +/* Module release must be outside of the lock */ if (cur) - cur->event_handler = clockevents_handle_noop; - tick_broadcast_device.evtdev = dev; -if (!cpumask_empty (tick_broadcast_mask)) -tick_broadcast_start_periodic (dev); +module_put (cur->owner);if (!(dev->features &CLOCK_EVT_FEAT_ONESHOT ))return ;
@@ -1218,7 +1226,7 @@ int tick_broadcast_oneshot_active(void)*/ bool tick_broadcast_oneshot_available (void ) { -struct clock_event_device *bc = tick_broadcast_device.evtdev; +struct clock_event_device *bc =READ_ONCE (tick_broadcast_device.evtdev);return bc ? bc->features &CLOCK_EVT_FEAT_ONESHOT : false; }
@@ -1226,7 +1234,7 @@ bool tick_broadcast_oneshot_available(vo#else int __tick_broadcast_oneshot_control (enum tick_broadcast_state state) { -struct clock_event_device *bc = tick_broadcast_device.evtdev; +struct clock_event_device *bc =READ_ONCE (tick_broadcast_device.evtdev);if (!bc || (bc->features &CLOCK_EVT_FEAT_HRTIMER ))return -EBUSY ;
kernel/time/tick-internal.h +2 -0
@@ -54,6 +54,8 @@ static inline void clockevent_set_state( }extern void clockevents_shutdown (struct clock_event_device *dev); +extern void __clockevents_exchange_device (struct clock_event_device *old, +struct clock_event_device *new);extern void clockevents_exchange_device (struct clock_event_device *old,struct clock_event_device *new); extern void clockevents_switch_state(struct clock_event_device *dev,
Greg Kroah-Hartman
maintainerPATCH 495/733 tools/bootconfig: Fix integer overflow and truncation in size checks
In reply to Greg Kroah-Hartman7.2-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit 462d0b066b613103f579793031429db2ca23abc0 upstream.
Sashiko reported that on 32-bit systems, if an attacker crafts size in the bootconfig footer such that adding BOOTCONFIG_FOOTER_SIZE wraps around (for instance, if size is 0xFFFFFFFF), the size check in load_xbc_from_initrd() can be bypassed:
if (stat.st_size < size + BOOTCONFIG_FOOTER_SIZE) {
pr_err("bootconfig size is too big\n");
return -E2BIG;
}Furthermore, on 64-bit systems with an initrd > 4.29 GB, comparing a corrupted 32-bit size (e.g. 0xFFFFFFFF) against
stat.st_size - BOOTCONFIG_FOOTER_SIZE can also bypass the check if size is not bounded. Similarly, load_xbc_file() passes 64-bit stat.st_size directly into the 32-bit int size parameter of load_xbc_fd(), truncating large standalone files (>= 2GB).
In both cases, passing 0xFFFFFFFF to load_xbc_fd() truncates to -1, resulting in malloc(0), an integer overflow in read(), and an out-of-bounds null-byte write.
Fix this by:
1. Rejecting size > XBC_DATA_MAX or
size > stat.st_size - BOOTCONFIG_FOOTER_SIZE in load_xbc_from_initrd().
2. Rejecting stat.st_size > XBC_DATA_MAX in load_xbc_file() before passing it to load_xbc_fd().
3. Checking size < 0 || size > XBC_DATA_MAX defensively in load_xbc_fd().
--- tools/bootconfig/main.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
tools/bootconfig/main.c +12 -1
@@ -140,6 +140,9 @@ static int load_xbc_fd(int fd, char **bu {int ret; +if (size <0 || size >XBC_DATA_MAX ) +return -EINVAL ; + *buf =malloc (size +1 );if (!*buf)return -ENOMEM ;
@@ -168,6 +171,13 @@ static int load_xbc_file(const char *patreturn ret; } +if (stat.st_size >XBC_DATA_MAX ) { +pr_err ("%s size is too big\n" , path); + ret = -E2BIG ; +close (fd); +return ret; + } + ret =load_xbc_fd (fd, buf, stat.st_size);close (fd);
@@ -218,7 +228,8 @@ static int load_xbc_from_initrd(int fd, csum =le32toh (csum);/* Wrong size error */ -if (stat.st_size < size +BOOTCONFIG_FOOTER_SIZE ) { +if (size >XBC_DATA_MAX || + size > stat.st_size -BOOTCONFIG_FOOTER_SIZE ) {pr_err ("bootconfig size is too big\n" );return -E2BIG ; }