6.1.183-rc1 review
Greg Kroah-Hartman
maintainerPATCH 395/609 Bluetooth: HIDP: validate numbered report payloads
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sangho Lee <[email protected]>
commit 34f53d27b81a16a02828c8fdfa4e02badc326f17 upstream.
When hidp_get_raw_report() waits for a numbered report, hidp_process_data() compares the expected report number with skb->data[0]. A connected HIDP peer can reply with only a DATA transaction header, leaving the skb empty after the header is removed.
KMSAN reports an uninitialized-value use in hidp_session_run(), with the value originating in __alloc_skb() through vhci_write(). The transaction header checks remove the empty-frame reports, but this report remains until the payload check is added.
The comparison can also consume a peer-controlled byte beyond the declared L2CAP PDU. A DATA | FEATURE response followed by an extra 0x01 byte made the current code accept that byte as report ID 1 and complete HIDIOCGFEATURE with a zero-byte result. With this change the malformed response is rejected with -EIO, while a subsequent valid response still succeeds.
Require a payload byte before comparing a numbered report ID. Unnumbered reports continue to accept an empty payload.
--- net/bluetooth/hidp/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/bluetooth/hidp/core.c +3 -2
@@ -546,9 +546,10 @@ static int hidp_process_data(struct hidp }if (test_bit (HIDP_WAITING_FOR_RETURN , &session->flags) && - param == session->waiting_report_type) { + param == session->waiting_report_type) {if (session->waiting_report_number <0 || - session->waiting_report_number == skb->data[0 ]) { + (skb->len && + session->waiting_report_number == skb->data[0 ])) {/* hidp_get_raw_report() is waiting on this report. */ session->report_return = skb; done_with_skb =0 ;
Greg Kroah-Hartman
maintainerPATCH 396/609 bpf: lwt: Fix dst reference leak on reroute failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
commit 88c17de85ddb459c3fe1e3c65d61fa366b1cf0a8 upstream.
bpf_lwt_xmit_reroute() obtains a referenced dst from the route lookup. When skb_cow_head() fails before that dst is installed on the skb, the error path only frees the skb. The skb still owns its previous dst, so the newly looked up dst reference is leaked.
Release the new dst reference before freeing the skb on this error path.
--- net/core/lwt_bpf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/core/lwt_bpf.c +3 -1
@@ -246,8 +246,10 @@ static int bpf_lwt_xmit_reroute(struct s* if there is enough header space in skb. */ err =skb_cow_head (skb,LL_RESERVED_SPACE (dst->dev)); -if (unlikely (err)) +if (unlikely (err)) { +dst_release (dst); goto err; + }skb_dst_drop (skb);skb_dst_set (skb, dst);
Greg Kroah-Hartman
maintainerPATCH 397/609 ALSA: 6fire: Fix UAF at error handling during probe
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit a54bf16965f896415c3337bc4fbb40fb11941d99 upstream.
Although 6fire driver had a few fixes for dealing with the early error handling during the probe phase, it forgot a pending URB before freeing the resources, which may lead to a UAF.
This patch addresses it by doing the almost same cleanup procedure like the normal disconnect phase at the error path.
--- sound/usb/6fire/chip.c | 4 ++++ 1 file changed, 4 insertions(+)
sound/usb/6fire/chip.c +4 -0
@@ -158,6 +158,10 @@ static int usb6fire_chip_probe(struct usreturn 0 ; destroy_chip: + chip->shutdown = true; +if (card) +snd_card_disconnect (card); +usb6fire_chip_abort (chip);snd_card_free (card);return ret; }
Greg Kroah-Hartman
maintainerPATCH 398/609 ALSA: lx6464es: fix period byte count for 16-bit streams
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 6437033bffe8bd2af174d139af552d90d40c7ac6 upstream.
The lx6464es driver advertises both 16-bit and packed 24-bit PCM formats, but lx_trigger_start() and lx_interrupt_request_new_buffer() calculate the DMA period size as runtime->period_size * runtime->channels * 3. That is only correct for the packed 24-bit formats.
For 16-bit streams the driver submits buffers that are 50% larger than the actual ALSA period and advances the DMA address by the same wrong amount. For example, with 2 channels, 256 frames and 4 periods, the third buffer already extends beyond the ALSA buffer and the fourth buffer starts outside it.
Use snd_pcm_lib_period_bytes() so the byte count matches the runtime format, channel count and period size.
--- sound/pci/lx6464es/lx6464es.c | 5 +---- sound/pci/lx6464es/lx_core.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-)
sound/pci/lx6464es/lx6464es.c +1 -4
@@ -410,11 +410,8 @@ static void lx_trigger_start(struct lx64int err; -const u32 channels = substream->runtime->channels; -const u32 bytes_per_frame = channels *3 ; -const u32 period_size = substream->runtime->period_size;const u32 periods = substream->runtime->periods; -const u32 period_bytes = period_size * bytes_per_frame; +const u32 period_bytes =snd_pcm_lib_period_bytes (substream);dma_addr_t buf = substream->dma_buffer.addr;int i;
sound/pci/lx6464es/lx_core.c +1 -4
@@ -1015,10 +1015,7 @@ static int lx_interrupt_request_new_buffconst unsigned int is_capture = lx_stream->is_capture;int err; -const u32 channels = substream->runtime->channels; -const u32 bytes_per_frame = channels *3 ; -const u32 period_size = substream->runtime->period_size; -const u32 period_bytes = period_size * bytes_per_frame; +const u32 period_bytes =snd_pcm_lib_period_bytes (substream);const u32 pos = lx_stream->frame_pos;const u32 next_pos = ((pos+1 ) == substream->runtime->periods) ?0 : pos +1 ;
Greg Kroah-Hartman
maintainerPATCH 399/609 ALSA: pcm: wake linked drain waiters on unlink
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit f495b6c4c8594122918552c9be2b51eb71647cd9 upstream.
snd_pcm_drain() on a linked stream parks an on-stack wait entry on the drained peer's runtime->sleep, and after schedule_timeout() removes it only if that peer is still found in the caller's group. If group membership changes during the wait and the sleep ends by signal or timeout (so autoremove_wake_function() does not run), finish_wait() is skipped and snd_pcm_drain() returns with the entry still queued on that stream's sleep list; a later wake_up() then walks a freed stack frame. This is reachable by unlinking either the drained or the draining stream.
Unlike the close path (snd_pcm_drop() -> snd_pcm_post_stop()), snd_pcm_unlink() never wakes the sleep queues. Wake every group member under the group lock before the membership change, so a linked drainer is released and drops its entry while the streams are still grouped.
The window was opened when snd_pcm_link_rwsem stopped being held across the wait and the removal became conditional on group membership (see Fixes). The later switch to finish_wait() kept that conditional removal, so the signal/timeout case remained.
--- sound/core/pcm_native.c | 7 +++++++ 1 file changed, 7 insertions(+)
sound/core/pcm_native.c +7 -0
@@ -2352,6 +2352,7 @@ static void relink_to_local(struct snd_pstatic int snd_pcm_unlink (struct snd_pcm_substream *substream) { +struct snd_pcm_substream *s;struct snd_pcm_group *group;bool nonatomic = substream->pcm->nonatomic;bool do_free = false;
@@ -2367,6 +2368,12 @@ static int snd_pcm_unlink(struct snd_pcm group = substream->group;snd_pcm_group_lock_irq (group, nonatomic); +/* release drain waiters before changing membership, else snd_pcm_drain() +* leaves its on-stack wait entry queued on a member's sleep list +*/ +snd_pcm_group_for_each_entry (s, substream) +wake_up (&s->runtime->sleep); +relink_to_local (substream);refcount_dec (&group->refs);
Greg Kroah-Hartman
maintainerPATCH 400/609 ASoC: tas2562: fix DVC coefficient write order
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haidar Lee <[email protected]>
commit 8e957e4907c58e9ca944f98799524f2bbb9cf68a upstream.
The TAS2562 applies the 32-bit digital volume coefficient to the playback path when the last byte, DVC_CFG4 (book 0 page 2 reg 0x0F), is written. tas2562_volume_control_put() wrote DVC_CFG4 first and DVC_CFG1 (the MSB) last, so every volume change latched a value made of the previous coefficient's upper three bytes combined with the new LSB; the remaining bytes only took effect on the next volume change.
In practice the control was unusable: the first setting after power-on always played at roughly 0 dB no matter what value was requested (the chip's default upper bytes were still latched), and most subsequent changes muted the output entirely or produced a distorted, over-unity gain.
Verified on a TAS2562 (ADLINK OSM-520 / MT8189 board) by tracing the I2C writes with ftrace and by writing the same coefficients manually in both byte orders: written MSB-first the register block behaves exactly as the driver expects, LSB-first reproduces the broken behaviour.
Write the bytes MSB first with DVC_CFG4 last so the complete new coefficient is latched atomically.
--- sound/soc/codecs/tas2562.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
sound/soc/codecs/tas2562.c +15 -8
@@ -477,20 +477,27 @@ static int tas2562_volume_control_put(stu32 reg_val; reg_val = float_vol_db_lookup[ucontrol->value.integer.value[0 ]/2 ]; - ret =snd_soc_component_write (component,TAS2562_DVC_CFG4 , - (reg_val &0xff )); -if (ret) -return ret; - ret =snd_soc_component_write (component,TAS2562_DVC_CFG3 , - ((reg_val >>8 ) &0xff )); +/* +* The device applies the 32-bit coefficient to the playback path on +* the write to DVC_CFG4 (the LSB, book 0 page 2 reg 0x0F), so the +* bytes must be written MSB first and DVC_CFG4 last. Writing CFG4 +* first latches a mix of the previous coefficient's upper bytes and +* the new LSB instead of the requested value. +*/ + ret =snd_soc_component_write (component,TAS2562_DVC_CFG1 , + ((reg_val >>24 ) &0xff ));if (ret)return ret; ret =snd_soc_component_write (component,TAS2562_DVC_CFG2 , ((reg_val >>16 ) &0xff ));if (ret)return ret; - ret =snd_soc_component_write (component,TAS2562_DVC_CFG1 , - ((reg_val >>24 ) &0xff )); + ret =snd_soc_component_write (component,TAS2562_DVC_CFG3 , + ((reg_val >>8 ) &0xff )); +if (ret) +return ret; + ret =snd_soc_component_write (component,TAS2562_DVC_CFG4 , + (reg_val &0xff ));if (ret)return ret;
Greg Kroah-Hartman
maintainerPATCH 401/609 ASoC: tas2562: fix broken entries in the volume lookup table
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haidar Lee <[email protected]>
commit bdb0fd6de403fcea7b85dc9d38f0a571583ebe80 upstream.
The float_vol_db_lookup table is supposed to hold round(10^(dB/20) * 2^30) for every 2 dB step from -110 dB to 0 dB, which is 56 entries, but it only has 55: the -90 dB entry duplicates the -92 dB value (0x0000695b) and the -20 dB entry (0x06666666) is missing altogether. As a result every step between -90 dB and -22 dB is off by 2 dB, and the control's maximum raw value of 110 indexes one element past the end of the array.
Replace the duplicated -90 dB entry with the correct value 0x000084a3 and add the missing -20 dB entry, bringing the table to the full 56 entries so index 55 (raw value 110, 0 dB) is in range again.
--- sound/soc/codecs/tas2562.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
sound/soc/codecs/tas2562.c +4 -3
@@ -33,15 +33,16 @@static const unsigned int float_vol_db_lookup[] = {0x00000d43 ,0x000010b2 ,0x00001505 ,0x00001a67 ,0x00002151 ,0x000029f1 ,0x000034cd ,0x00004279 ,0x000053af ,0x0000695b , -0x0000695b ,0x0000a6fa ,0x0000d236 ,0x000108a4 ,0x00014d2a , +0x000084a3 ,0x0000a6fa ,0x0000d236 ,0x000108a4 ,0x00014d2a ,0x0001a36e ,0x00021008 ,0x000298c0 ,0x000344df ,0x00041d8f ,0x00052e5a ,0x000685c8 ,0x00083621 ,0x000a566d ,0x000d03a7 ,0x0010624d ,0x0014a050 ,0x0019f786 ,0x0020b0bc ,0x0029279d ,0x0033cf8d ,0x004139d3 ,0x00521d50 ,0x00676044 ,0x0082248a ,0x00a3d70a ,0x00ce4328 ,0x0103ab3d ,0x0146e75d ,0x019b8c27 ,0x02061b89 ,0x028c423f ,0x03352529 ,0x0409c2b0 ,0x05156d68 , -0x080e9f96 ,0x0a24b062 ,0x0cc509ab ,0x10137987 ,0x143d1362 , -0x197a967f ,0x2013739e ,0x28619ae9 ,0x32d64617 ,0x40000000 +0x06666666 ,0x080e9f96 ,0x0a24b062 ,0x0cc509ab ,0x10137987 , +0x143d1362 ,0x197a967f ,0x2013739e ,0x28619ae9 ,0x32d64617 , +0x40000000 };struct tas2562_data {
Greg Kroah-Hartman
maintainerPATCH 402/609 ALSA: usb-audio: fix OOB write in snd_usbmidi_akai_output()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 0970274613fb463d376211450cab066d34ebfe6a upstream.
snd_usbmidi_akai_output() computes its fill-loop bound
buf_end = ep->max_transfer - MAX_AKAI_SYSEX_LEN - 1;
as a signed int, so a small device-advertised bulk-OUT max_transfer makes buf_end negative. The loop guard then compares the u32 urb->transfer_buffer_length against that negative int: the usual arithmetic conversion turns buf_end into a large unsigned value, so the guard stays true and each iteration keeps appending SysEx framing and payload bytes past the end of the URB transfer buffer, which is only max_transfer bytes long.
A USB device that advertises a tiny bulk-OUT endpoint can therefore trigger an attacker-length- and content-controlled heap out-of-bounds write when a process writes to the created /dev/snd/midiC*D* node.
Return early when there is no room for even one SysEx, so the loop is never entered with a bound that would wrap. The loop is the last statement of the function, so bailing out is equivalent to it not running.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/usb/midi.c | 2 ++ 1 file changed, 2 insertions(+)
sound/usb/midi.c +2 -0
@@ -800,6 +800,8 @@ static void snd_usbmidi_akai_output(stru msg = urb->transfer_buffer + urb->transfer_buffer_length; buf_end = ep->max_transfer -MAX_AKAI_SYSEX_LEN -1 ; +if (buf_end <=0 ) +return ;/* only try adding more data when there's space for at least 1 SysEx */ while (urb->transfer_buffer_length < buf_end) {
Greg Kroah-Hartman
maintainerPATCH 403/609 ALSA: usb-audio: Fix DMA buffer out-of-bounds write when fill_max is set
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sonali Pradhan <[email protected]>
commit d0199ae1666ff9ae2d1d568d64c3430d4c47f0e5 upstream.
When a USB audio endpoint requests full packet transfers via the fill_max descriptor flag, data_ep_set_params() promotes ep->curpacksize to ep->maxpacksize. However, maxsize is left at the original sample-rate derived value.
Since u->buffer_size is allocated as maxsize * packets, the resulting DMA buffer is far too small for the requested transfer length. When the USB host controller streams up to curpacksize bytes per packet, it writes past the end of the buffer via DMA, corrupting kernel heap memory.
Update maxsize to curpacksize when fill_max is set so that the allocated DMA buffer size matches the actual transfer request size.
[ changed to reassign maxsize only when ep->fill_max is set -- tiwai ]
--- sound/usb/endpoint.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
sound/usb/endpoint.c +4 -2
@@ -1167,10 +1167,12 @@ static int data_ep_set_params(struct snd << (16 - ep->datainterval); } -if (ep->fill_max) +if (ep->fill_max) { ep->curpacksize = ep->maxpacksize; -else + maxsize = ep->curpacksize; + }else { ep->curpacksize = maxsize; + }if (snd_usb_get_speed (chip->dev) !=USB_SPEED_FULL ) { packs_per_ms =8 >> ep->datainterval;
Greg Kroah-Hartman
maintainerPATCH 404/609 ALSA: usb-audio: Clamp frame size in implicit-feedback mode
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sonali Pradhan <[email protected]>
commit 8d7a30c50c2e58a6839634ed0acde14466d1dc61 upstream.
snd_usb_handle_sync_urb() scales received sync packet sizes by the sender's stride and stores the result directly in out_packet->packet_size[i]. If a connected USB device sends an oversized sync packet, this frame count can exceed ep->maxframesize.
The un-clamped frame count then propagates to the playback endpoint queue, potentially driving packet transfers beyond the endpoint's hardware frame limits.
Cap the calculated frame count against ep->maxframesize in snd_usb_handle_sync_urb() to prevent oversized packets from entering the playback queue.
--- sound/usb/endpoint.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
sound/usb/endpoint.c +5 -3
@@ -1826,11 +1826,13 @@ static void snd_usb_handle_sync_urb(stru out_packet->packets = in_ctx->packets;for (i =0 ; i < in_ctx->packets; i++) { -if (urb->iso_frame_desc[i].status ==0 ) - out_packet->packet_size[i] = +if (urb->iso_frame_desc[i].status ==0 ) { +unsigned int frames = urb->iso_frame_desc[i].actual_length / sender->stride; -else + out_packet->packet_size[i] =min (frames, ep->maxframesize); + }else { out_packet->packet_size[i] =0 ; + } }spin_unlock_irqrestore (&ep->lock, flags);
Greg Kroah-Hartman
maintainerPATCH 405/609 dmaengine: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Md Sadre Alam <[email protected]>
commit 867621ba203027338b525af6729719c544135336 upstream.
BAM version 1.6.0 and later changed the behavior of the mask field in command elements for read operations.
In older BAM versions, or prior implementation assumptions, the mask field was effectively ignored for read commands. However, starting from BAM v1.6.0, the mask field for read commands is repurposed to carry the upper 4 bits of the destination address, enabling support for 36-bit addressing. For write commands, the mask field continues to function as a traditional write mask.
The current driver sets mask = 0xffffffff for all command elements. While this works for write operations, it breaks read operations on BAM v1.6.0+ hardware. In such cases, the hardware interprets the upper address bits as 0xf, resulting in an invalid destination address (0xf_xxxxxxxx instead of 0x0_xxxxxxxx).
This leads to failures such as NAND enumeration issues observed on platforms like IPQ5424.
Fix this by assigning the mask field based on command type:
- For read commands: set mask = 0 (upper address bits = 0)
- For write commands: retain mask = 0xffffffff
Also update the bam_cmd_element structure documentation to reflect the dual purpose of the mask field across BAM versions.
This ensures correct behavior on BAM v1.6.0+ while maintaining backward compatibility with older hardware.
--- include/linux/dma/qcom_bam_dma.h | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
include/linux/dma/qcom_bam_dma.h +16 -5
@@ -13,9 +13,12 @@* supported by BAM DMA Engine. * * @cmd_and_addr - upper 8 bits command and lower 24 bits register address. -* @data - for write command: content to be written into peripheral register. -* for read command: dest addr to write peripheral register value. -* @mask - register mask. +* @data - For write command: content to be written into peripheral register. +* For read command: lower 32 bits of destination address. +* @mask - For write command: register write mask. +* For read command on BAM v1.6.0+: upper 4 bits of destination address. +* For read command on BAM < v1.6.0: ignored by hardware. +* Setting to 0 ensures 32-bit addressing compatibility. * @reserved - for future usage. * */
@@ -42,6 +45,10 @@ enum bam_command_type {* @addr: target address * @cmd: BAM command * @data: actual data for write and dest addr for read in le32 +* +* For BAM v1.6.0+, the mask field behavior depends on command type: +* - Write commands: mask = write mask (typically 0xffffffff) +* - Read commands: mask = upper 4 bits of destination address (0 for 32-bit) */ static inline void bam_prep_ce_le32(struct bam_cmd_element *bam_ce, u32 addr,
@@ -50,7 +57,11 @@ bam_prep_ce_le32(struct bam_cmd_element bam_ce->cmd_and_addr =cpu_to_le32 ((addr &0xffffff ) | ((cmd &0xff ) <<24 )); bam_ce->data = data; - bam_ce->mask =cpu_to_le32 (0xffffffff ); +if (cmd ==BAM_READ_COMMAND ) + bam_ce->mask =cpu_to_le32 (0x0 );/* 32-bit addressing */ +else + bam_ce->mask =cpu_to_le32 (0xffffffff );/* Write mask */ + bam_ce->reserved =0 ; }/*
@@ -60,7 +71,7 @@ bam_prep_ce_le32(struct bam_cmd_element* @bam_ce: BAM command element * @addr: target address * @cmd: BAM command -* @data: actual data for write and dest addr for read +* @data: actual data for write and destination address for read */ static inline void bam_prep_ce(struct bam_cmd_element *bam_ce, u32 addr,
Greg Kroah-Hartman
maintainerPATCH 406/609 e1000: fix memory leak in e1000_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
commit 816419dfea5c88126f35eb7a1b429a1bf546665e upstream.
In the e1000_probe() path, e1000_sw_init() allocates adapter->tx_ring and adapter->rx_ring. If the subsequent CE4100-specific MDIO BAR mapping fails, the error handling jumps past the ring cleanup code, leaking both allocations.
Fix this leak by moving the err_mdio_ioremap label above the ring deallocation logic. This guarantees the proper release of these resources and prevents the memory leak.
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1-rc6.
An x86_64 allyesconfig build showed no new warnings. As we do not have a CE4100 reference platform to test with, no runtime testing was able to be performed.
--- drivers/net/ethernet/intel/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/e1000/e1000_main.c +1 -1
@@ -1228,11 +1228,11 @@ err_eeprom:if (hw->flash_address)iounmap (hw->flash_address); +err_mdio_ioremap:kfree (adapter->tx_ring);kfree (adapter->rx_ring); err_dma: err_sw_init: -err_mdio_ioremap:iounmap (hw->ce4100_gbe_mdio_base_virt);iounmap (hw->hw_addr); err_ioremap:
Greg Kroah-Hartman
maintainerPATCH 407/609 igbvf: Fix leak in TX DMA error cleanup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Vollrath <[email protected]>
commit 0565052b7e2f436b7f1541f4849da96dc0aa7a0e upstream.
If an error is encountered while mapping TX buffers, the driver should unmap any buffers already mapped for that skb.
Because count is incremented before each frag mapping, it will always match the correct number of unmappings needed when dma_error is reached. Decrementing count before the while loop in dma_error causes an off-by-one error. If any mapping was successful before an unsuccessful mapping, exactly one DMA mapping (the head) would leak.
This bug was introduced by a 2010 fix for an endless loop in dma_error. All other affected drivers have already been fixed.
--- drivers/net/ethernet/intel/igbvf/netdev.c | 2 -- 1 file changed, 2 deletions(-)
drivers/net/ethernet/intel/igbvf/netdev.c +0 -2
@@ -2202,8 +2202,6 @@ dma_error: buffer_info->time_stamp =0 ; buffer_info->length =0 ; buffer_info->mapped_as_page = false; -if (count) - count--;/* clear timestamp and dma mappings for remaining portion of packet */ while (count--) {
Greg Kroah-Hartman
maintainerPATCH 408/609 ipvs: do not propagate one-packet flag to synced conns
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit a63d2dbaeb50a85d4c976b15a36e6b0c7113db5b upstream.
Synced connections can be created before their destination exists. When the destination is later added, ip_vs_bind_dest() copies connection flags from the destination into cp->flags.
IP_VS_CONN_F_ONE_PACKET connections are not synced. If a synced connection inherits IP_VS_CONN_F_ONE_PACKET while it is already hashed, expiry can treat it as a one-packet connection and skip unlinking the existing conn_tab node, leaving stale hash nodes pointing at a freed struct ip_vs_conn.
Drop IP_VS_CONN_F_ONE_PACKET from destination flags when binding synced connections.
--- net/netfilter/ipvs/ip_vs_conn.c | 3 +++ 1 file changed, 3 insertions(+)
net/netfilter/ipvs/ip_vs_conn.c +3 -0
@@ -599,6 +599,9 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, s flags = cp->flags;/* Bind with the destination and its corresponding transmitter */ if (flags &IP_VS_CONN_F_SYNC ) { +/* Synced conns are hashed, so they can not get this flag */ + conn_flags &= ~IP_VS_CONN_F_ONE_PACKET ; +/* if the connection is not template and is created * by sync, preserve the activity flag. */
Greg Kroah-Hartman
maintainerPATCH 409/609 net/smc: fix socket use-after-free during link group termination
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
commit f621d6ebeebb6374342571e4ddf45fdbc420f6cd upstream.
__smc_lgr_terminate() drops conns_lock after finding a connection in lgr->conns_all, but before taking a reference on its socket. The connection is embedded in the socket, and its registration reference protects it only while the connection remains in the tree.
A concurrent close can unregister the connection and drop that reference, freeing the socket before the termination worker reaches sock_hold().
The race is reachable when close overlaps link group termination. Local stress testing reproduced the use-after-free and KASAN reported:
BUG: KASAN: slab-use-after-free in __smc_lgr_terminate.part.0 [smc] Write of size 4 by task kworker/3:3 Workqueue: events smc_lgr_terminate_work [smc] __smc_lgr_terminate.part.0 [smc]
The socket was allocated by smc_create(), freed through slab_free_after_rcu_debug(), and was followed by:
refcount_t: addition on 0; use-after-free.
__smc_lgr_terminate.part.0 [smc]
Take the socket reference while conns_lock still protects the tree entry. The unregister path then cannot drop the last reference until termination has finished using the socket.
--- net/smc/smc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/smc/smc_core.c +1 -1
@@ -1468,10 +1468,10 @@ static void __smc_lgr_terminate(struct sread_lock_bh (&lgr->conns_lock); node =rb_first (&lgr->conns_all);while (node) { -read_unlock_bh (&lgr->conns_lock); conn = rb_entry(node, struct smc_connection, alert_node); smc = container_of(conn, struct smc_sock, conn);sock_hold (&smc->sk);/* sock_put below */ +read_unlock_bh (&lgr->conns_lock);lock_sock (&smc->sk);smc_conn_kill (conn, soft);release_sock (&smc->sk);
Greg Kroah-Hartman
maintainerPATCH 410/609 netfilter: ipset: do not update comments from kernel-side hash adds
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <[email protected]>
commit f30415929be8aeb002d557c8d3f7ab2d2188003a upstream.
mtype_resize() copies comment pointers with memcpy(), not the comment objects themselves. During the window after an entry has been copied but before the table swap and backlog replay, the old table is still published for packet-side updates while the replacement-table entry already holds the same ip_set_comment_rcu pointer.
If xt_SET --add-set ... --exist hits that old entry in this window, mtype_add() calls ip_set_init_comment() even though packet-side adds carry no comment payload. That call frees the shared comment through the old entry, so the replacement-table entry now holds a stale pointer. When the queued add is replayed on the new table, mtype_add() calls ip_set_init_comment() again and strlen() dereferences the stale pointer.
Fix this in mtype_add() by skipping ip_set_init_comment() when ext->target marks a packet-side add. Userspace adds still update comments, while packet-side adds can no longer free comment storage shared with a resize copy.
--- net/netfilter/ipset/ip_set_hash_gen.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/ipset/ip_set_hash_gen.h +1 -1
@@ -971,7 +971,7 @@ overwrite_extensions:#endif if (SET_WITH_COUNTER (set))ip_set_init_counter (ext_counter (data, set), ext); -if (SET_WITH_COMMENT (set)) +if (SET_WITH_COMMENT (set) && !ext->target)ip_set_init_comment (set,ext_comment (data, set), ext);if (SET_WITH_SKBINFO (set))ip_set_init_skbinfo (ext_skbinfo (data, set), ext);
Greg Kroah-Hartman
maintainerPATCH 411/609 tipc: avoid use-after-free in poll trace queue dumps
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit b4f1719dfea023220e0e6bd892b087d76b2a6a49 upstream.
TIPC socket tracepoints dump queue state through tipc_sk_dump(). Most queue-dump callsites already serialize that walk under the socket lock or sk->sk_lock.slock, but tipc_poll() calls trace_tipc_sk_poll(..., TIPC_DUMP_ALL, ...) without holding either lock.
That lets the poll trace path reach tipc_list_dump() and backlog head/tail dumping while another context dequeues and frees an skb, leaving the trace helper dereferencing a stale queue entry.
Stop the unlocked poll trace site from requesting queue dumps. Other queue dump trace callsites keep their existing output under the locking they already provide, while poll still emits the event itself without walking live queue members from an unlocked context.
--- net/tipc/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/tipc/socket.c +1 -1
@@ -797,7 +797,7 @@ static __poll_t tipc_poll(struct file *f__poll_t revents =0 ;sock_poll_wait (file, sock, wait); -trace_tipc_sk_poll (sk,NULL ,TIPC_DUMP_ALL ," " ); +trace_tipc_sk_poll (sk,NULL ,TIPC_DUMP_NONE ," " );if (sk->sk_shutdown &RCV_SHUTDOWN ) revents |=EPOLLRDHUP |EPOLLIN |EPOLLRDNORM ;
Greg Kroah-Hartman
maintainerPATCH 412/609 wifi: mwifiex: use the subframe length when parsing A-MSDU TDLS frames
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
commit 99a948382af8a225e2d5e54a7052158cd6281cc6 upstream.
mwifiex_11n_dispatch_amsdu_pkt() splits an A-MSDU with ieee80211_amsdu_to_8023s() and walks the resulting subframes. For each subframe it passes the subframe data pointer to mwifiex_process_tdls_action_frame(), but pairs it with skb->len, the length of the A-MSDU parent, instead of rx_skb->len:
rx_skb = __skb_dequeue(&list);
rx_hdr = (struct rx_packet_hdr *)rx_skb->data;
if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
mwifiex_process_tdls_action_frame(priv, (u8 *)rx_hdr,
skb->len);
}The parent is not a valid description of that buffer, and may not be valid memory at all. ieee80211_amsdu_to_8023s() ends with
if (!reuse_skb) dev_kfree_skb(skb);
and it only sets reuse_skb when the parent is linear, is not a head_frag, and is being consumed as the *last* subframe. So when the parent does not qualify for reuse it has already been freed, and the read of skb->len is a use-after-free. When it is reused, skb->len is the length of the last subframe, applied to every earlier subframe, which over-states the buffer whenever an earlier subframe is shorter.
The callee cannot absorb a wrong length, because it derives its own ceiling from the value it is given. Each frame type computes
ies_len = len - sizeof(struct ethhdr) - TDLS_*_FIX_LEN;
and the element walk is then bounded entirely against that ceiling,
for (end = pos + ies_len; pos + 1 < end; pos += 2 + pos[1]) {
u8 ie_len = pos[1];
if (pos + 2 + ie_len > end)
break;so a too-large len moves end past the end of the subframe and the walk reads and copies beyond it. The A-MSDU layout is chosen by the sender, which makes the difference between the last subframe and a shorter earlier one remotely selectable. Reaching this requires TDLS support in firmware and the TDLS ethertype on the subframe.
The other caller, mwifiex_process_rx_packet(), is correct: it passes a pointer and a length that describe the same region of the RX buffer.
Pass rx_skb->len, the length of the subframe actually being parsed.
--- drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +1 -1
@@ -44,7 +44,7 @@ static int mwifiex_11n_dispatch_amsdu_pk ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {mwifiex_process_tdls_action_frame (priv, (u8 *)rx_hdr, - skb->len); + rx_skb->len); }if (priv->bss_role ==MWIFIEX_BSS_ROLE_UAP )
Greg Kroah-Hartman
maintainerPATCH 413/609 binfmt_misc: reject a flag character as the field delimiter
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 8e85d50ba1117fd446bf9a250bd8a97d48384bdc upstream.
The registration string starts with a user chosen delimiter that separates the individual fields. So that the field parsers terminate even on a truncated string create_entry() pads the buffer with that same delimiter:
memset(buf + count, del, 8);
Most fields are scanned for the delimiter with strchr()/scanarg() and happily stop on the padding. The flags field is different: instead of scanning for the delimiter check_special_flags() consumes the flag characters 'P', 'O', 'C' and 'F' and stops at the first byte that is none of them, relying on the trailing delimiter to end the scan.
If the delimiter is itself a flag character the padding no longer acts as a terminator. The scan swallows all eight padding bytes and keeps reading past the end of the allocation until it hits a byte that is not a flag character. For example registering
PaPEPPxPPiP
with 'P' as the delimiter (name "a", type extension, magic "x", interpreter "i", empty flags) leaves the flag scan running off the end of the buffer. The registration is rejected in the end because the parser does not stop exactly at buf + count, but only after the out of bounds read has already happened. With an unlucky allocation layout the scan can walk into an unmapped page; under KASAN it is reported as a slab out of bounds read. binfmt_misc mounts are available to unprivileged users in a user namespace so the read is reachable without privileges.
Reject a delimiter that is one of the flag characters up front. Such a registration was always rejected anyway, only after the out of bounds read, so no valid registration string changes meaning.
--- fs/binfmt_misc.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/binfmt_misc.c +4 -0
@@ -347,6 +347,10 @@ static Node *create_entry(const char __upr_debug ("register: delim: %#x {%c}\n" , del, del); +/* A flag-char delimiter runs the flag scan off the buffer. */ +if (del =='P' || del =='O' || del =='C' || del =='F' ) + goto einval; +/* Pad the buffer with the delim to simplify parsing below. */ memset (buf + count, del,8 );
Greg Kroah-Hartman
maintainerPATCH 414/609 mm/page_reporting: use system_freezable_wq to fix UAF during suspend
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Link Lin <[email protected]>
commit 0b45f6927a14914ff685fe0e6f9d11232a1e03df upstream.
During PM freeze (e.g. S3 suspend or S4 hibernation), device drivers like virtio_balloon reset their underlying virtio devices and delete their virtqueues via vdev->config->del_vqs().
However, page reporting work (page_reporting_process) was scheduled on the global system_wq. Because system_wq lacks the WQ_FREEZABLE flag, the PM freezer skips it, leaving page_reporting_process active during suspend.
If pages are freed into the buddy allocator while suspending (for example, when core MM invokes the balloon shrinker during S4 hibernation image saving), page reporting triggers virtballoon_free_page_report() on deleted virtqueues, resulting in a Use-After-Free / General Protection Fault:
[ 196.795226] general protection fault, probably for non-canonical address 0xaa1436fe70dae6df: 0000 [#1] SMP NOPTI
[ 196.825967] Workqueue: events page_reporting_process
[ 196.831038] RIP: 0010:virtqueue_add_split+0x233/0x4c0 [virtio_ring]
[ 196.927073] virtballoon_free_page_report+0x3a/0xe0 [virtio_balloon]
[ 196.946943] page_reporting_process+0x370/0x4f0Fix this by switching page reporting work to system_freezable_wq. This ensures that the PM freezer pauses page_reporting_process before device drivers destroy their reporting virtqueues. Because the reporting worker is frozen, memory reclamation/freeing (e.g. via shrinker execution) can safely return pages to MM during freeze without triggering unfrozen reporting work on deleted virtqueues.
This aligns with the driver's existing design. The comment in virtballoon_freeze() states:
/*
* The workqueue is already frozen by the PM core before this
* function is called.
*/
Testing:
I have verified these fixes using Google’s virtualization infrastructure by running continuous suspend/resume iterations (40+ cycles) while churning memory using stress-ng (stress-ng --vm 4 --vm-bytes 60% --timeout 1) to constantly create free pages for the buddy allocator. We also set the page_reporting_order parameter to 0 to make the page reporting worker highly sensitive, forcing it to pick up any 4K free pages. This confirmed that the UAF crashes are no longer reproducible.
--- mm/page_reporting.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
mm/page_reporting.c +4 -2
@@ -48,7 +48,8 @@ __page_reporting_request(struct page_rep* now we are limiting this to running no more than once every * couple of seconds. */ -schedule_delayed_work (&prdev->work,PAGE_REPORTING_DELAY ); +queue_delayed_work (system_freezable_wq, &prdev->work, +PAGE_REPORTING_DELAY ); }/* notify prdev of free page reporting request */
@@ -311,7 +312,8 @@ err_out:*/ state =atomic_cmpxchg (&prdev->state, state,PAGE_REPORTING_IDLE );if (state ==PAGE_REPORTING_REQUESTED ) -schedule_delayed_work (&prdev->work,PAGE_REPORTING_DELAY ); +queue_delayed_work (system_freezable_wq, &prdev->work, +PAGE_REPORTING_DELAY ); }static DEFINE_MUTEX (page_reporting_mutex);
Greg Kroah-Hartman
maintainerPATCH 415/609 net: bridge: stop fast-leave after deleting a port group
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit a39789f211b8a4125f0c70e05b30cf715f4f187d upstream.
br_multicast_leave_group() iterates mp->ports with pp = &p->next in its fast-leave path. After br_multicast_del_pg() removes p, continuing the loop advances pp through the deleted entry.
If multicast-to-unicast was enabled, the bridge can hold multiple port groups for the same port and group with different source MAC addresses. Once multicast-to-unicast is disabled, br_port_group_equal() matches those entries by port only. A fast leave can then delete one entry and continue from its stale next pointer, leaving mp->ports pointing at a deleted port group.
Fast leave only needs to remove one matching port group. Break after br_multicast_del_pg() so the loop stops before dereferencing the removed entry.
--- net/bridge/br_multicast.c | 1 + 1 file changed, 1 insertion(+)
net/bridge/br_multicast.c +1 -0
@@ -3511,6 +3511,7 @@ br_multicast_leave_group(struct net_brid p->flags |=MDB_PG_FLAGS_FAST_LEAVE ;br_multicast_del_pg (mp, p, pp); +break ; } goto out; }
Greg Kroah-Hartman
maintainerPATCH 416/609 net: ipv6: clear suppressed fib6 rule result
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit 6aea62e433fe1b586202a5fee8b5807ce635e1d7 upstream.
fib6_rule_suppress() drops a suppressed route with ip6_rt_put_flags(), but leaves res->rt6 pointing at the released rt6_info.
If no later rule supplies a replacement, fib6_rule_lookup() still sees res.rt6 and returns that stale dst to its caller. A suppressing rule can therefore leak a released route back to rt6_lookup(), and the next put hits rcuref_put_slowpath() from dst_release().
Clear res->rt6 when suppressing the route so suppressed lookups fall through to the null dst instead of reusing the released one.
--- net/ipv6/fib6_rules.c | 1 + 1 file changed, 1 insertion(+)
net/ipv6/fib6_rules.c +1 -0
@@ -301,6 +301,7 @@ INDIRECT_CALLABLE_SCOPE bool fib6_rule_s suppress_route:ip6_rt_put_flags (rt, flags); + res->rt6 =NULL ;return true; }
Greg Kroah-Hartman
maintainerPATCH 417/609 powerpc/ps3: Fix map failure path in dma_ioc0_map_pages()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit 0bb024f11d120abff3e8db9144a585b9d7fb8459 upstream.
If lv1_put_iopte() fails in dma_ioc0_map_pages(), the error path decrements iopage but keeps using the failed mapping's offset. As a result, it repeatedly tries to invalidate the failed IOPTE slot and leaves the already installed IOPTEs valid.
Recompute offset and invalidate the installed IOPTEs instead.
--- arch/powerpc/platforms/ps3/mm.c | 1 + 1 file changed, 1 insertion(+)
arch/powerpc/platforms/ps3/mm.c +1 -0
@@ -615,6 +615,7 @@ static int dma_ioc0_map_pages(struct ps3 fail_map:for (iopage--;0 <= iopage; iopage--) { + offset = (1 << r->page_size) * iopage; lv1_put_iopte(0, c->bus_addr + offset, c->lpar_addr + offset,
Greg Kroah-Hartman
maintainerPATCH 418/609 um: vector: fix use-after-free in vector_mmsg_rx()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit af421e9aed3920c7ac88c24daa48606c7112feca upstream.
When vector_mmsg_rx() discards a packet whose overlay header fails verify_header(), it frees the skb and continues the loop:
if (header_check < 0) {
dev_kfree_skb_irq(skb);
vp->estats.rx_encaps_errors++;
continue;
}The normal and short-packet paths fall through to the bottom of the loop body, which clears the consumed slot and advances the cursors:
(*skbuff_vector) = NULL; mmsg_vector++; skbuff_vector++;
The verify_header() < 0 path skips that via continue, so the freed skb is left in skbuff_vector[] and the cursors do not advance. The next iteration reads the same slot, gets the freed skb, and frees it again, producing a refcount underflow / use-after-free in the RX path.
Discard the slot the same way the other paths do before continuing.
Only transports whose verify_header() can return negative are affected:
GRE and L2TPv3 do so on a cookie/session-id mismatch (raw/tap do not), so any peer on such a transport can trigger it without authentication.
--- arch/um/drivers/vector_kern.c | 3 +++ 1 file changed, 3 insertions(+)
arch/um/drivers/vector_kern.c +3 -0
@@ -1007,6 +1007,9 @@ static int vector_mmsg_rx(struct vector_*/ dev_kfree_skb_irq (skb); vp->estats.rx_encaps_errors++; + (*skbuff_vector) =NULL ; + mmsg_vector++; + skbuff_vector++;continue ; }if (header_check >0 ) {
Greg Kroah-Hartman
maintainerPATCH 419/609 vxlan: re-fetch eth header after route_shortcircuit()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 1395a676ec15a0a02a2a6d86602324f2d5fd41d5 upstream.
Before route_shortcircuit(), the eth header pointer is cached from eth_hdr(skb).
Inside route_shortcircuit(), pskb_may_pull() can be called, which may reallocate skb->head.
In this case, returning to vxlan_xmit() leaves the cached eth pointer pointing to freed memory, leading to a use-after-free when dereferencing eth->h_dest.
Fix this by updating eth = eth_hdr(skb) after calling route_shortcircuit().
--- drivers/net/vxlan/vxlan_core.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/vxlan/vxlan_core.c +1 -0
@@ -2879,6 +2879,7 @@ static netdev_tx_t vxlan_xmit(struct sk_ (ntohs(eth->h_proto) == ETH_P_IP || ntohs(eth->h_proto) == ETH_P_IPV6)) { did_rsc =route_shortcircuit (dev, skb); + eth =eth_hdr (skb);if (did_rsc) f =vxlan_find_mac (vxlan, eth->h_dest, vni); }
Greg Kroah-Hartman
maintainerPATCH 420/609 vxlan: unclone skb head before modifying eth header in route_shortcircuit()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 760d36e737f2b3867762f42af36c663f55babcc4 upstream.
When route_shortcircuit() performs L3 short-circuit routing, it modifies the Ethernet header of the skb in-place:
memcpy(eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, dev->addr_len);
memcpy(eth_hdr(skb)->h_dest, n->ha, dev->addr_len);If the incoming skb is cloned (for example by packet sockets, tcpdump, or dev_queue_xmit), modifying the Ethernet header without uncloning can corrupt the packet header for other readers holding a reference to the cloned skb.
Ensure the skb header is writable and unshared by calling skb_cow_head(skb, 0) prior to updating the Ethernet header. If skb_cow_head() fails, abort short-circuiting and return false to allow standard packet processing fallback.
--- drivers/net/vxlan/vxlan_core.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/vxlan/vxlan_core.c +4 -0
@@ -2208,6 +2208,10 @@ static bool route_shortcircuit(struct ne diff = !ether_addr_equal (eth_hdr (skb)->h_dest, n->ha);if (diff) { +if (skb_cow_head (skb,0 )) { +neigh_release (n); +return false; + }memcpy (eth_hdr (skb)->h_source,eth_hdr (skb)->h_dest, dev->addr_len);memcpy (eth_hdr (skb)->h_dest, n->ha, dev->addr_len);
Greg Kroah-Hartman
maintainerPATCH 421/609 vxlan: use neigh_ha_snapshot() in route_shortcircuit()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 8eca411347e1d38964f9ed2c8d3b6ab0e7e4473d upstream.
The neighbour hardware address n->ha can be updated asynchronously by the neighbour subsystem, protected by n->ha_lock seqlock. Reading n->ha without holding the seqlock loop can lead to torn reads or reading a partially updated MAC address.
Use neigh_ha_snapshot() in route_shortcircuit() to safely copy n->ha under read_seqbegin()/read_seqretry() lock protection before using it.
Note that arp_reduce() and neigh_reduce() seem to have the same issue left for future patches.
--- drivers/net/vxlan/vxlan_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/vxlan/vxlan_core.c +4 -2
@@ -2204,9 +2204,11 @@ static bool route_shortcircuit(struct ne }if (n) { +u8 haddr[ETH_ALEN ];bool diff; - diff = !ether_addr_equal (eth_hdr (skb)->h_dest, n->ha); +neigh_ha_snapshot (haddr, n, dev); + diff = !ether_addr_equal_unaligned (eth_hdr (skb)->h_dest, haddr);if (diff) {if (skb_cow_head (skb,0 )) {neigh_release (n);
@@ -2214,7 +2216,7 @@ static bool route_shortcircuit(struct ne }memcpy (eth_hdr (skb)->h_source,eth_hdr (skb)->h_dest, dev->addr_len); -memcpy (eth_hdr (skb)->h_dest, n->ha, dev->addr_len); +memcpy (eth_hdr (skb)->h_dest, haddr, dev->addr_len); }neigh_release (n);return diff;
Greg Kroah-Hartman
maintainerPATCH 422/609 vxlan: use pskb_network_may_pull() in route_shortcircuit()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 26bb2dd0a8839617e2c79ffbbe1923f8e4bab9fb upstream.
route_shortcircuit() currently calls pskb_may_pull(skb, sizeof(struct iphdr)) (or ipv6hdr), which checks if bytes are available starting from skb->data.
However, in vxlan_xmit(), skb->data points to the MAC header, so skb_network_offset(skb) is ETH_HLEN (14 bytes). Using pskb_may_pull(skb, 20) only checks 20 bytes from skb->data (which is 14 bytes MAC header + 6 bytes of IP header), leaving the rest of the IP header potentially un-pulled in non-linear frags. Subsequent dereferences of ip_hdr(skb)->daddr can read beyond the pulled linear buffer length.
Fix this by using pskb_network_may_pull(), which adds skb_network_offset(skb) to the length check to ensure the full network header is present in the linear buffer.
--- drivers/net/vxlan/vxlan_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/vxlan/vxlan_core.c +2 -2
@@ -2156,7 +2156,7 @@ static bool route_shortcircuit(struct ne {struct iphdr *pip; -if (!pskb_may_pull (skb,sizeof (struct iphdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct iphdr )))return false; pip =ip_hdr (skb); n =neigh_lookup (&arp_tbl, &pip->daddr, dev);
@@ -2182,7 +2182,7 @@ static bool route_shortcircuit(struct ne*/ if (!ipv6_stub->nd_tbl)return false; -if (!pskb_may_pull (skb,sizeof (struct ipv6hdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct ipv6hdr )))return false; pip6 =ipv6_hdr (skb); n =neigh_lookup (ipv6_stub->nd_tbl, &pip6->daddr, dev);
Greg Kroah-Hartman
maintainerPATCH 423/609 ublk: reset kernel-owned dev_info fields in ublk_ctrl_add_dev()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Lei <[email protected]>
commit e65848e4ce352bac9e3465099354c8b8f845391f upstream.
ublk_ctrl_add_dev() memcpy()s the userspace ublksrv_ctrl_dev_info into ub->dev_info and then fixes up the fields the driver owns, but misses ->state and ->ublksrv_pid.
A device added with ->state = UBLK_S_DEV_LIVE passes the "->state != UBLK_S_DEV_DEAD" test that ublk_stop_dev_unlocked() uses as its proxy for "a disk is attached", while ->ub_disk is still NULL, so DEL_DEV right after ADD_DEV oopses in del_gendisk(). UBLK_S_DEV_QUIESCED plus UBLK_F_USER_RECOVERY dies one step earlier, in ublk_force_abort_dev(). A poisoned ->state also gets START_USER_RECOVERY and the char device read/write path onto a device that was never started, and wedges START_DEV at -EEXIST. A poisoned ->ublksrv_pid just makes GET_DEV_INFO report an unrelated task as the ublk server.
Reset both after the memcpy(), as ublk_detach_disk() does. Userspace only ever reads these back, so correcting them silently breaks nothing.
ADD_DEV has copied ->state in unsanitized since ublk was merged, but back then it was harmless: the gendisk was allocated during ADD_DEV, and both teardown and the START_DEV -EEXIST check keyed off disk_live() rather than ->state. The oops became reachable once the disk allocation moved to START_DEV and those checks switched to ->state.
--- drivers/block/ublk_drv.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/block/ublk_drv.c +9 -0
@@ -1727,6 +1727,15 @@ static int ublk_ctrl_add_dev(struct io_u ub->dev_info.dev_id = ub->ub_number;/* +* ->state and ->ublksrv_pid are owned by the driver and only read back +* by userspace, but they come from the copied-in dev_info, so reset +* them. Otherwise a device added with ->state != DEAD looks live while +* ->ub_disk is still NULL. +*/ + ub->dev_info.state =UBLK_S_DEV_DEAD ; + ub->dev_info.ublksrv_pid =-1 ; + +/* * 64bit flags will be copied back to userspace as feature * negotiation result, so have to clear flags which driver * doesn't support yet, then userspace can get correct flags
Greg Kroah-Hartman
maintainerPATCH 424/609 tracing: Check return value of __register_event() in trace_module_add_events()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit ac8719969e6c3c54e939834df812bc41f25453cf upstream.
trace_module_add_events() ignores the return value of __register_event() and unconditionally calls __add_event_to_tracers() for each event.
If __register_event() fails (for example, if event_init() fails), the trace_event_call is not added to ftrace_events list, but __add_event_to_tracers() still creates a trace_event_file pointing to it. If module loading subsequently fails and module memory is freed, tracing state retains a stale trace_event_call pointer in trace_event_file, leading to a use-after-free when tracefs or tracing subsystem operations are later executed.
Fix this by checking the return value of __register_event() and only calling __add_event_to_tracers() if event registration succeeded.
--- kernel/trace/trace_events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/trace/trace_events.c +2 -2
@@ -3122,8 +3122,8 @@ static void trace_module_add_events(stru end = mod->trace_events + mod->num_trace_events;for_each_event (call, start, end) { -__register_event (*call, mod); -__add_event_to_tracers (*call); +if (!__register_event (*call, mod)) +__add_event_to_tracers (*call); } }
Greg Kroah-Hartman
maintainerPATCH 425/609 tracing/filters: Fix false positive match in regex_match_full()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit c22c7b735f9810ad276014f788f9aa5c879ec238 upstream.
regex_match_full() calls strncmp(str, r->pattern, len) where len is the target field buffer size. When len is smaller than r->len (the filter pattern length), strncmp() checks only len bytes of r->pattern against str. If those len bytes match, strncmp() returns 0, resulting in a false-positive match where a shorter string in a fixed-size field matches a longer filter pattern.
For example, a 4-byte static string field containing "abcd" matched the filter pattern "abcdefgh" because strncmp("abcd", "abcdefgh", 4) returned 0. In this case, @len does NOT include '\0' because it is fixed-size array.
Fix this by returning 0 (no match) early when len < r->len.
--- kernel/trace/trace_events_filter.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/trace/trace_events_filter.c +3 -0
@@ -894,6 +894,9 @@ static int regex_match_full(char *str, sif (!len)return strcmp (str, r->pattern) ==0 ; +if (len < r->len) +return 0 ; +return strncmp (str, r->pattern, len) ==0 ; }
Greg Kroah-Hartman
maintainerPATCH 426/609 selftests/clone3: fix wild pointer access of getline due to missing init
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Gellermann <[email protected]>
commit 8f6f9fd93cd7a5dd607ad5cd910476dd68fff3ed upstream.
Patch series "selftests: Add missing initalization of pointer passed to getline", v2.
This patch (of 2):
Clone3_set_tid uses getline(&line, ...) in a loop to read the child's process status. The code expects that getline allocates the buffer for the line on the first loop iteration. According to the Open Group Spec[1], char *line has to be null pointer for this:
Quoted 3 lines
ssize_tgetline(char **restrict lineptr, ...);
If *lineptr is a null pointer or if the object pointed to by *lineptr is of insufficient size, an object shall be allocated as if by
malloc()
Quoted 1 line
or the object shall be reallocated as if by realloc()[...].
However, char *line is only declared, leading to an undefined value that is potentially non-null. In an example run with Musl v1.2.6, the realloc call[2] of getdelim, which implements getline, triggers a segfault:
./run_kselftest.sh --test clone3:clone3_set_tid
[ 1366.165898] kselftest: Running tests in clone3 ... [ 1367.799244] clone3_set_tid[811]: unhandled signal 11 code 0x1 at 0x0000000000000000 in libc.so[68184,3fbf69f000+4c000] [ 1367.802808] CPU: 0 UID: 0 PID: 811 Comm: clone3_set_tid Not tainted .. [ 1367.804188] epc: 0x0000003fbf6b0184 [ 1367.804188] ra : 0x0000003fbf6d4664 [ 1367.804188] sp : 0x0000003fce5f2e40 [ 1367.805314] gp : 0x0000002aaab0dfb8 [ 1367.805314] tp : 0x0000003fbf6f14a8 [ 1367.805314] t0 : 0x0000003fbf63d000
...
Looking at the realloc implementation, Musl mallocs for a null pointer memory. But for a non-null pointer, it assumes it's passed a valid pointer to the heap and tries to access its meta-data. This leads to the segfault we see:
void *realloc(void *p, size_t n)
{
if (!p) return malloc(n);
if (size_overflows(n)) return 0;
struct meta *g = get_meta(p);
...
}Fix this by properly initializing the line pointer to NULL.
--- tools/testing/selftests/clone3/clone3_set_tid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/clone3/clone3_set_tid.c +1 -1
@@ -146,7 +146,7 @@ int main(int argc, char *argv[]) {FILE *f;char buf; -char *line; +char *line =NULL ;int status;int ret =-1 ;size_t len =0 ;
Greg Kroah-Hartman
maintainerPATCH 427/609 scsi: scsi_debug: Fix REPORT ZONES alloc_len underflow OOB write
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
commit 93dde0bf2f39a0f9f57fd610aa3201ce5b753433 upstream.
resp_report_zones() sizes the reply buffer from the CDB allocation length. The v3 fix rounds alloc_len up with ALIGN() before deriving the descriptor count:
rep_max_zones = (ALIGN((u64)alloc_len, RZONES_DESC_HD) - RZONES_DESC_HD) >> ilog2(RZONES_DESC_HD); arr_len = (u64)RZONES_DESC_HD * (rep_max_zones + 1);
For alloc_len in 0xFFFFFFC1..0xFFFFFFFF, ALIGN() rounds up to 0x100000000, so arr_len is 4 GB. On 32-bit, kzalloc()'s size_t is 32-bit and truncates 0x100000000 to 0; kzalloc(0) returns ZERO_SIZE_PTR, which passes the !arr check, and desc = arr + 64 is then dereferenced in the loop -> out-of-bounds write / panic.
Clamp rep_max_zones to devip->nr_zones. The loop already stops at sdebug_capacity (after nr_zones zones), so a report can never hold more than nr_zones descriptors; the clamp does not change the report, it only bounds arr_len to (nr_zones + 1) * RZONES_DESC_HD, a real device property that can never reach 0x100000000.
--- drivers/scsi/scsi_debug.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/scsi/scsi_debug.c +6 -2
@@ -4481,6 +4481,7 @@ static int resp_report_zones(struct scsiu32 alloc_len, rep_opts, rep_len;bool partial;u64 lba, zs_lba; +u64 arr_len;u8 *arr =NULL , *desc;u8 *cmd = scp->cmnd;struct sdeb_zone_state *zsp =NULL ;
@@ -4502,9 +4503,12 @@ static int resp_report_zones(struct scsireturn check_condition_result; } - rep_max_zones = (alloc_len -64 ) >>ilog2 (RZONES_DESC_HD ); + rep_max_zones = (ALIGN ((u64 )alloc_len,RZONES_DESC_HD ) -RZONES_DESC_HD ) >> +ilog2 (RZONES_DESC_HD ); + rep_max_zones = min_t(unsigned int, rep_max_zones, devip->nr_zones); + arr_len = (u64 )RZONES_DESC_HD * (rep_max_zones +1 ); - arr =kzalloc (alloc_len,GFP_ATOMIC | __GFP_NOWARN); + arr =kzalloc (arr_len,GFP_ATOMIC | __GFP_NOWARN);if (!arr) {mk_sense_buffer (scp,ILLEGAL_REQUEST ,INSUFF_RES_ASC ,INSUFF_RES_ASCQ );
Greg Kroah-Hartman
maintainerPATCH 428/609 sctp: reject stale cookies with mismatched verification tags
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuxiang Yang <[email protected]>
commit 9d8da8e0a9bce4a340af60dd0446bc7eb8d07587 upstream.
sctp_unpack_cookie() skips cookie expiration checks whenever an association already exists. This is broader than the exception in RFC 9260 Section 5.2.4.
For an existing association, Section 5.2.4 permits an expired State Cookie only when both Verification Tags in the cookie match the current association. Otherwise, the packet SHOULD be discarded and a Stale Cookie ERROR MUST be sent.
The broad check lets an expired Action A restart cookie reach sctp_sf_do_dupcook_a(). In a runtime test with the default 60 second cookie lifetime, replaying such a cookie after 65 seconds returned a COOKIE-ACK and restarted the association.
Check cookie expiration unless both Verification Tags match. This preserves the Action D exception for a lost COOKIE ACK while rejecting expired cookies in all other cases.
--- net/sctp/sm_make_chunk.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
net/sctp/sm_make_chunk.c +7 -4
@@ -1821,9 +1821,9 @@ no_hmac: goto fail; } -/* Check to see if the cookie is stale. If there is already -* an association, there is no need to check cookie's expiration -* for init collision case of lost COOKIE ACK. +/* Check to see if the cookie is stale. RFC 9260 Section 5.2.4 +* exempts an expired cookie only when both Verification Tags match +* the current association. * If skb has been timestamped, then use the stamp, otherwise * use current time. This introduces a small possibility that * a cookie may be considered expired, but this would only slow
@@ -1834,7 +1834,10 @@ no_hmac:else kt =ktime_get_real (); -if (!asoc &&ktime_before (bear_cookie->expiration, kt)) { +if ((!asoc || + asoc->c.my_vtag != bear_cookie->my_vtag || + asoc->c.peer_vtag != bear_cookie->peer_vtag) && +ktime_before (bear_cookie->expiration, kt)) {suseconds_t usecs =ktime_to_us (ktime_sub (kt, bear_cookie->expiration));__be32 n =htonl (usecs);
Greg Kroah-Hartman
maintainerPATCH 429/609 sctp: prevent peer transport count overflow
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asim Viladi Oglu Manizada <[email protected]>
commit bd0e9289e2642f6a5c54faad304ce0f41e926d22 upstream.
sctp_assoc_add_peer() increments the association's 16-bit transport_count for every new unique peer. Adding the 65,536th transport wraps the count to zero.
SCTP sock_diag uses transport_count to reserve the INET_DIAG_PEERS payload, then copies one sockaddr_storage for every entry in transport_addr_list. After the wrap, a diagnostic dump reserves an empty payload and writes 8 MiB of peer addresses past the skb tail.
Reject a new unique peer when transport_count has reached U16_MAX. Perform the check after the existing-peer lookup so a duplicate address continues to return its existing transport at the limit.
--- net/sctp/associola.c | 3 +++ 1 file changed, 3 insertions(+)
net/sctp/associola.c +3 -0
@@ -616,6 +616,9 @@ struct sctp_transport *sctp_assoc_add_pereturn peer; } +if (asoc->peer.transport_count ==U16_MAX ) +return NULL ; + peer =sctp_transport_new (asoc->base.net, addr, gfp);if (!peer)return NULL ;
Greg Kroah-Hartman
maintainerPATCH 430/609 hwmon: (npcm750-pwm-fan): stop fan timer on device detach
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
commit f27f6976ea269219c1259a7c2f8c6dfe782540a3 upstream.
When a fan tach channel is present, npcm7xx_pwm_fan_probe() starts fan_timer. The timer callback polls tach state and rearms the timer, but the driver has no remove callback or devm cleanup action to stop it. On device detach, the devm-managed driver data and I/O mappings can be released while the timer is still pending or running.
Register a devm cleanup action before starting the timer and shut the timer down synchronously from that action.
This issue was found by a static analysis tool.
--- drivers/hwmon/npcm750-pwm-fan.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/hwmon/npcm750-pwm-fan.c +11 -0
@@ -360,6 +360,11 @@ static void npcm7xx_fan_polling(struct tadd_timer (&data->fan_timer); } +static void npcm7xx_fan_cleanup (void *timer) +{ +timer_shutdown_sync (timer); +} +static inline void npcm7xx_fan_compute (struct npcm7xx_pwm_fan_data *data,u8 fan,u8 cmp,u8 fan_id,u8 flag_int,u8 flag_mode,u8 flag_clear)
@@ -1003,6 +1008,12 @@ static int npcm7xx_pwm_fan_probe(structmsecs_to_jiffies (NPCM7XX_FAN_POLL_TIMER_200MS );timer_setup (&data->fan_timer, npcm7xx_fan_polling,0 ); + ret =devm_add_action_or_reset (dev, + npcm7xx_fan_cleanup, + &data->fan_timer); +if (ret) +return ret; +add_timer (&data->fan_timer);break ; }
Greg Kroah-Hartman
maintainerPATCH 431/609 i2c: amd-mp2: Unregister callback on adapter add failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 82048795242f04275a3f49ffc66ad851b6120954 upstream.
amd_mp2_register_cb() stores the platform I2C context in the MP2 PCI driver's callback table before the adapter is registered. If i2c_add_adapter() fails, probe returns and devres frees the context, but the PCI driver can still dereference the stale pointer from its IRQ and system-sleep callbacks.
Unregister the callback before returning the adapter registration error.
--- drivers/i2c/busses/i2c-amd-mp2-plat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/i2c/busses/i2c-amd-mp2-plat.c +3 -1
@@ -316,8 +316,10 @@ static int i2c_amd_probe(struct platformamd_mp2_pm_runtime_put (mp2_dev); -if (ret <0 ) +if (ret <0 ) {dev_err (&pdev->dev,"i2c add adapter failed = %d\n" , ret); +amd_mp2_unregister_cb (&i2c_dev->common); + }return ret; }
Greg Kroah-Hartman
maintainerPATCH 432/609 gpio: pca953x: fix cache_only and IRQ state on restore_context() failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: bui duc phuc <[email protected]>
commit d233087c19f6607ef926ac3f47d776e2406ffd1f upstream.
When pca953x_restore_context() fails, cache_only is left disabled and the IRQ left enabled, even though register synchronization may not have completed successfully. Restore cache_only and disable the IRQ again on failure, matching the state set by pca953x_save_context().
--- drivers/gpio/gpio-pca953x.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/gpio/gpio-pca953x.c +13 -2
@@ -1247,9 +1247,20 @@ static int pca953x_restore_context(strucregcache_mark_dirty (chip->regmap); ret =pca953x_regcache_sync (chip);if (ret) -return ret; + goto err; -return regcache_sync (chip->regmap); + ret =regcache_sync (chip->regmap); +if (ret) + goto err; + +return 0 ; + +err: +if (chip->client->irq >0 ) +disable_irq (chip->client->irq); +regcache_cache_only (chip->regmap, true); + +return ret; }static void pca953x_save_context (struct pca953x_chip *chip)
Greg Kroah-Hartman
maintainerPATCH 433/609 cpufreq: powernow-k8: Fix possible memory leak in powernowk8_cpu_init()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit d5f8e5f6040d052d44fcbf4f31dd35145c0c8d7d upstream.
The memory allocated for data->powernow_table inside powernow_k8_cpu_init_acpi() or find_psb_table() is not freed in one of the error paths in powernowk8_cpu_init(). Fix that by adding a kfree().
--- drivers/cpufreq/powernow-k8.c | 1 + 1 file changed, 1 insertion(+)
drivers/cpufreq/powernow-k8.c +1 -0
@@ -1083,6 +1083,7 @@ static int powernowk8_cpu_init(struct cp err_out_exit_acpi:powernow_k8_cpu_exit_acpi (data); +kfree (data->powernow_table); err_out:kfree (data);
Greg Kroah-Hartman
maintainerPATCH 434/609 power: supply: bq25890: fix the -10 C NTC lookup entry
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 160a783aa65b74782bc17cb874af1a6d3f5fba3c upstream.
The TSPCT lookup table is monotonically decreasing except for ADC code 121, where the sequence reads -9.0 C, -1.0 C, -12.0 C. This makes the reported battery temperature jump upward by eight degrees for one code and then downward by eleven degrees for the next code.
The entry is a missing zero: use -10.0 C so the sequence remains monotonic between -9.0 C and -12.0 C.
--- drivers/power/supply/bq25890_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/power/supply/bq25890_charger.c +1 -1
@@ -310,7 +310,7 @@ static const u32 bq25890_tspct_tbl[] = {145 ,140 ,130 ,120 ,115 ,110 ,100 ,90 ,80 ,70 ,60 ,50 ,40 ,30 ,20 ,10 ,0 ,-10 ,-20 ,-30 ,-40 ,-60 ,-70 ,-80 , - -90, -10, -120, -140, -150, -170, -190, -210, + -90, -100, -120, -140, -150, -170, -190, -210, };#define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl)
Greg Kroah-Hartman
maintainerPATCH 435/609 s390/qeth: Check CAP_NET_ADMIN for private ioctls
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aswin Karuvally <[email protected]>
commit d211028bac1bd0fff0026bfa2a8328e5b78cd0e6 upstream.
Gate the SIOCDEVPRIVATE ioctl commands SIOC_QETH_ADP_SET_SNMP_CONTROL, SIOC_QETH_GET_CARD_TYPE and SIOC_QETH_QUERY_OAT with CAP_NET_ADMIN capable check to ensure unprivileged users cannot invoke them.
--- drivers/s390/net/qeth_core_main.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/s390/net/qeth_core_main.c +3 -0
@@ -6524,6 +6524,9 @@ int qeth_siocdevprivate(struct net_devicstruct qeth_card *card = dev->ml_priv;int rc =0 ; +if (!capable (CAP_NET_ADMIN )) +return -EPERM ; +switch (cmd) {case SIOC_QETH_ADP_SET_SNMP_CONTROL : rc =qeth_snmp_command (card, data);
Greg Kroah-Hartman
maintainerPATCH 436/609 s390/dasd: Fix potential NULL pointer dereference
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Höppner <[email protected]>
commit 9973026f572db6b67570cadc30942f3014e41079 upstream.
dasd_release_space() checks the implementation of the is_ese() discipline function before calling it to determine if a given device is an ESE DASD.
The current usage of the logical AND operator will lead to a NULL pointer dereference as the function is called even if the function pointer is NULL.
Fix this by using the logical OR operator.
--- drivers/s390/block/dasd_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/block/dasd_ioctl.c +1 -1
@@ -330,7 +330,7 @@ out_err:static int dasd_release_space (struct dasd_device *device,struct format_data_t *rdata) { -if (!device->discipline->is_ese && !device->discipline->is_ese (device)) +if (!device->discipline->is_ese || !device->discipline->is_ese (device))return -ENOTSUPP ;if (!device->discipline->release_space)return -ENOTSUPP ;
Greg Kroah-Hartman
maintainerPATCH 437/609 s390/zcrypt: Fix wrong domain value verification with EP11 CPRBs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <[email protected]>
commit 983279d7f86ade73db86f886e09172dd567031b5 upstream.
There is a wrong upper limit check for the domain value when an EP11 CPRB is processed for sending to a crypto card. This check is only active on custom device nodes but may lead to access heap memory behind perms->adm when an administrative CPRB is sent. Add correct limit (AP_DOMAINS = 256) checking to fix this.
--- drivers/s390/crypto/zcrypt_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/crypto/zcrypt_api.c +1 -1
@@ -1119,7 +1119,7 @@ static long _zcrypt_send_ep11_cprb(boolif (rc) goto out_free; -if (perms != &ap_perms && domain <AUTOSEL_DOM ) { +if (perms != &ap_perms && domain <AP_DOMAINS ) {if (ap_msg.flags &AP_MSG_FLAG_ADMIN ) {if (!test_bit_inv (domain, perms->adm)) { rc = -ENODEV ;
Greg Kroah-Hartman
maintainerPATCH 438/609 s390/zcrypt: Validate length for CCA AES cipher key requests
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Holger Dengler <[email protected]>
commit 06afe425d5283b9764303de47f554da5a808ce8a upstream.
cca_cipher2protkey() derives the copy length for the CPRB parameter block directly from the length field in the key token. Reject the request early if the token length exceeds the available space in the parameter block.
--- drivers/s390/crypto/zcrypt_ccamisc.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/s390/crypto/zcrypt_ccamisc.c +3 -0
@@ -1232,6 +1232,9 @@ int cca_cipher2protkey(u16 cardnr, u16 d }__packed * prepparm;int keytoklen = ((struct cipherkeytoken *)ckey)->len; +if (keytoklen >PARMBSIZE -sizeof (struct aureqparm )) +return -EINVAL ; +/* get already prepared memory for 2 cprbs with param block each */ rc =alloc_and_prep_cprbmem (PARMBSIZE , &mem, &preqcblk, &prepcblk);if (rc)
Greg Kroah-Hartman
maintainerPATCH 439/609 s390/zcrypt: Validate length for CCA ECC private key requests
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Holger Dengler <[email protected]>
commit a9ae0f6dd45c3ccc1d69363f7aea8af179122730 upstream.
cca_ecc2protkey() derives the copy length for the CPRB parameter block directly from the length field in the key token. Reject the request early if the token length exceeds the available space in the parameter block.
--- drivers/s390/crypto/zcrypt_ccamisc.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/s390/crypto/zcrypt_ccamisc.c +3 -0
@@ -1404,6 +1404,9 @@ int cca_ecc2protkey(u16 cardnr, u16 doma }__packed * prepparm;int keylen = ((struct eccprivkeytoken *)key)->len; +if (keylen >PARMBSIZE -sizeof (struct aureqparm )) +return -EINVAL ; +/* get already prepared memory for 2 cprbs with param block each */ rc =alloc_and_prep_cprbmem (PARMBSIZE , &mem, &preqcblk, &prepcblk);if (rc)
Greg Kroah-Hartman
maintainerPATCH 440/609 phy: zynqmp: fix L0_TM_DISABLE_SCRAMBLE_ENCODER mask
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nava kishore Manne <[email protected]>
commit 6cb22477929489a412df8d153e550e77a012e701 upstream.
The L0_TX_DIG_61 register bit 2 is a reserved read-only field. The previous mask value 0x0f incorrectly included bit 2, causing unintended writes to a reserved bit on every scrambler bypass operation.
Correct the mask to (BIT(3) | GENMASK(1, 0)) to cover only the valid scramble bypass control bits.
--- drivers/phy/xilinx/phy-zynqmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/phy/xilinx/phy-zynqmp.c +1 -1
@@ -53,7 +53,7 @@#define L0_TM_DIG_6 0x106c#define L0_TM_DIS_DESCRAMBLE_DECODER 0x0f#define L0_TX_DIG_61 0x00f4 -#define L0_TM_DISABLE_SCRAMBLE_ENCODER 0x0f +#define L0_TM_DISABLE_SCRAMBLE_ENCODER (BIT(3) | GENMASK(1, 0))/* PLL Test Mode register parameters */ #define L0_TM_PLL_DIG_37 0x2094
Greg Kroah-Hartman
maintainerPATCH 441/609 phy: zynqmp: use read-modify-write for SERDES scrambler bypass
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nava kishore Manne <[email protected]>
commit 21e0749f931702765b9d52d05740092bc87fcd8d upstream.
xpsgtr_bypass_scrambler_8b10b() used xpsgtr_write_phy() which performs a full register write, silently clearing any bits beyond the intended bypass control fields.
Switch to xpsgtr_clr_set_phy() with clr=mask, set=mask to set only the bypass bits while preserving the remaining bits in each register.
--- drivers/phy/xilinx/phy-zynqmp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/phy/xilinx/phy-zynqmp.c +6 -2
@@ -491,8 +491,12 @@ static void xpsgtr_lane_set_protocol(str/* Bypass (de)scrambler and 8b/10b decoder and encoder. */ static void xpsgtr_bypass_scrambler_8b10b (struct xpsgtr_phy *gtr_phy) { -xpsgtr_write_phy (gtr_phy,L0_TM_DIG_6 ,L0_TM_DIS_DESCRAMBLE_DECODER ); -xpsgtr_write_phy (gtr_phy,L0_TX_DIG_61 ,L0_TM_DISABLE_SCRAMBLE_ENCODER ); +xpsgtr_clr_set_phy (gtr_phy,L0_TM_DIG_6 , +L0_TM_DIS_DESCRAMBLE_DECODER , +L0_TM_DIS_DESCRAMBLE_DECODER ); +xpsgtr_clr_set_phy (gtr_phy,L0_TX_DIG_61 , +L0_TM_DISABLE_SCRAMBLE_ENCODER , +L0_TM_DISABLE_SCRAMBLE_ENCODER ); }/* DP-specific initialization. */
Greg Kroah-Hartman
maintainerPATCH 442/609 phy: zynqmp: keep SERDES scrambler and 8b/10b enabled for USB
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nava kishore Manne <[email protected]>
commit 7eb61caf45607e1e1270f51f8f93f0ded53146da upstream.
USB Gen1 requires scrambling and 8b/10b encoding to be performed in the physical layer. Do not bypass PHY-side scrambler or encoder/decoder for USB operation, as mandated by the USB 3.x specification.
Scrambler and 8b/10b bypass remain restricted to SATA and SGMII modes, where encoding is handled in the controller.
--- drivers/phy/xilinx/phy-zynqmp.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-)
drivers/phy/xilinx/phy-zynqmp.c +29 -10
@@ -488,15 +488,30 @@ static void xpsgtr_lane_set_protocol(str } } -/* Bypass (de)scrambler and 8b/10b decoder and encoder. */ -static void xpsgtr_bypass_scrambler_8b10b (struct xpsgtr_phy *gtr_phy) +/** +* xpsgtr_bypass_scrambler_8b10b - Configure scrambler/encoder behavior +* @gtr_phy: pointer to lane context +* @bypass: true to enable scrambler/encoder bypass (SATA/SGMII), +* false to disable scrambler/encoder bypass (USB3) +* +* Uses RMW to preserve reserved and unrelated register fields. +*/ +static void xpsgtr_bypass_scrambler_8b10b (struct xpsgtr_phy *gtr_phy, +bool bypass) { -xpsgtr_clr_set_phy (gtr_phy,L0_TM_DIG_6 , -L0_TM_DIS_DESCRAMBLE_DECODER , -L0_TM_DIS_DESCRAMBLE_DECODER ); -xpsgtr_clr_set_phy (gtr_phy,L0_TX_DIG_61 , -L0_TM_DISABLE_SCRAMBLE_ENCODER , -L0_TM_DISABLE_SCRAMBLE_ENCODER ); +if (bypass) { +xpsgtr_clr_set_phy (gtr_phy,L0_TM_DIG_6 , +L0_TM_DIS_DESCRAMBLE_DECODER , +L0_TM_DIS_DESCRAMBLE_DECODER ); +xpsgtr_clr_set_phy (gtr_phy,L0_TX_DIG_61 , +L0_TM_DISABLE_SCRAMBLE_ENCODER , +L0_TM_DISABLE_SCRAMBLE_ENCODER ); + }else { +xpsgtr_clr_set_phy (gtr_phy,L0_TM_DIG_6 , +L0_TM_DIS_DESCRAMBLE_DECODER ,0 ); +xpsgtr_clr_set_phy (gtr_phy,L0_TX_DIG_61 , +L0_TM_DISABLE_SCRAMBLE_ENCODER ,0 ); + } }/* DP-specific initialization. */
@@ -517,7 +532,7 @@ static void xpsgtr_phy_init_sata(struct {struct xpsgtr_dev *gtr_dev = gtr_phy->dev; -xpsgtr_bypass_scrambler_8b10b (gtr_phy); +xpsgtr_bypass_scrambler_8b10b (gtr_phy, true);writel (gtr_phy->lane, gtr_dev->siou +SATA_CONTROL_OFFSET ); }
@@ -533,7 +548,7 @@ static void xpsgtr_phy_init_sgmii(structxpsgtr_clr_set (gtr_dev,TX_PROT_BUS_WIDTH , mask, val);xpsgtr_clr_set (gtr_dev,RX_PROT_BUS_WIDTH , mask, val); -xpsgtr_bypass_scrambler_8b10b (gtr_phy); +xpsgtr_bypass_scrambler_8b10b (gtr_phy, true); }/* Configure TX de-emphasis and margining for DP. */
@@ -694,6 +709,10 @@ static int xpsgtr_phy_init(struct phy *pcase ICM_PROTOCOL_SGMII :xpsgtr_phy_init_sgmii (gtr_phy);break ; + +case ICM_PROTOCOL_USB : +xpsgtr_bypass_scrambler_8b10b (gtr_phy, false); +break ; } goto out;
Greg Kroah-Hartman
maintainerPATCH 443/609 net: openvswitch: fix potential UAF on meter attach failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Maximets <[email protected]>
commit a58a2b0ce354df531ebc71fc870058c2feb59f6b upstream.
While attaching a newly created meter attach_meter() function makes the new meter visible to other CPUs but can still fail afterwards. On failure, it detaches the meter back and returns an error.
However, this is an unexpected behavior for the ovs_meter_cmd_set() that uses a plain kfree(meter) on attach failure without waiting for RCU readers to stop using it, assuming it was never visible.
This is never a problem for ovs-vswitchd as it always creates meters before creating any flows that use them. But the UAF can be triggered with a custom application using uAPI:
BUG: KASAN: slab-use-after-free in ovs_meter_execute (net/openvswitch/meter.c:653) Read of size 8 at addr ffff88810d152650 by task meter/2508 Call Trace: ovs_meter_execute (net/openvswitch/meter.c:653) do_execute_actions (net/openvswitch/actions.c:1407) ovs_execute_actions (net/openvswitch/actions.c:1584) ovs_packet_cmd_execute (net/openvswitch/datapath.c:703) ... netlink_sendmsg (af_netlink.c:1900) Allocated by task 2519: __kasan_kmalloc (mm/kasan/common.c:398 mm/kasan/common.c:415) ovs_meter_cmd_set (net/openvswitch/meter.c:422) ... netlink_sendmsg (af_netlink.c:1900) Freed by task 2519: kfree (mm/slub.c:2705 mm/slub.c:6405 mm/slub.c:6720) ovs_meter_cmd_set (net/openvswitch/meter.c:479) ... netlink_sendmsg (af_netlink.c:1900)
Fix that by making sure attach_meter() doesn't make the meter visible until all the checks are done and the function can't fail anymore.
This also makes sure the "hash" value is calculated after the potential re-sizing of the table.
Reported by Trend Micro's Zero Day Initiative as ZDI-CAN-31642.
--- net/openvswitch/meter.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-)
net/openvswitch/meter.c +19 -14
@@ -135,18 +135,10 @@ static void dp_meter_instance_remove(strstatic int attach_meter (struct dp_meter_table *tbl,struct dp_meter *meter) { -struct dp_meter_instance *ti =rcu_dereference_ovsl (tbl->ti); -u32 hash =meter_hash (ti, meter->id); +struct dp_meter_instance *ti; +u32 hash;int err; -/* In generally, slots selected should be empty, because -* OvS uses id-pool to fetch a available id. -*/ -if (unlikely (rcu_dereference_ovsl (ti->dp_meters[hash]))) -return -EBUSY ; - -dp_meter_instance_insert (ti, meter); -/* That function is thread-safe. */ tbl->count++;if (tbl->count >= tbl->max_meters_allowed) {
@@ -154,16 +146,29 @@ static int attach_meter(struct dp_meter_ goto attach_err; } -if (tbl->count >= ti->n_meters && -dp_meter_instance_realloc (tbl, ti->n_meters *2 )) { - err = -ENOMEM ; + ti =rcu_dereference_ovsl (tbl->ti); +if (tbl->count >= ti->n_meters) { + err =dp_meter_instance_realloc (tbl, ti->n_meters *2 ); +if (err) + goto attach_err; + + ti =rcu_dereference_ovsl (tbl->ti); + } + + hash =meter_hash (ti, meter->id); + +/* In general, selected slots should be empty, because +* OvS uses id-pool to fetch available ids. +*/ +if (unlikely (rcu_dereference_ovsl (ti->dp_meters[hash]))) { + err = -EBUSY ; goto attach_err; } +dp_meter_instance_insert (ti, meter);return 0 ; attach_err: -dp_meter_instance_remove (ti, meter); tbl->count--;return err; }
Greg Kroah-Hartman
maintainerPATCH 444/609 net: openvswitch: fix skb leak on flow key update failure during ct
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Maximets <[email protected]>
commit bc62e843bc48f933da765ce47079fd992e535794 upstream.
ovs_ct_execute() always steals or frees the skb on failure while ovs_flow_key_update() does not. So, if it fails and we return right away, the skb ends up leaked.
Fix that by breaking instead and letting the common error handling code at the bottom of the loop to free the skb properly.
This is a very unlikely scenario as it requires the packet to become unparseable by applying a set of actions on a previously parseable skb, but should be fixed nevertheless.
Reported by Sashiko.
--- net/openvswitch/actions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/openvswitch/actions.c +1 -1
@@ -1326,7 +1326,7 @@ static int do_execute_actions(struct datif (!is_flow_key_valid (key)) { err =ovs_flow_key_update (skb, key);if (err) -return err; +break ; } err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key,
Greg Kroah-Hartman
maintainerPATCH 445/609 ice: wait for reset completion in ice_resume()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aaron Ma <[email protected]>
commit c2816d613f388814d27bc9fd6dbd931a88056e19 upstream.
ice_resume() schedules an asynchronous PF reset and returns immediately. The reset runs later in ice_service_task(). If userspace tries to bring up the net device before the reset finishes, ice_open() fails with -EBUSY:
ice_resume()
ice_schedule_reset() # sets ICE_PFR_REQ, returns
...
ice_open()
ice_is_reset_in_progress() # ICE_PFR_REQ still set, -EBUSY
...
ice_service_task()
ice_do_reset()
ice_rebuild() # clears ICE_PFR_REQ, too late
Reproduced on E800 series NICs during suspend/resume with irdma enabled, where the aux device probe widens the race window.
ice 0000:81:00.0: can't open net device while reset is in progress
Add a best-effort wait (10s timeout, matching ice_devlink_info_get()) for the reset to complete before returning from ice_resume(). In practice the reset completes in ~300ms.
--- drivers/net/ethernet/intel/ice/ice_main.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/net/ethernet/intel/ice/ice_main.c +10 -0
@@ -5369,6 +5369,16 @@ static int __maybe_unused ice_resume(str/* Restart the service task */ mod_timer (&pf->serv_tmr,round_jiffies (jiffies + pf->serv_tmr_period)); +/* Best-effort wait for the scheduled reset to finish so that the +* device is operational before returning. Without this, userspace +* (e.g. NetworkManager) may try to open the net device while the +* asynchronous reset is still in progress, hitting -EBUSY. +*/ + ret =ice_wait_for_reset (pf,secs_to_jiffies (10 )); +if (ret) +dev_err (dev,"Wait for reset timed out (10s) during resume: %d\n" , + ret); + return 0; }#endif /* CONFIG_PM */
Greg Kroah-Hartman
maintainerPATCH 446/609 i2c: jz4780: Cache host clock rate at probe to prevent CCF prepare_lock deadlock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: H. Nikolaus Schaller <[email protected]>
commit d99607c888f26e8a4e9fe9772860cef4aff86bb4 upstream.
Fix a severe AB/BA deadlock between the Common Clock Framework (CCF) and the I2C adapter lock, which triggers when an I2C-controlled clock generator client (like the Si5351) is registered or modified under the CCF.
During an i2c client clock (generator) frequency change, the CCF acquires its global 'prepare_lock' mutex and the driver calls i2c_transfer() to update the client's chip registers, stalling for the adapter's I2C bus lock.
Concurrently, an independent, parallel transfer on the same bus (e.g., a GPIO expander handling LEDs) can hold the I2C adapter lock. Inside this parallel transfer path, jz4780_i2c_set_speed() calls clk_get_rate() on the host controller's input clock to calculate bus timings. This call attempts to acquire the blocked CCF 'prepare_lock', creating a circular dependency that freezes the system.
The jz4780 host controller clock itself is static and never changes at runtime.
However, calling clk_get_rate() inside the active transfer path introduces an unnecessary dependency on the CCF internal locks.
Eliminate this synchronous clk_get_rate() call from the active transfer path by caching the static host peripheral clock rate once - inside the private jz4780_i2c structure during jz4780_i2c_probe(). Update jz4780_i2c_set_speed() to use this cached value, safely decoupling active I2C transactions from the CCF internal locks without any risk of stale timings.
Assisted-by web based Google AI (pinpointing the bug and writing the message).
--- drivers/i2c/busses/i2c-jz4780.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/i2c/busses/i2c-jz4780.c +4 -1
@@ -141,6 +141,7 @@ struct jz4780_i2c {void __iomem *iomem;int irq;struct clk *clk; +unsigned long clk_rate_khz;struct i2c_adapter adap;const struct ingenic_i2c_config *cdata;
@@ -246,7 +247,7 @@ static int jz4780_i2c_set_target(structstatic int jz4780_i2c_set_speed (struct jz4780_i2c *i2c) { -int dev_clk_khz =clk_get_rate (i2c->clk) /1000 ; +int dev_clk_khz = i2c->clk_rate_khz;int cnt_high =0 ;/* HIGH period count of the SCL clock */ int cnt_low =0 ;/* LOW period count of the SCL clock */ int cnt_period =0 ;/* period count of the SCL clock */
@@ -800,6 +801,8 @@ static int jz4780_i2c_probe(struct platfif (ret)return ret; + i2c->clk_rate_khz =clk_get_rate (i2c->clk) /1000 ; + ret =of_property_read_u32 (pdev->dev.of_node,"clock-frequency" , &clk_freq);if (ret) {
Greg Kroah-Hartman
maintainerPATCH 447/609 i2c: imx: Fix slave registration race and error handling
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liem <[email protected]>
commit d64ec362c369bbc33833f7936d5f3a706b0d5c45 upstream.
In i2c_imx_reg_slave(), the slave pointer was assigned before pm_runtime_resume_and_get(). If pm_runtime_resume_and_get() failed, the error path returned without clearing i2c_imx->slave, leaving it non-NULL and causing all subsequent registration attempts to fail with -EBUSY.
Additionally, because this driver uses a shared IRQ, the interrupt handler i2c_imx_isr() can execute concurrently and, after acquiring slave_lock, dereference i2c_imx->slave. The previous fix attempt added a lockless i2c_imx->slave = NULL on the error path, but that could race with the ISR under the lock and still cause a NULL pointer dereference.
Fix both issues by deferring the assignment of i2c_imx->slave and i2c_imx->last_slave_event to after a successful resume, and by performing the assignment inside the slave_lock critical section. This guarantees that the slave pointer is never left stale on the error path and is always valid when observed by the interrupt handler.
--- drivers/i2c/busses/i2c-imx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/i2c/busses/i2c-imx.c +5 -3
@@ -871,9 +871,6 @@ static int i2c_imx_reg_slave(struct i2c_if (i2c_imx->slave)return -EBUSY ; - i2c_imx->slave = client; - i2c_imx->last_slave_event =I2C_SLAVE_STOP ; -/* Resume */ ret =pm_runtime_resume_and_get (i2c_imx->adapter.dev.parent);if (ret <0 ) {
@@ -881,6 +878,11 @@ static int i2c_imx_reg_slave(struct i2c_return ret; } + scoped_guard(spinlock_irqsave, &i2c_imx->slave_lock) { + i2c_imx->slave = client; + i2c_imx->last_slave_event =I2C_SLAVE_STOP ; + } +i2c_imx_slave_init (i2c_imx);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 448/609 i2c: imx: Cancel hrtimer before clearing slave pointer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liem <[email protected]>
commit 6ac7702b6cc2b94aaed9ef2d95bfbefcdc90061f upstream.
In i2c_imx_unreg_slave(), the slave pointer is set to NULL after disabling interrupts. However, a pending interrupt might already have started the hrtimer (i2c_imx_slave_timeout) before the pointer was cleared. If the hrtimer fires after i2c_imx->slave is set to NULL, the timer callback i2c_imx_slave_finish_op() will call i2c_imx_slave_event() with a NULL slave pointer, which results in a use-after-free / NULL pointer dereference.
Fix by canceling the hrtimer and waiting for it to complete after disabling interrupts, before clearing the slave pointer.
--- drivers/i2c/busses/i2c-imx.c | 1 + 1 file changed, 1 insertion(+)
drivers/i2c/busses/i2c-imx.c +1 -0
@@ -901,6 +901,7 @@ static int i2c_imx_unreg_slave(struct i2i2c_imx_reset_regs (i2c_imx); +hrtimer_cancel (&i2c_imx->slave_timer); i2c_imx->slave =NULL ;/* Suspend */
Greg Kroah-Hartman
maintainerPATCH 449/609 can: c_can: c_can_chip_config(): keep controller in init mode until bittiming is configured
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lucas Martins Alves <[email protected]>
commit 26504844613fb44c7cab1c5f6fcff77861709baa upstream.
c_can_chip_config() was programming C_CAN_CTRL_REG without CONTROL_INIT, which may allow the controller to become active before c_can_set_bittiming() finishes.
That creates a short timing window where the peripheral can interact with the bus using a different/default bitrate, potentially generating bus errors and corrupting traffic.
Set CONTROL_INIT together with the control-mode writes in c_can_chip_config() (normal, loopback and listen-only paths), so the controller stays halted until bit timing is fully programmed.
This prevents transient bus disturbance during startup when the configured bitrate differs from the active bus bitrate.
--- drivers/net/can/c_can/c_can_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/can/c_can/c_can_main.c +4 -4
@@ -597,20 +597,20 @@ static int c_can_chip_config(struct net_return err;/* enable automatic retransmission */ - priv->write_reg (priv,C_CAN_CTRL_REG ,CONTROL_ENABLE_AR ); + priv->write_reg (priv,C_CAN_CTRL_REG ,CONTROL_ENABLE_AR |CONTROL_INIT );if ((priv->can.ctrlmode &CAN_CTRLMODE_LISTENONLY ) && (priv->can.ctrlmode &CAN_CTRLMODE_LOOPBACK )) {/* loopback + silent mode : useful for hot self-test */ - priv->write_reg (priv,C_CAN_CTRL_REG ,CONTROL_TEST ); + priv->write_reg (priv,C_CAN_CTRL_REG ,CONTROL_TEST |CONTROL_INIT ); priv->write_reg (priv,C_CAN_TEST_REG ,TEST_LBACK |TEST_SILENT ); }else if (priv->can.ctrlmode &CAN_CTRLMODE_LOOPBACK ) {/* loopback mode : useful for self-test function */ - priv->write_reg (priv,C_CAN_CTRL_REG ,CONTROL_TEST ); + priv->write_reg (priv,C_CAN_CTRL_REG ,CONTROL_TEST |CONTROL_INIT ); priv->write_reg (priv,C_CAN_TEST_REG ,TEST_LBACK ); }else if (priv->can.ctrlmode &CAN_CTRLMODE_LISTENONLY ) {/* silent mode : bus-monitoring mode */ - priv->write_reg (priv,C_CAN_CTRL_REG ,CONTROL_TEST ); + priv->write_reg (priv,C_CAN_CTRL_REG ,CONTROL_TEST |CONTROL_INIT ); priv->write_reg (priv,C_CAN_TEST_REG ,TEST_SILENT ); }
Greg Kroah-Hartman
maintainerPATCH 450/609 can: ems_usb: validate CPC message lengths
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit 02925f51377f2a42a6724f00549167499c9302e5 upstream.
ems_usb_read_bulk_callback() walks CPC messages packed in one USB receive buffer.
Check that each declared message fits in the URB payload. Also require the type-specific payload to cover the fields used by the CAN, state, error and overrun handlers.
--- drivers/net/can/usb/ems_usb.c | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+)
drivers/net/can/usb/ems_usb.c +43 -0
@@ -409,6 +409,40 @@ static void ems_usb_rx_err(struct ems_usnetif_rx (skb); } +static bool ems_usb_rx_msg_len_valid (struct ems_cpc_msg *msg) +{ +size_t len = msg->length; +size_t can_len; + +switch (msg->type) { +case CPC_MSG_TYPE_CAN_STATE : +return len >=sizeof (msg->msg.can_state); + +case CPC_MSG_TYPE_CAN_FRAME : +case CPC_MSG_TYPE_EXT_CAN_FRAME : +case CPC_MSG_TYPE_RTR_FRAME : +case CPC_MSG_TYPE_EXT_RTR_FRAME : +if (len <CPC_CAN_MSG_MIN_SIZE ) +return false; + +if (msg->type ==CPC_MSG_TYPE_RTR_FRAME || + msg->type ==CPC_MSG_TYPE_EXT_RTR_FRAME ) +return true; + + can_len =can_cc_dlc2len (msg->msg.can_msg.length &0xf ); +return len >=CPC_CAN_MSG_MIN_SIZE + can_len; + +case CPC_MSG_TYPE_CAN_FRAME_ERROR : +return len >=sizeof (msg->msg.error); + +case CPC_MSG_TYPE_OVERRUN : +return len >=sizeof (msg->msg.overrun); + +default : +return true; + } +} +/* * callback for bulk IN urb */
@@ -451,6 +485,15 @@ static void ems_usb_read_bulk_callback(s } msg = (struct ems_cpc_msg *)&ibuf[start]; +if (msg->length > + urb->actual_length - start -CPC_MSG_HEADER_LEN ) { +netdev_err (netdev,"format error\n" ); +break ; + } +if (!ems_usb_rx_msg_len_valid (msg)) { +netdev_err (netdev,"format error\n" ); +break ; + }switch (msg->type) {case CPC_MSG_TYPE_CAN_STATE :
Greg Kroah-Hartman
maintainerPATCH 451/609 can: etas_es58x: es58x_read_bulk_callback(): fix RX buffer leak on URB resubmit failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 7a0cf2b2497c757c3cb1286eddf2986abb0d387b upstream.
es58x_read_bulk_callback() resubmits the RX URB after processing a received packet. If the resubmit succeeds, the URB remains anchored and will be handled by the normal RX path or by teardown.
However, if usb_submit_urb() fails, the callback unanchors the URB and then returns directly. This skips the existing free_urb path, so the coherent transfer buffer allocated with usb_alloc_coherent() is not released.
Reuse the existing free_urb path after a resubmit failure so that the RX coherent buffer is freed before leaving the callback.
--- drivers/net/can/usb/etas_es58x/es58x_core.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/can/usb/etas_es58x/es58x_core.c +0 -1
@@ -1475,7 +1475,6 @@ static void es58x_read_bulk_callback(strdev_err_ratelimited (dev,"Failed resubmitting read bulk urb: %pe\n" ,ERR_PTR (ret)); -return ; free_urb: usb_free_coherent(urb->dev, urb->transfer_buffer_length,
Greg Kroah-Hartman
maintainerPATCH 452/609 can: j1939: transport: j1939_session_fresh_new(): initialize receive buffer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oleksij Rempel <[email protected]>
commit eb96c58907922546e415e545fe9a14ea63b02719 upstream.
Zero the allocated buffer in j1939_session_fresh_new() to ensure it contains no residual data.
While there is a potential performance impact if users allocate maximum sized ETP buffers, most real-world use cases are not noticeably affected since the maximum known buffer size is typically around 65K.
Message-ID: <CAPAUci5dykCLjoijqkUtFqJFesgncrD7+S6y_V=gjbFkY2Tifg@mail.gmail.com>
--- net/can/j1939/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/can/j1939/transport.c +1 -1
@@ -1562,7 +1562,7 @@ j1939_session *j1939_session_fresh_new(s }/* alloc data area */ -skb_put (skb, size); +skb_put_zero (skb, size);/* skb is recounted in j1939_session_new() */ return session; }
Greg Kroah-Hartman
maintainerPATCH 453/609 can: j1939: use netdevice_tracker for j1939_{priv,session,ecu} tracking
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <[email protected]>
commit d2fb981384b3a45f690616d550b29046e8ad16a4 upstream.
syzbot is still reporting
unregister_netdevice: waiting for vcan0 to become free. Usage count = 2
problem. A debug printk() patch in linux-next-20260508 identified that there is dev_hold()/dev_put() imbalance in j1939_priv management.
Call trace for vcan0[26] +4 at
__dev_hold include/linux/netdevice.h:4470 [inline]
netdev_hold include/linux/netdevice.h:4513 [inline]
dev_hold include/linux/netdevice.h:4536 [inline]
j1939_priv_create net/can/j1939/main.c:140 [inline]
j1939_netdev_start+0x36b/0xc10 net/can/j1939/main.c:268
j1939_sk_bind+0x853/0xb30 net/can/j1939/socket.c:506
__sys_bind_socket net/socket.c:1948 [inline]
__sys_bind+0x2e9/0x410 net/socket.c:1979Call trace for vcan0[28] -3 at
__dev_put include/linux/netdevice.h:4456 [inline]
netdev_put include/linux/netdevice.h:4523 [inline]
dev_put include/linux/netdevice.h:4548 [inline]
__j1939_priv_release net/can/j1939/main.c:166 [inline]
kref_put include/linux/kref.h:65 [inline]
j1939_priv_put+0x128/0x270 net/can/j1939/main.c:172
j1939_sk_sock_destruct+0x52/0x90 net/can/j1939/socket.c:388
__sk_destruct+0x8d/0x9d0 net/core/sock.c:2352
rcu_do_batch kernel/rcu/tree.c:2617 [inline]
rcu_core kernel/rcu/tree.c:2869 [inline]
rcu_cpu_kthread+0x99e/0x1470 kernel/rcu/tree.c:2957
smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245This refcount leak in j1939_priv might be caused by a refcount leak in j1939_{session,ecu} because j1939_{session,ecu} holds a ref on j1939_priv. For further investigation using upstream kernels, enable netdevice_tracker in j1939_{priv,session,ecu} management.
--- net/can/j1939/bus.c | 2 ++ net/can/j1939/j1939-priv.h | 3 +++ net/can/j1939/main.c | 8 ++++---- net/can/j1939/transport.c | 2 ++ 4 files changed, 11 insertions(+), 4 deletions(-)
net/can/j1939/bus.c +2 -0
@@ -20,6 +20,7 @@ static void __j1939_ecu_release(struct kstruct j1939_priv *priv = ecu->priv;list_del (&ecu->list); +netdev_put (priv->ndev, &ecu->priv_dev_tracker);kfree (ecu);j1939_priv_put (priv); }
@@ -155,6 +156,7 @@ struct j1939_ecu *j1939_ecu_create_lockeif (!ecu)return ERR_PTR (-ENOMEM );kref_init (&ecu->kref); +netdev_hold (priv->ndev, &ecu->priv_dev_tracker,gfp_any ()); ecu->addr =J1939_IDLE_ADDR ; ecu->name = name;
net/can/j1939/j1939-priv.h +3 -0
@@ -38,6 +38,7 @@ struct j1939_ecu {struct hrtimer ac_timer;struct kref kref;struct j1939_priv *priv; +netdevice_tracker priv_dev_tracker;/* count users, to help transport protocol decide for interaction */ int nusers;
@@ -60,6 +61,7 @@ struct j1939_priv {rwlock_t lock;struct net_device *ndev; +netdevice_tracker dev_tracker;/* list of 256 ecu ptrs, that cache the claimed addresses. * also protected by the above lock
@@ -229,6 +231,7 @@ enum j1939_session_state {struct j1939_session {struct j1939_priv *priv; +netdevice_tracker priv_dev_tracker;struct list_head active_session_list_entry;struct list_head sk_session_queue_entry;struct kref kref;
net/can/j1939/main.c +4 -4
@@ -137,7 +137,7 @@ static struct j1939_priv *j1939_priv_cre priv->ndev = ndev;kref_init (&priv->kref);kref_init (&priv->rx_kref); -dev_hold (ndev); +netdev_hold (ndev, &priv->dev_tracker,GFP_KERNEL );netdev_dbg (priv->ndev,"%s : 0x%p\n" , __func__, priv);
@@ -163,7 +163,7 @@ static void __j1939_priv_release(structWARN_ON_ONCE (!list_empty (&priv->ecus));WARN_ON_ONCE (!list_empty (&priv->j1939_socks)); -dev_put (ndev); +netdev_put (ndev, &priv->dev_tracker);kfree (priv); }
@@ -281,7 +281,7 @@ struct j1939_priv *j1939_netdev_start(st*/ kref_get (&priv_new->rx_kref);mutex_unlock (&j1939_netdev_lock); -dev_put (ndev); +netdev_put (ndev, &priv->dev_tracker);kfree (priv);return priv_new; }
@@ -298,7 +298,7 @@ struct j1939_priv *j1939_netdev_start(stj1939_priv_set (ndev,NULL );mutex_unlock (&j1939_netdev_lock); -dev_put (ndev); +netdev_put (ndev, &priv->dev_tracker);kfree (priv);return ERR_PTR (ret);
net/can/j1939/transport.c +2 -0
@@ -282,6 +282,7 @@ static void j1939_session_destroy(structkfree_skb (skb); }__j1939_session_drop (session); +netdev_put (session->priv->ndev, &session->priv_dev_tracker);j1939_priv_put (session->priv);kfree (session); }
@@ -1510,6 +1511,7 @@ static struct j1939_session *j1939_sessiINIT_LIST_HEAD (&session->active_session_list_entry);INIT_LIST_HEAD (&session->sk_session_queue_entry);kref_init (&session->kref); +netdev_hold (priv->ndev, &session->priv_dev_tracker,gfp_any ());j1939_priv_get (priv); session->priv = priv;
Greg Kroah-Hartman
maintainerPATCH 454/609 can: kvaser_usb: kvaser_usb_hydra_get_busparams(): fix memory leak in kvaser_usb_hydra_get_busparams()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 941eaf9a6d3b33dea49f2c0a1da7546a03b6ff71 upstream.
The memory allocated for cmd is not freed after the call to kvaser_usb_send_cmd() in both the normal and error paths. Fix that by adding a kfree() immediately after the call.
--- drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c +1 -0
@@ -1605,6 +1605,7 @@ static int kvaser_usb_hydra_get_busparamreinit_completion (&priv->get_busparams_comp); err =kvaser_usb_send_cmd (dev, cmd, cmd_len); +kfree (cmd);if (err)return err;
Greg Kroah-Hartman
maintainerPATCH 455/609 can: kvaser_usb_leaf: kvaser_usb_leaf_wait_cmd(): validate received command extents
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit 0293dd153f9dbc1ddf5dacdccc76b363bce4a8ee upstream.
The wait and bulk receive paths walk variable-length commands from a USB buffer. A nonzero command shorter than CMD_HEADER_LEN can still be dispatched, and the wait path copies a matching command into a fixed caller-owned struct kvaser_cmd using the device-provided length.
Reject nonzero commands that do not contain the fixed header or that extend beyond the current USB buffer item. In the wait path, also reject a matching command that exceeds the destination before copying it.
--- drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c +11 -2
@@ -614,13 +614,22 @@ static int kvaser_usb_leaf_wait_cmd(conscontinue ; } -if (pos + tmp->len > actual_len) { +if (tmp->len <CMD_HEADER_LEN || + tmp->len > actual_len - pos) {dev_err_ratelimited (&dev->intf->dev,"Format error\n" );break ; }if (tmp->id == id) { +if (tmp->len >sizeof (*cmd)) { +dev_err_ratelimited (&dev->intf->dev, +"Received command %u too large (%u)\n" , + tmp->id, tmp->len); + err = -EIO ; + goto end; + } +memcpy (cmd, tmp, tmp->len); goto end; }
@@ -1572,7 +1581,7 @@ static void kvaser_usb_leaf_read_bulk_cacontinue ; } -if (pos + cmd->len > len) { +if (cmd->len <CMD_HEADER_LEN || cmd->len > len - pos) {dev_err_ratelimited (&dev->intf->dev,"Format error\n" );break ; }
Greg Kroah-Hartman
maintainerPATCH 456/609 can: softing: fw_parse(): validate firmware record spans
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit 856d6cb04e5407523566b075841dcd6423757d1c upstream.
fw_parse() reads a fixed record header, a firmware-provided payload, and a trailing checksum without knowing the end of the firmware blob. A truncated record can therefore make those reads exceed the blob.
The same record also supplies addresses and lengths for writes into DPRAM. The generic loader uses wrap-prone mixed signed arithmetic for its bounds check, while the application loader does not bound the staging copy at all.
Pass the firmware end to the parser and validate the full source record. Use a signed wide offset for generic DPRAM records and validate the application staging span against the mapped DPRAM before copying.
--- drivers/net/can/softing/softing_fw.c | 46 ++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 14 deletions(-)
drivers/net/can/softing/softing_fw.c +32 -14
@@ -91,12 +91,12 @@ int softing_bootloader_command(struct soreturn ret; } -static int fw_parse (const uint8_t **pmem,uint16_t *ptype,uint32_t *paddr, -uint16_t *plen,const uint8_t **pdat) +static int fw_parse (const u8 **pmem,const u8 *limit,u16 *ptype, +u32 *paddr,u16 *plen,const u8 **pdat) {uint16_t checksum[2 ]; -const uint8_t *mem; -const uint8_t *end; +const u8 *mem; +const u8 *record_end;/* * firmware records are a binary, unaligned stream composed of:
@@ -114,14 +114,21 @@ static int fw_parse(const uint8_t **pmem* endianness & alignment. */ mem = *pmem; +/* A record needs an 8-byte prefix and a 2-byte checksum. */ +if (mem > limit || limit - mem <10 ) +return -EINVAL ; + *ptype =le16_to_cpup ((void *)&mem[0 ]); *paddr =le32_to_cpup ((void *)&mem[2 ]); *plen =le16_to_cpup ((void *)&mem[6 ]); +if (*plen > limit - mem -10 ) +return -EINVAL ; + *pdat = &mem[8 ];/* verify checksum */ - end = &mem[8 + *plen]; - checksum[0 ] =le16_to_cpup ((void *)end); -for (checksum[1 ] =0 ; mem < end; ++mem) + record_end = &mem[8 + *plen]; + checksum[0 ] =le16_to_cpup ((void *)record_end); +for (checksum[1 ] =0 ; mem < record_end; ++mem) checksum[1 ] += *mem;if (checksum[0 ] != checksum[1 ])return -EINVAL ;
@@ -139,6 +146,7 @@ int softing_load_fw(const char *file, stuint16_t type, len;uint32_t addr;uint8_t *buf =NULL , *new_buf; +s64 dpram_offset;int buflen =0 ;int8_t type_end =0 ;
@@ -153,7 +161,7 @@ int softing_load_fw(const char *file, st mem = fw->data; end = &mem[fw->size];/* look for header record */ - ret =fw_parse (&mem, &type, &addr, &len, &dat); + ret =fw_parse (&mem, end, &type, &addr, &len, &dat);if (ret <0 ) goto failed;if (type !=0xffff )
@@ -164,7 +172,7 @@ int softing_load_fw(const char *file, st }/* ok, we had a header */ while (mem < end) { - ret =fw_parse (&mem, &type, &addr, &len, &dat); + ret =fw_parse (&mem, end, &type, &addr, &len, &dat);if (ret <0 ) goto failed;if (type ==3 ) {
@@ -179,9 +187,13 @@ int softing_load_fw(const char *file, st goto failed; } -if ((addr + len + offset) > size) + dpram_offset = (s64 )addr + offset; +if (dpram_offset <0 || dpram_offset > size || + len > size - dpram_offset) { + ret = -EINVAL ; goto failed; -memcpy_toio (&dpram[addr + offset], dat, len); + } +memcpy_toio (&dpram[dpram_offset], dat, len);/* be sure to flush caches from IO space */ mb ();if (len > buflen) {
@@ -195,7 +207,7 @@ int softing_load_fw(const char *file, st buf = new_buf; }/* verify record data */ -memcpy_fromio (buf, &dpram[addr + offset], len); +memcpy_fromio (buf, &dpram[dpram_offset], len);if (memcmp (buf, dat, len)) {/* is not ok */ dev_alert (&card->pdev->dev,"DPRAM readback failed\n" );
@@ -237,7 +249,7 @@ int softing_load_app_fw(const char *file mem = fw->data; end = &mem[fw->size];/* look for header record */ - ret =fw_parse (&mem, &type, &addr, &len, &dat); + ret =fw_parse (&mem, end, &type, &addr, &len, &dat);if (ret) goto failed; ret = -EINVAL ;
@@ -253,7 +265,7 @@ int softing_load_app_fw(const char *file }/* ok, we had a header */ while (mem < end) { - ret =fw_parse (&mem, &type, &addr, &len, &dat); + ret =fw_parse (&mem, end, &type, &addr, &len, &dat);if (ret) goto failed;
@@ -279,6 +291,12 @@ int softing_load_app_fw(const char *file/* work in 16bit (target) */ sum &=0xffff ; +if (card->pdat->app.offs > card->dpram_size || + len > card->dpram_size - card->pdat->app.offs) { + ret = -EINVAL ; + goto failed; + } +memcpy_toio (&card->dpram[card->pdat->app.offs], dat, len);iowrite32 (card->pdat->app.offs + card->pdat->app.addr, &card->dpram[DPRAM_COMMAND +2 ]);
Greg Kroah-Hartman
maintainerPATCH 457/609 can: peak_usb: add bounds check for USB channel index
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Gao <[email protected]>
commit 39132f166ca8ce00ae60d8a9068e06a60943cc4b upstream.
The channel control index ctrl_idx is derived from rx->len which comes directly from a device USB payload. The mask 0x0f allows values 0-15, but the array size of usb_if->dev[] is only 2. Values 2-15 cause heap out-of-bounds read, eventually causing kernel panic in the IRQ context.
Add bounds checking for ctrl_idx before the array access in both pcan_usb_pro_handle_canmsg() and pcan_usb_pro_handle_error().
--- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
drivers/net/can/usb/peak_usb/pcan_usb_pro.c +16 -4
@@ -520,12 +520,18 @@ static int pcan_usb_pro_handle_canmsg(st struct pcan_usb_pro_rxmsg *rx) {const unsigned int ctrl_idx = (rx->len >>4 ) &0x0f ; -struct peak_usb_device *dev = usb_if->dev[ctrl_idx]; -struct net_device *netdev = dev->netdev; +struct peak_usb_device *dev; +struct net_device *netdev;struct can_frame *can_frame;struct sk_buff *skb;struct skb_shared_hwtstamps *hwts; +if (ctrl_idx >=ARRAY_SIZE (usb_if->dev)) +return -EINVAL ; + + dev = usb_if->dev[ctrl_idx]; + netdev = dev->netdev; + skb =alloc_can_skb (netdev, &can_frame);if (!skb)return -ENOMEM ;
@@ -559,14 +565,20 @@ static int pcan_usb_pro_handle_error(str {const u16 raw_status =le16_to_cpu (er->status);const unsigned int ctrl_idx = (er->channel >>4 ) &0x0f ; -struct peak_usb_device *dev = usb_if->dev[ctrl_idx]; -struct net_device *netdev = dev->netdev; +struct peak_usb_device *dev; +struct net_device *netdev;struct can_frame *can_frame;enum can_state new_state =CAN_STATE_ERROR_ACTIVE ;u8 err_mask =0 ;struct sk_buff *skb;struct skb_shared_hwtstamps *hwts; +if (ctrl_idx >=ARRAY_SIZE (usb_if->dev)) +return -EINVAL ; + + dev = usb_if->dev[ctrl_idx]; + netdev = dev->netdev; +/* nothing should be sent while in BUS_OFF state */ if (dev->can.state ==CAN_STATE_BUS_OFF )return 0 ;
Greg Kroah-Hartman
maintainerPATCH 458/609 can: peak_usb: peak_usb_start(): fix double free of transfer buffer on URB submit error
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
commit 9b3d5a6d952c38bbcf07f903cbeadefdb56b9bc9 upstream.
In peak_usb_start(), each RX URB transfer buffer is allocated with kmalloc() and the URB is flagged URB_FREE_BUFFER so that the final usb_free_urb() also frees the transfer buffer.
If usb_submit_urb() fails, the error path frees the buffer explicitly with kfree(buf) and then calls usb_free_urb(urb). Because URB_FREE_BUFFER is set, usb_free_urb() -> urb_destroy() frees the same buffer a second time, a double free of the transfer buffer.
BUG: KASAN: double-free in usb_free_urb.part.0+0x91/0xb0 Free of addr ffff8881069ccb80 by task trigger.sh/285 Call Trace: kfree+0x113/0x3c0 usb_free_urb.part.0+0x91/0xb0
Drop the redundant kfree(buf); usb_free_urb() already releases the transfer buffer. This mirrors commit 03819abbeb11 ("net: usb: lan78xx: Fix double free issue with interrupt buffer allocation").
--- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/can/usb/peak_usb/pcan_usb_core.c +0 -1
@@ -461,7 +461,6 @@ static int peak_usb_start(struct peak_usnetif_device_detach (dev->netdev);usb_unanchor_urb (urb); -kfree (buf);usb_free_urb (urb);break ; }
Greg Kroah-Hartman
maintainerPATCH 459/609 can: peak_usb: validate uCAN receive record lengths
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit 93fcab2c6968446316bbb49548848df604d6346f upstream.
pcan_usb_fd_decode_buf() walks uCAN records packed in one USB receive buffer.
Require each record to contain the fixed header for its type, and verify CAN payload bytes before copying them into the skb.
--- drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 40 ++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-)
drivers/net/can/usb/peak_usb/pcan_usb_fd.c +39 -1
@@ -519,6 +519,13 @@ static int pcan_usb_fd_decode_canmsg(str dev->can.ctrlmode); } +if (!(rx_msg_flags &PUCAN_MSG_RTR ) && +le16_to_cpu (rx_msg->size) - offsetof(struct pucan_rx_msg , d) < + cfd->len) { +kfree_skb (skb); +return -EBADMSG ; + } + cfd->can_id =le32_to_cpu (rm->can_id);if (rx_msg_flags &PUCAN_MSG_EXT_ID )
@@ -667,6 +674,24 @@ static void pcan_usb_fd_decode_ts(structpeak_usb_set_ts_now (&usb_if->time_ref,le32_to_cpu (ts->ts_low)); } +static size_t pcan_usb_fd_rx_msg_min_size (u16 rx_msg_type) +{ +switch (rx_msg_type) { +case PUCAN_MSG_CAN_RX : +return offsetof(struct pucan_rx_msg , d); +case PCAN_UFD_MSG_CALIBRATION : +return sizeof (struct pcan_ufd_ts_msg ); +case PUCAN_MSG_ERROR : +return sizeof (struct pucan_error_msg ); +case PUCAN_MSG_STATUS : +return sizeof (struct pucan_status_msg ); +case PCAN_UFD_MSG_OVERRUN : +return sizeof (struct pcan_ufd_ovr_msg ); +default : +return sizeof (struct pucan_msg ); + } +} +/* callback for bulk IN urb */ static int pcan_usb_fd_decode_buf (struct peak_usb_device *dev,struct urb *urb) {
@@ -681,6 +706,12 @@ static int pcan_usb_fd_decode_buf(struct msg_end = urb->transfer_buffer + urb->actual_length;for (; msg_ptr < msg_end;) {u16 rx_msg_type, rx_msg_size; +size_t rx_msg_min_size; + +if (msg_end - msg_ptr <sizeof (*rx_msg)) { + err = -EBADMSG ; +break ; + } rx_msg = (struct pucan_msg *)msg_ptr;if (!rx_msg->size) {
@@ -692,12 +723,19 @@ static int pcan_usb_fd_decode_buf(struct rx_msg_type =le16_to_cpu (rx_msg->type);/* check if the record goes out of current packet */ -if (msg_ptr + rx_msg_size > msg_end) { +if (rx_msg_size > msg_end - msg_ptr) {netdev_err (netdev,"got frag rec: should inc usb rx buf sze\n" ); err = -EBADMSG ;break ; } + + rx_msg_min_size =pcan_usb_fd_rx_msg_min_size (rx_msg_type); +if (rx_msg_size < rx_msg_min_size) { +netdev_err (netdev,"got short rec\n" ); + err = -EBADMSG ; +break ; + }switch (rx_msg_type) {case PUCAN_MSG_CAN_RX :
Greg Kroah-Hartman
maintainerPATCH 460/609 can: ctucanfd: add missing MODULE_DEVICE_TABLE()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit d937bdb244a751fe5967052ea2d64a7b2c476cc0 upstream.
The driver has a match table for the pci bus wired into its driver structure, but the table is not exported with MODULE_DEVICE_TABLE().
Add the missing MODULE_DEVICE_TABLE() entry so module alias information is generated for automatic module loading.
This is a source-level fix. It does not claim dynamic hardware reproduction; the evidence is the driver-owned match table, its use by the driver registration structure, and the missing module alias publication.
--- drivers/net/can/ctucanfd/ctucanfd_pci.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/can/ctucanfd/ctucanfd_pci.c +1 -0
@@ -278,6 +278,7 @@ static const struct pci_device_id ctucan CTUCAN_WITH_CTUCAN_ID)}, {}, }; +MODULE_DEVICE_TABLE (pci, ctucan_pci_tbl);static struct pci_driver ctucan_pci_driver = { .name =KBUILD_MODNAME ,
Greg Kroah-Hartman
maintainerPATCH 461/609 can: ctucanfd: use self-test mode for PRESUME_ACK
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Avi Weiss <[email protected]>
commit c31a435933f18be0f874302161333e9f16e200a0 upstream.
Use self-test mode for CAN_CTRLMODE_PRESUME_ACK so transmitted frames can complete without receiving an ACK.
ACK forbidden mode prevents the controller from acknowledging received frames and does not implement the presume-ack behavior.
--- drivers/net/can/ctucanfd/ctucanfd_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/can/ctucanfd/ctucanfd_base.c +2 -2
@@ -340,8 +340,8 @@ static void ctucan_set_mode(struct ctuca (mode_reg & ~REG_MODE_FDE ); mode_reg = (mode->flags &CAN_CTRLMODE_PRESUME_ACK ) ? - (mode_reg |REG_MODE_ACF ) : - (mode_reg & ~REG_MODE_ACF ); + (mode_reg |REG_MODE_STM ) : + (mode_reg & ~REG_MODE_STM ); mode_reg = (mode->flags &CAN_CTRLMODE_FD_NON_ISO ) ? (mode_reg | REG_MODE_NISOFD) :
Greg Kroah-Hartman
maintainerPATCH 462/609 can: ctucanfd: unmap BAR0 using base address
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Avi Weiss <[email protected]>
commit a6873910f983096746d1a2e0af94f36b8003e839 upstream.
BAR0 is mapped into bar0_base, while cra_addr points to an offset within that mapping and is used for other purposes.
Pass bar0_base to pci_iounmap(), instead of cra_addr, on the probe error path so the address returned by pci_iomap() is used for unmapping.
--- drivers/net/can/ctucanfd/ctucanfd_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/can/ctucanfd/ctucanfd_pci.c +1 -1
@@ -202,7 +202,7 @@ err_free_board:pci_set_drvdata (pdev,NULL );kfree (bdata); err_pci_iounmap_bar0: -pci_iounmap (pdev, cra_addr); +pci_iounmap (pdev, bar0_base); err_pci_iounmap_bar1:pci_iounmap (pdev, addr); err_release_regions:
Greg Kroah-Hartman
maintainerPATCH 463/609 can: ctucanfd: handle bus error interrupts
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Avi Weiss <[email protected]>
commit e74bae899529f49c0f375307983d12e8ecad7d4b upstream.
Include REG_INT_STAT_BEI in the top-level error interrupt condition.
BEI is enabled when CAN_CTRLMODE_BERR_REPORTING is requested and ctucan_err_interrupt() already handles it. Without checking and clearing BEI in the top-level handler, bus error interrupts are not handled or acknowledged.
--- drivers/net/can/ctucanfd/ctucanfd_base.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/can/ctucanfd/ctucanfd_base.c +6 -2
@@ -1135,8 +1135,12 @@ static irqreturn_t ctucan_interrupt(int/* Error interrupts */ if (FIELD_GET (REG_INT_STAT_EWLI , isr) ||FIELD_GET (REG_INT_STAT_FCSI , isr) || -FIELD_GET (REG_INT_STAT_ALI , isr)) { - icr = isr & (REG_INT_STAT_EWLI |REG_INT_STAT_FCSI |REG_INT_STAT_ALI ); +FIELD_GET (REG_INT_STAT_ALI , isr) || +FIELD_GET (REG_INT_STAT_BEI , isr)) { + icr = isr & (REG_INT_STAT_EWLI | +REG_INT_STAT_FCSI | +REG_INT_STAT_ALI | +REG_INT_STAT_BEI );ctucan_netdev_dbg (ndev,"some ERR interrupt: clearing 0x%08x\n" , icr);ctucan_write32 (priv,CTUCANFD_INT_STAT , icr);
Greg Kroah-Hartman
maintainerPATCH 464/609 can: ctucanfd: mark error-active controller status valid
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Avi Weiss <[email protected]>
commit 4e735cbe3affe88001428fdd9cae8e685ce92f21 upstream.
In the CAN_STATE_ERROR_ACTIVE case, cf->data[1] is set to CAN_ERR_CRTL_ACTIVE, but cf->can_id is not set with CAN_ERR_CRTL in that path.
Set CAN_ERR_CRTL so consumers know the controller-status information in cf->data[1] is valid.
--- drivers/net/can/ctucanfd/ctucanfd_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/can/ctucanfd/ctucanfd_base.c +1 -1
@@ -868,7 +868,7 @@ static void ctucan_err_interrupt(structbreak ;case CAN_STATE_ERROR_ACTIVE :if (skb) { - cf->can_id |=CAN_ERR_CNT ; + cf->can_id |=CAN_ERR_CRTL |CAN_ERR_CNT ; cf->data[1 ] =CAN_ERR_CRTL_ACTIVE ; cf->data[6 ] = bec.txerr; cf->data[7 ] = bec.rxerr;
Greg Kroah-Hartman
maintainerPATCH 465/609 drm/dp: Read the PCON max FRL bandwidth only for HDMI DFPs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Kaplan <[email protected]>
commit e40e20ac089e32f1d910636155dc82e61e61dcf3 upstream.
The PCON max FRL bandwidth field lives in byte 2 of the DFP Detailed Capability Info (DPCD 0x82 for the first DFP).
The DP standard defines the meaning of descriptor bytes 1-3 strictly per DFP type, and for a DisplayPort type DFP all of them are reserved, with "read all 0s" semantics (DP v2.0, section 2.12.3, Table 2-183).
The FRL bandwidth field is an HDMI DFP extension added by the VESA DP-to-HDMI PCON specification. drm_dp_get_pcon_max_frl_bw() however parses the byte without checking the DFP type, the branch presence or DETAILED_CAP_INFO_AVAILABLE. Without the latter the port descriptors are one byte wide and port_cap[2] is not even the right register.
All neighbouring helpers parsing the same descriptor are scoped by the DFP type already, see for instance drm_dp_downstream_max_bpc() reading the same byte and returning 0 for a DP type DFP. amdgpu's DC parses the field only for HDMI(/DP++) detailed types as well.
This is not theoretical.
A Synaptics VMM7100 based USB-C to HDMI adapter with a macOS targeted firmware advertises a DisplayPort type DFP with the type byte replicated across the whole descriptor (08 08 08 08).
i915 decodes that as "PCON limited to 18 Gbps FRL" and prunes every mode above ~750 MHz dotclock, including all the 4k@100/120 modes the sink EDID offers, while macOS drives 4k@120 through the same adapter just fine via DP DSC (and amdgpu's type-scoped parser would ignore the bogus field as well).
Only parse the field for an HDMI DFP behind a DPCD 1.1+ branch device that reports detailed cap info, matching the type-scoped field layout of the spec and the rest of the helpers.
--- drivers/gpu/drm/display/drm_dp_helper.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/gpu/drm/display/drm_dp_helper.c +12 -0
@@ -2930,6 +2930,18 @@ int drm_dp_get_pcon_max_frl_bw(const u8int bw;u8 buf; +if (!drm_dp_is_branch (dpcd)) +return 0 ; + +if (dpcd[DP_DPCD_REV ] <0x11 ) +return 0 ; + +if ((dpcd[DP_DOWNSTREAMPORT_PRESENT ] &DP_DETAILED_CAP_INFO_AVAILABLE ) ==0 ) +return 0 ; + +if ((port_cap[0 ] &DP_DS_PORT_TYPE_MASK ) !=DP_DS_PORT_TYPE_HDMI ) +return 0 ; + buf = port_cap[2 ]; bw = buf &DP_PCON_MAX_FRL_BW ;
Greg Kroah-Hartman
maintainerPATCH 466/609 drm/vc4: Supply the overflow slot size in BPOS, not the whole bin BO size
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jose Maria Casanova Crespo <[email protected]>
commit 6395789e4739aa5177bbec0fa0f07ccc38d249b0 upstream.
vc4_overflow_mem_work() points BPOA at a 512KB slot inside the 16MB binner BO, but writes the size of the whole BO to BPOS. On every binner out-of-memory event the PTB is therefore authorized to write tile lists across all the other slots (which may hold the tile state, tile alloc and overflow memory of in-flight jobs) and, for any slot but the first, past the end of the binner BO into unrelated CMA memory.
Since CMA pages are recycled into page cache and user allocations, this is arbitrary memory corruption by GPU DMA. In practice it shows up as GPU hangs with corrupted control list pointers, userspace heap corruption, a GPU that stays permanently wedged after the first hang, and occasional full system crashes, whenever a job overflows the initial binner slot.
The bug dates back to the conversion from a dedicated overflow BO (where writing the full BO size was correct) to the slotted binner BO.
--- drivers/gpu/drm/vc4/vc4_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/vc4/vc4_irq.c +1 -1
@@ -106,7 +106,7 @@ vc4_overflow_mem_work(struct work_struct vc4->bin_alloc_overflow =BIT (bin_bo_slot);V3D_WRITE (V3D_BPOA , bo->base.dma_addr + bin_bo_slot * vc4->bin_alloc_size); -V3D_WRITE (V3D_BPOS , bo->base.base.size); +V3D_WRITE (V3D_BPOS , vc4->bin_alloc_size);V3D_WRITE (V3D_INTCTL ,V3D_INT_OUTOMEM );V3D_WRITE (V3D_INTENA ,V3D_INT_OUTOMEM );spin_unlock_irqrestore (&vc4->job_lock, irqflags);
Greg Kroah-Hartman
maintainerPATCH 467/609 drm/vc4: Zero the tile state data array before each BIN job
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maíra Canal <[email protected]>
commit 48a570c964d8e37d353381e4195106277e17f5cb upstream.
The binner BO is a single 16MB buffer split into 512KB slots that are handed out to jobs at submission time and recycled as jobs complete, without ever being cleared. Each slot holds the job's Tile State Data Array (TSDA) at its start, followed by the tile allocation pool.
While the tile allocation pool is only walked by the render thread through branches the binner generated during the current job, the TSDA is the PTB's own per-tile bookkeeping and is consumed by the hardware itself. Although the kernel sets the "Auto-initialise Tile State Data Array" flag in the tile binning mode configuration, the PTB demonstrably still acts on stale tile state left by the slot's previous user: the binner ends up creating invalid command streams with invalid primitive streams and branches, which can cause GPU hangs as observed in [1][2].
Zero the TSDA when the job's binning slot is configured. This clears 48 bytes per tile (~24KB for a 1080p frame) in the submission path, and guarantees the PTB never sees another job's tile state.
The tile count is only checked for being non-zero today, so the 8-bit fields it comes from can describe a tile state array almost six times larger than the slot it has to live in. Bound it before the slot is handed out, since such size decides how much of the slot is left for the tile alloc pool.
--- drivers/gpu/drm/vc4/vc4_validate.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-)
drivers/gpu/drm/vc4/vc4_validate.c +23 -6
@@ -387,6 +387,23 @@ validate_tile_binning_config(VALIDATE_ARreturn -EINVAL ; } +/* The tile state data array is 48 bytes per tile, and we put it at +* the start of a BO containing both it and the tile alloc. +*/ + tile_state_size =48 * tile_count; + +/* Since the tile alloc array will follow us, align. */ + tile_state_size =roundup (tile_state_size,4096 ); + +/* Reject configurations whose tile state would leave no room for +* the tile alloc pool that follows it in the slot. +*/ +if (tile_state_size >= vc4->bin_alloc_size) { +DRM_DEBUG ("Tile binning config of %dx%d too large\n" , + exec->bin_tiles_x, exec->bin_tiles_y); +return -EINVAL ; + } + bin_slot =vc4_v3d_get_bin_slot (vc4);if (bin_slot <0 ) {if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS ) {
@@ -402,13 +419,13 @@ validate_tile_binning_config(VALIDATE_AR exec->bin_slots |=BIT (bin_slot); bin_addr = vc4->bin_bo->base.dma_addr + bin_slot * vc4->bin_alloc_size; -/* The tile state data array is 48 bytes per tile, and we put it at -* the start of a BO containing both it and the tile alloc. -*/ - tile_state_size =48 * tile_count; + exec->tile_alloc_offset = bin_addr + tile_state_size; -/* Since the tile alloc array will follow us, align. */ - exec->tile_alloc_offset = bin_addr +roundup (tile_state_size,4096 ); +/* The TSDA area must be zeroed out before use, otherwise the PTB might +* consume a stale tile state. +*/ +memset (vc4->bin_bo->base.vaddr + bin_slot * vc4->bin_alloc_size,0 , + tile_state_size); *(uint8_t *)(validated + 14) = ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK |
Greg Kroah-Hartman
maintainerPATCH 468/609 drm/amdgpu: restore UMD profile pstate after runtime resume
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Candice Li <[email protected]>
commit f931c54b241ce2f36bfc34955aec43a188276b8d upstream.
Runtime suspend runs GFX hw_fini and clears perfmon clock gating while the UMD profile DPM level remains set in software. Re-apply stable pstate after a successful runtime resume when a profile mode is active.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +15 -0
@@ -2637,6 +2637,19 @@ static int amdgpu_pmops_runtime_suspend(return 0 ; } +static void amdgpu_restore_umd_profile_pstate_after_runpm (struct amdgpu_device *adev) +{ +enum amd_dpm_forced_level level; +uint32_t profile_mode_mask =AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD | +AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK | +AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK | +AMD_DPM_FORCED_LEVEL_PROFILE_PEAK ; + + level =amdgpu_dpm_get_performance_level (adev); +if (level & profile_mode_mask) +amdgpu_asic_update_umd_stable_pstate (adev, true); +} +static int amdgpu_pmops_runtime_resume (struct device *dev) {struct pci_dev *pdev =to_pci_dev (dev);
@@ -2680,6 +2693,8 @@ static int amdgpu_pmops_runtime_resume(sif (amdgpu_device_supports_px (drm_dev)) drm_dev->switch_power_state =DRM_SWITCH_POWER_ON ; + +amdgpu_restore_umd_profile_pstate_after_runpm (adev); adev->in_runpm = false;return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 469/609 drm/amdgpu: cap GTT size to physical RAM on APUs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harkirat Gill <[email protected]>
commit 5e70f6804b4d6256058c360b10e044ee04ea4a4e upstream.
On APUs, the GTT pool is backed by system RAM, but its size is not bound to the non-carveout memory that actually backs it. A user can end up with GTT + VRAM exceeding total physical memory through the following sequence:
- Have a large non-carveout memory space (~128GB) and accordingly set a large GTT (~100GB) via the ttm module parameter.
- Lower the non-carveout memory space in BIOS by increasing the UMA Frame Buffer Size (VRAM) to 64GB.
- The previously set GTT value (~100GB) persists, even though the new non-carveout space (64GB) can no longer back it.
This leads to a case where kernel reports GTT (100GB) + VRAM (64GB) despite the sum being greater than total physical memory (128GB).
Cap the GTT size to totalram_pages() on APUs. totalram_pages() already excludes the VRAM carveout, so the resulting GTT can never exceed the system RAM that actually backs it.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +12 -0
@@ -1862,6 +1862,18 @@ int amdgpu_ttm_init(struct amdgpu_device gtt_size = (uint64_t )amdgpu_gtt_size <<20 ; } +/* Cap GTT so that it does not exceed total physical RAM. */ +if (adev->flags &AMD_IS_APU ) { +u64 phys_ram = (u64 )totalram_pages () <<PAGE_SHIFT ; + +if (gtt_size > phys_ram) { + gtt_size = phys_ram; +dev_info (adev->dev, +"Capping GTT to %uM to not exceed available system memory\n" , + (unsigned int )(gtt_size / (1024 *1024 ))); + } + } +/* Initialize GTT memory pool */ r =amdgpu_gtt_mgr_init (adev, gtt_size);if (r) {
Greg Kroah-Hartman
maintainerPATCH 470/609 drm/amdkfd: Handle invalid event type in CRIU event restore
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Francis <[email protected]>
commit a9cdc85839e4fe2c760aa4ca6cc341c31ad1918a upstream.
In kfd_criu_restore_event, there was no handling for the event priv data having an invalid event type. The priv data here is untrusted and can be invalid.
In that case, fail with EINVAL.
--- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/amd/amdkfd/kfd_events.c +3 -0
@@ -519,6 +519,9 @@ int kfd_criu_restore_event(struct file * ret =create_other_event (p, ev, &ev_priv->event_id);break ; +default : + ret = -EINVAL ; +break ; }mutex_unlock (&p->event_mutex);
Greg Kroah-Hartman
maintainerPATCH 471/609 drm/amdkfd: hold event_mutex while checkpointing CRIU events
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: William Palacek <[email protected]>
commit ff8bc5a68a9a70bdc38d61a72c7a49c56063f9d2 upstream.
kfd_criu_checkpoint_events() counts the entries in p->event_idr via kfd_get_num_events(), allocates an array sized to that count, and then walks the same IDR to fill it. Neither the count nor the walk holds p->event_mutex.
The CRIU checkpoint caller holds only p->mutex. Event create and destroy (kfd_event_create()/kfd_event_destroy()) take p->event_mutex and do not take p->mutex, so a second thread in the same process can insert or remove events between the count and the walk. If an event is inserted, the walk iterates more entries than were counted and writes past the end of the ev_privs allocation; if an event is removed, the walk dereferences an entry that is being freed.
Hold p->event_mutex across the count and the walk so both observe a consistent view of p->event_idr. The lock is released before copy_to_user(), which only touches the local buffer. The caller already holds p->mutex and the create/destroy paths never take p->mutex, so the p->mutex -> p->event_mutex order is not inverted and no deadlock is introduced.
--- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_events.c +18 -4
@@ -543,15 +543,27 @@ int kfd_criu_checkpoint_events(struct kfint ret =0 ;struct kfd_event *ev;uint32_t ev_id; +uint32_t num_events; -uint32_t num_events =kfd_get_num_events (p); - -if (!num_events) +/* Serialize the count and the walk below against concurrent event +* create/destroy. Those paths take only p->event_mutex, not the +* p->mutex held by the CRIU checkpoint caller, so without this the +* event_idr can grow between kfd_get_num_events() and the loop and the +* walk writes past the ev_privs allocation. +*/ +mutex_lock (&p->event_mutex); + + num_events =kfd_get_num_events (p); +if (!num_events) { +mutex_unlock (&p->event_mutex);return 0 ; + } ev_privs =kvzalloc (num_events *sizeof (*ev_privs),GFP_KERNEL ); -if (!ev_privs) +if (!ev_privs) { +mutex_unlock (&p->event_mutex);return -ENOMEM ; + }idr_for_each_entry (&p->event_idr, ev, ev_id) {
@@ -592,6 +604,8 @@ int kfd_criu_checkpoint_events(struct kf i++; } +mutex_unlock (&p->event_mutex); + ret =copy_to_user (user_priv_data + *priv_data_offset, ev_privs, num_events *sizeof (*ev_privs));if (ret) {
Greg Kroah-Hartman
maintainerPATCH 472/609 drm/vmwgfx: drop dma_buf reference on foreign-fd prime import
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zack Rusin <[email protected]>
commit f739416dc555fa205a785e5135d73fa39b26f35d upstream.
ttm_prime_fd_to_handle() returns -ENOSYS when the imported fd's dma_buf->ops do not match the ttm_object_device's ops, but does so without releasing the reference acquired by dma_buf_get(). Any unprivileged renderD client passing a non-vmwgfx prime fd through the DRM_VMW_GB_SURFACE_REF{,_EXT} path leaks one dma_buf reference per call and indefinitely pins the foreign exporter's GEM resources.
Funnel the error path through the existing dma_buf_put() so the reference is always dropped.
--- drivers/gpu/drm/vmwgfx/ttm_object.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/vmwgfx/ttm_object.c +5 -2
@@ -551,14 +551,17 @@ int ttm_prime_fd_to_handle(struct ttm_obif (IS_ERR (dma_buf))return PTR_ERR (dma_buf); -if (dma_buf->ops != &tdev->ops) -return -ENOSYS ; +if (dma_buf->ops != &tdev->ops) { + ret = -ENOSYS ; + goto out; + } prime = (struct ttm_prime_object *) dma_buf->priv; base = &prime->base; *handle = base->handle; ret =ttm_ref_object_add (tfile, base,NULL , false); +out:dma_buf_put (dma_buf);return ret;
Greg Kroah-Hartman
maintainerPATCH 473/609 drm/vmwgfx: validate DRAW_PRIMITIVES header size before division
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zack Rusin <[email protected]>
commit 85891d174707d8bddcec7a888fb4e1d17def34f3 upstream.
vmw_cmd_draw() computes
maxnum = (header->size - sizeof(cmd->body)) / sizeof(*decl);
where header->size is u32 and is taken straight from the user-supplied command stream. When header->size is less than sizeof(cmd->body) the unsigned subtraction wraps to nearly 4 GiB, producing a huge maxnum. Any user-controlled cmd->body.numVertexDecls then passes the bound and the loop dereferences decl[i] far past the end of the kernel command bounce buffer, producing an out-of-bounds read of kernel memory.
Reject undersized headers up front.
--- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +7 -1
@@ -1577,11 +1577,17 @@ static int vmw_cmd_draw(struct vmw_privauint32_t maxnum;int ret; + cmd =container_of (header,typeof (*cmd), header); + +if (unlikely (header->size <sizeof (cmd->body))) { +VMW_DEBUG_USER ("Illegal DRAW_PRIMITIVES header size.\n" ); +return -EINVAL ; + } + ret =vmw_cmd_cid_check (dev_priv, sw_context, header);if (unlikely (ret !=0 ))return ret; - cmd =container_of (header,typeof (*cmd), header); maxnum = (header->size -sizeof (cmd->body)) /sizeof (*decl);if (unlikely (cmd->body.numVertexDecls > maxnum)) {
Greg Kroah-Hartman
maintainerPATCH 474/609 drm/vmwgfx: bound DMA command body size against suffix pointer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zack Rusin <[email protected]>
commit f4f1db96bfd68b81053693ba53405b6f510ac16c upstream.
vmw_cmd_dma() locates the DMA suffix at
(unsigned long) &cmd->body + header->size - sizeof(*suffix)
without checking that header->size is large enough to contain both cmd->body and the suffix. An undersized header makes the suffix pointer underflow back into the previous command in the bounce buffer. The verifier later writes suffix->maximumOffset, clobbering verified fields of an already-relocated earlier command -- a TOCTOU on the device-visible command stream that lets one command rewrite another's GMR id, surface id, or other authenticated fields.
Reject the command if the body is too small for the suffix to fit.
--- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +6 -0
@@ -1516,6 +1516,12 @@ static int vmw_cmd_dma(struct vmw_privatbool dirty; cmd =container_of (header,typeof (*cmd), header); + +if (unlikely (header->size <sizeof (cmd->body) +sizeof (*suffix))) { +VMW_DEBUG_USER ("Illegal SVGA_3D_CMD_SURFACE_DMA size.\n" ); +return -EINVAL ; + } + suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long ) &cmd->body + header->size -sizeof (*suffix));
Greg Kroah-Hartman
maintainerPATCH 475/609 HID: logitech-dj: Fix maxfield check in DJ short report validation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
commit 590cc4d782487632a52f37c2171bee1eeea29627 upstream.
Commit b6a57912854e ("HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write") added validation for the DJ short output report, but the error path dereferences rep->field[0] even when rep->maxfield is zero.
Commit 8b9a097eb2fc ("HID: logitech-dj: fix wrong detection of bad DJ_SHORT output report") made the check conditional on rep being present, but a crafted descriptor can still create report ID 0x20 with only padding output items. hid-core registers the report, ignores the padding field, and leaves rep->maxfield as zero.
In that case the validation enters the rep->maxfield < 1 branch and then dereferences rep->field[0]->report_count while printing the error message, causing a NULL pointer dereference during probe. This is reproducible with uhid by emulating a Logitech receiver with a padding-only DJ short output report:
BUG: KASAN: null-ptr-deref in logi_dj_probe+0xb1/0x754 [hid_logitech_dj] Read of size 4 at addr 0000000000000028 by task kworker/4:1/129 ... Call Trace: logi_dj_probe+0xb1/0x754 [hid_logitech_dj] hid_device_probe+0x329/0x3f0 [hid] really_probe+0x162/0x570 __device_attach+0x137/0x2c0 bus_probe_device+0x38/0xc0 device_add+0xa56/0xce0 hid_add_device+0x19c/0x280 [hid] uhid_device_add_worker+0x2c/0xb0 [uhid]
Reject the zero-field report before printing the field report_count.
--- drivers/hid/hid-logitech-dj.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/hid/hid-logitech-dj.c +7 -2
@@ -1797,8 +1797,13 @@ static int logi_dj_probe(struct hid_devi output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT ]; rep = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT ]; -if (rep && (rep->maxfield <1 || - rep->field[0 ]->report_count !=DJREPORT_SHORT_LENGTH -1 )) { +if (rep && rep->maxfield <1 ) { +hid_err (hdev,"Expected size of DJ short report is %d, but got 0" , +DJREPORT_SHORT_LENGTH -1 ); +return -EINVAL ; + } + +if (rep && rep->field[0 ]->report_count !=DJREPORT_SHORT_LENGTH -1 ) {hid_err (hdev,"Expected size of DJ short report is %d, but got %d" ,DJREPORT_SHORT_LENGTH -1 , rep->field[0 ]->report_count);return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 476/609 ata: libahci_platform: Do not set mask_port_map when not needed
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Damien Le Moal <[email protected]>
commit 2c202e6c4f4dd19d2e8c1dfac9df05170aa3934f upstream.
Commit 8c87215dd3a2 ("ata: libahci_platform: support non-consecutive port numbers") modified ahci_platform_get_resources() to allow identifying the ports of a controller that are defined as child nodes of the controller node in order to support non-consecutive port numbers (as defined by the platform device tree).
However, this commit also erroneously sets bit 0 of hpriv->mask_port_map when the platform devices tree does not define port child nodes, to match the fact that the temporary default number of ports used in that case is 1 (which is also consistent with the fact that only index 0 of hpriv->phys[] is initialized with the call to ahci_platform_get_phy(). But doing so causes ahci_platform_init_host() to initialize and probe only the first port, even if this function determines that the controller has in fact multiple ports using the capability register of the controller (through a call to ahci_nr_ports()). This can be seen with the ahci_mvebu driver (Armada 385 SoC) with the second port declared as "dummy":
ahci-mvebu f10a8000.sata: masking port_map 0x3 -> 0x1
ahci-mvebu f10a8000.sata: AHCI vers 0001.0000, 32 command slots, 6 Gbps, platform mode ahci-mvebu f10a8000.sata: 1/2 ports implemented (port mask 0x1) ahci-mvebu f10a8000.sata: flags: 64bit ncq sntf led only pmp fbs pio slum part sxs scsi host0: ahci-mvebu
scsi host1: ahci-mvebu
ata1: SATA max UDMA/133 mmio [mem 0xf10a8000-0xf10a9fff] port 0x100 irq 40 lpm-pol 0
ata2: DUMMY
Fix this issue by removing setting bit 0 of hpriv->mask_port_map when the platform device tree does not define port child nodes.
--- drivers/ata/libahci_platform.c | 2 -- 1 file changed, 2 deletions(-)
drivers/ata/libahci_platform.c +0 -2
@@ -659,8 +659,6 @@ struct ahci_host_priv *ahci_platform_get* If no sub-node was found, keep this for device tree * compatibility */ - hpriv->mask_port_map |=BIT (0 ); - rc =ahci_platform_get_phy (hpriv,0 , dev, dev->of_node);if (rc) goto err_out;
Greg Kroah-Hartman
maintainerPATCH 477/609 ata: ahci: Make ahci_ignore_port() handle empty mask_port_map
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Niklas Cassel <[email protected]>
commit 130ff5c8b78e6fd05270a04985c50bce6a3de6c1 upstream.
Commit 8c87215dd3a2 ("ata: libahci_platform: support non-consecutive port numbers") added a skip to ahci_platform_enable_phys() for ports that are not in mask_port_map.
The code in ahci_platform_get_resources(), will currently set mask_port_map for each child "port" node it finds in the device tree.
However, device trees that do not have any child "port" nodes will not have mask_port_map set, and for non-device tree platforms mask_port_map will only exist as a quirk for specific PCI device + vendor IDs, or as a kernel module parameter, but will not be set by default.
Therefore, the common thing is that mask_port_map is only set if you do not want to use all ports (as defined by Offset 0Ch: PI – Ports Implemented register), but instead only want to use the ports in mask_port_map. If mask_port_map is not set, all ports are available.
Thus, ahci_ignore_port() must be able to handle an empty mask_port_map.
--- drivers/ata/ahci.h | 8 ++++++-- drivers/ata/libahci.c | 1 + 2 files changed, 7 insertions(+), 2 deletions(-)
drivers/ata/ahci.h +6 -2
@@ -388,8 +388,12 @@ struct ahci_host_priv {static inline bool ahci_ignore_port (struct ahci_host_priv *hpriv,unsigned int portid) { -return portid >= hpriv->nports || - !(hpriv->mask_port_map & (1 << portid)); +if (portid >= hpriv->nports) +return true; +/* mask_port_map not set means that all ports are available */ +if (!hpriv->mask_port_map) +return false; +return !(hpriv->mask_port_map & (1 << portid)); }extern int ahci_ignore_sss;
drivers/ata/libahci.c +1 -0
@@ -539,6 +539,7 @@ void ahci_save_initial_config(struct dev hpriv->saved_port_map = port_map; } +/* mask_port_map not set means that all ports are available */ if (hpriv->mask_port_map) { dev_warn(dev, "masking port_map 0x%lx -> 0x%lx\n", port_map,
Greg Kroah-Hartman
maintainerPATCH 478/609 mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiryl Shutsemau (Meta) <[email protected]>
[ Upstream commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23 ]
copy_hugetlb_page_range() clears the uffd-wp bit of migration and hwpoison entries with huge_pte_clear_uffd_wp(), which operates on the present-PTE bit position. Swap entries keep the uffd-wp state elsewhere -- the migration branch reads and sets it with pte_swp_uffd_wp() and pte_swp_mkuffd_wp() -- and the present-PTE position falls into the swap payload. On x86-64 it lands in the inverted swap offset, where a naturally-aligned hugetlb PFN always has the affected bit set, so the clear advances the encoded PFN by two pages.
No userfaultfd needs to be involved: the clear is guarded only by the child VMA not being uffd-wp registered, so a plain fork() with an in-flight hugetlb migration entry (or a poisoned hugetlb page) corrupts the entry copied into the child. Instrumenting the clear and forking after MADV_HWPOISON on a 2MB anon hugetlb page shows:
offset before=120e00
offset after =120e02
The fallout is mostly latent: rmap walks match migration entries by folio range and remove_migration_pte() rebuilds the PTE from the folio, so a within-folio PFN skew heals once migration completes. But any path that re-encodes the corrupted offset -- e.g. hugetlb_change_protection() rewriting a writable migration entry via make_readable_migration_entry(swp_offset(entry)) -- propagates it.
Migration entries legitimately carry uffd-wp, so clear it with pte_swp_clear_uffd_wp(), matching copy_nonpresent_pte() and move_huge_pte().
A hwpoison entry, on the other hand, never carries the uffd-wp bit: it is installed fresh by make_hwpoison_entry() (try_to_unmap_one() does not preserve uffd-wp on the hwpoison path) and hugetlb_change_protection() leaves hwpoison entries untouched. There was nothing to clear there, only the corruption, so drop the clear entirely.
[ kas: 6.1 predates the huge_pte_*uffd_wp() -> pte_swp_*uffd_wp()
conversion in copy_hugetlb_page_range() (commit 5a2f8d22ace4), so apply the fix inline: convert the migration branch's uffd-wp read and set to the swap-position helpers too, otherwise the src re-encode (huge_pte_mkuffd_wp) corrupts the offset the same way; and drop the hwpoison clear ]
--- mm/hugetlb.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
mm/hugetlb.c +10 -8
@@ -5106,14 +5106,16 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,*/ ; }else if (unlikely (is_hugetlb_entry_hwpoisoned (entry))) { -bool uffd_wp =huge_pte_uffd_wp (entry); - -if (!userfaultfd_wp (dst_vma) && uffd_wp) - entry =huge_pte_clear_uffd_wp (entry); +/* +* A hwpoison entry never carries the uffd-wp bit: it is +* installed fresh by make_hwpoison_entry() and +* hugetlb_change_protection() leaves it untouched, so +* there is nothing to clear for the child. +*/ set_huge_pte_at (dst, addr, dst_pte, entry); }else if (unlikely (is_hugetlb_entry_migration (entry))) {swp_entry_t swp_entry =pte_to_swp_entry (entry); -bool uffd_wp =huge_pte_uffd_wp (entry); +bool uffd_wp =pte_swp_uffd_wp (entry);if (!is_readable_migration_entry (swp_entry) && cow) {/*
@@ -5124,11 +5126,11 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, swp_offset(swp_entry)); entry =swp_entry_to_pte (swp_entry);if (userfaultfd_wp (src_vma) && uffd_wp) - entry =huge_pte_mkuffd_wp (entry); + entry =pte_swp_mkuffd_wp (entry);set_huge_pte_at (src, addr, src_pte, entry); } -if (!userfaultfd_wp (dst_vma) && uffd_wp) - entry =huge_pte_clear_uffd_wp (entry); +if (!userfaultfd_wp (dst_vma)) + entry =pte_swp_clear_uffd_wp (entry);set_huge_pte_at (dst, addr, dst_pte, entry); }else if (unlikely (is_pte_marker (entry))) {/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 479/609 mm/huge_memory: unlock i_mmap_rwsem before releasing after-split folios
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiryl Shutsemau (Meta) <[email protected]>
[ Upstream commit e923bd21058ea02fd0dcd3549d151d143fd036e5 ]
__folio_split() keeps dereferencing the mapping after the split:shmem_uncharge(mapping->host) and remap_page() while the folios are still frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the after-split folios have been unlocked and freed.
Nothing holds an inode reference across that. The split relies on @folio -- which the beyond-EOF drop loop never removes, as it starts at folio_next(folio) -- staying locked and in the page cache to hold off eviction. But the unlock loop unlocks @folio before i_mmap_unlock_read() runs. If the caller's @lock_at is a tail beyond EOF, as memory_failure() passes when splitting a poisoned tail of a shmem THP that reaches past i_size during truncation, it too is gone from the page cache; so once @folio is unlocked no locked, in-cache folio pins the inode, and a concurrent final iput() can evict and RCU-free it before i_mmap_unlock_read() touches i_mmap_rwsem:
BUG: KASAN: slab-use-after-free in __up_read+0x634/0x790 i_mmap_unlock_read include/linux/fs.h:537 [inline] __folio_split+0x732/0x1640 mm/huge_memory.c:4100 try_to_split_thp_page+0xab/0x390 mm/memory-failure.c:1675 memory_failure+0x1394/0x26e0 mm/memory-failure.c:2470 Freed by task 4601: shmem_free_in_core_inode+0x54/0xb0 mm/shmem.c:5177 evict+0x57f/0xac0 fs/inode.c:870
Do every mapping dereference while @folio still pins the inode: drop i_mmap_rwsem right after remap_page(), before the loop that unlocks and frees the after-split folios, and clear @mapping so the exit path does not unlock it again. shmem_uncharge() and remap_page() already run before that point, so after this nothing past the unlock loop touches the inode or the mapping.
This is now a rule the split depends on, alongside keeping @folio frozen until the page cache is updated: no inode or mapping dereference once the after-split folios start being unlocked.
(cherry picked from commit e923bd21058ea02fd0dcd3549d151d143fd036e5) [ kas: adapt to the __split_huge_page()/split_huge_page_to_list()
two-function split: pass @mapping into __split_huge_page() and drop it there, before the loop that frees the after-split subpages while the head is still locked; the caller then skips its own i_mmap unlock ]
--- mm/huge_memory.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
mm/huge_memory.c +14 -2
@@ -2516,7 +2516,7 @@ static void __split_huge_page_tail(struct page *head, int tail, }static void __split_huge_page (struct page *page,struct list_head *list, -pgoff_t end) +pgoff_t end,struct address_space *mapping) {struct folio *folio =page_folio (page);struct page *head = &folio->page;
@@ -2594,6 +2594,16 @@ static void __split_huge_page(struct page *page, struct list_head *list,split_swap_cluster (entry); } +/* +* Drop the mapping while the head page is still locked and thus pins +* the inode. The loop below may free the after-split subpages -- +* including the head, when @page is a tail beyond EOF that the split +* dropped from the page cache -- which could otherwise let the inode, +* and @mapping, be freed before this unlock. +*/ +if (mapping) +i_mmap_unlock_read (mapping); +for (i =0 ; i < nr; i++) {struct page *subpage = head + i;if (subpage == page)
@@ -2774,7 +2784,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list) } } -__split_huge_page (page, list, end); +__split_huge_page (page, list, end, mapping); +/* __split_huge_page() dropped the i_mmap lock */ + mapping =NULL ; ret =0 ; }else {spin_unlock (&ds_queue->split_queue_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 480/609 net: openvswitch: fix skb leak on flow key update failure during recirculation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Maximets <[email protected]>
[ Upstream commit e1cf066244dad576221b7123a0e5005967f25a20 ]
do_execute_actions() returns right away when execute_recirc() fails on the last action as it assumes this function always takes ownership of the skb when 'last' is true. But when the flow key update fails, the function doesn't free the skb and it ends up leaked.
This is a very unlikely scenario as it requires the packet to become unparseable by applying a set of actions on a previously parseable skb, but should be fixed nevertheless.
Reported by Sashiko.
--- net/openvswitch/actions.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
net/openvswitch/actions.c +8 -1
@@ -1107,6 +1107,10 @@ static int execute_masked_set_action(struct sk_buff *skb,return err; } +/* When 'last' is true, recirc() should always consume the 'skb'. +* Otherwise, recirc() should keep 'skb' intact regardless what +* actions are executed on recirculation. +*/ static int execute_recirc (struct datapath *dp,struct sk_buff *skb,struct sw_flow_key *key,const struct nlattr *a,bool last)
@@ -1117,8 +1121,11 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,int err; err =ovs_flow_key_update (skb, key); -if (err) +if (err) { +if (last) +kfree_skb (skb);return err; + } }BUG_ON (!is_flow_key_valid (key));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 481/609 firmware: stratix10-svc: fix memory leaks and list corruption bugs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tze Yee Ng <[email protected]>
[ Upstream commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c ]
Fix a memory leak when gen_pool_alloc() fails by freeing pmem on the error path. Switch pmem allocation from devm_kzalloc() to kzalloc() with explicit kfree() in the free path to match its list-managed lifetime. Remove the erroneous list_del(&svc_data_mem) which corrupted the list head on failed lookups.
--- drivers/firmware/stratix10-svc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/firmware/stratix10-svc.c +6 -4
@@ -1065,14 +1065,16 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,struct gen_pool *genpool = chan->ctrl->genpool;size_t s =roundup (size,1 << genpool->min_alloc_order); - pmem =devm_kzalloc (chan->ctrl->dev,sizeof (*pmem),GFP_KERNEL ); + pmem =kzalloc (sizeof (*pmem),GFP_KERNEL );if (!pmem)return ERR_PTR (-ENOMEM );guard (mutex)(&svc_mem_lock); va =gen_pool_alloc (genpool, s); -if (!va) +if (!va) { +kfree (pmem);return ERR_PTR (-ENOMEM ); + }memset ((void *)va,0 , s); pa =gen_pool_virt_to_phys (genpool, va);
@@ -1098,6 +1100,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);void stratix10_svc_free_memory (struct stratix10_svc_chan *chan,void *kaddr) {struct stratix10_svc_data_mem *pmem; +guard (mutex)(&svc_mem_lock);list_for_each_entry (pmem, &svc_data_mem, node)
@@ -1106,10 +1109,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr) (unsigned long)kaddr, pmem->size); pmem->vaddr =NULL ;list_del (&pmem->node); +kfree (pmem);return ; } - -list_del (&svc_data_mem); }EXPORT_SYMBOL_GPL (stratix10_svc_free_memory);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 482/609 gpio: pch: use raw_spinlock_t for the register lock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junjie Cao <[email protected]>
[ Upstream commit a02b8950d619123da64f69b70fe1dadef217dfe4 ]
pch_irq_type() is registered as the irq_chip .irq_set_type callback and takes chip->spinlock with spin_lock_irqsave(). This callback is reached from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled. That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is an rtmutex-backed sleeping lock, so acquiring it there is invalid.
This was confirmed on a PREEMPT_RT kernel with lockdep (PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP). A grounded PoC mirrored pch_irq_type()'s locking and drove it through the real genirq carrier irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e. the same __irq_set_trigger() edge that __setup_irq() takes for a requested IRQ. With the original spin_lock_irqsave() edge lockdep reported an invalid wait context, immediately followed by:
BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48 in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60 rt_spin_lock+0x3a/0x1c0 repro_irq_set_type+0x64/0xa0 [pch_repro] __irq_set_trigger+0x69/0x140 irq_set_irq_type+0x78/0xd0
Switching the mirrored lock to raw_spinlock_t made both splats go away.
Convert the register lock to raw_spinlock_t. The same lock also serializes the GPIO direction/value callbacks and the suspend/resume register save/restore, but all of those critical sections only perform MMIO register accesses (ioread32()/iowrite32()) and irq_set_handler_locked(); none of them contain sleepable operations. Keeping this register lock non-sleeping is therefore appropriate for the irqchip callbacks and does not change the GPIO-side locking contract.
This is the same class of issue and fix as recently addressed for other GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use raw_spinlock_t in the irq startup path").
--- drivers/gpio/gpio-pch.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/gpio/gpio-pch.c +14 -14
@@ -97,7 +97,7 @@ struct pch_gpio {struct pch_gpio_reg_data pch_gpio_reg;int irq_base;enum pch_type_t ioh; -spinlock_t spinlock; +raw_spinlock_t spinlock; };static void pch_gpio_set (struct gpio_chip *gpio,unsigned int nr,int val)
@@ -106,7 +106,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)struct pch_gpio *chip =gpiochip_get_data (gpio);unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); reg_val =ioread32 (&chip->reg->po);if (val) reg_val |=BIT (nr);
@@ -114,7 +114,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) reg_val &= ~BIT (nr);iowrite32 (reg_val, &chip->reg->po); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags); }static int pch_gpio_get (struct gpio_chip *gpio,unsigned int nr)
@@ -132,7 +132,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,u32 reg_val;unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); reg_val =ioread32 (&chip->reg->po);if (val)
@@ -146,7 +146,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, pm |=BIT (nr);iowrite32 (pm, &chip->reg->pm); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -157,12 +157,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)u32 pm;unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); pm =ioread32 (&chip->reg->pm); pm &=BIT (gpio_pins[chip->ioh]) -1 ; pm &= ~BIT (nr);iowrite32 (pm, &chip->reg->pm); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -264,7 +264,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)return 0 ; } -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags);/* Set interrupt mode */ im =ioread32 (im_reg) & ~(PCH_IM_MASK << (im_pos *4 ));
@@ -276,7 +276,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)else if (type &IRQ_TYPE_EDGE_BOTH )irq_set_handler_locked (d, handle_edge_irq); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -373,7 +373,7 @@ static int pch_gpio_probe(struct pci_dev *pdev, chip->ioh = id->driver_data; chip->reg = chip->base;pci_set_drvdata (pdev, chip); -spin_lock_init (&chip->spinlock); +raw_spin_lock_init (&chip->spinlock);pch_gpio_setup (chip); ret =devm_gpiochip_add_data (dev, &chip->gpio, chip);
@@ -406,9 +406,9 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)struct pch_gpio *chip =dev_get_drvdata (dev);unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags);pch_gpio_save_reg_conf (chip); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -418,11 +418,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)struct pch_gpio *chip =dev_get_drvdata (dev);unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags);iowrite32 (0x01 , &chip->reg->reset);iowrite32 (0x00 , &chip->reg->reset);pch_gpio_restore_reg_conf (chip); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 483/609 Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Elver <[email protected]>
[ Upstream commit b66774b48dd98f07254951f74ea6f513efe7ff8b ]
l2cap_chan_timeout() runs asynchronously and accesses chan->conn. If the connection is torn down while the timer is running or pending, chan->conn can be freed, leading to a use-after-free when the timer worker attempts to lock conn->lock:
| BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:112 [inline] | BUG: KASAN: slab-use-after-free in atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline] | BUG: KASAN: slab-use-after-free in __mutex_trylock_fast kernel/locking/mutex.c:161 [inline] | BUG: KASAN: slab-use-after-free in mutex_lock+0x4f/0xa0 kernel/locking/mutex.c:318 | Write of size 8 at addr ffff8881298d9550 by task kworker/2:1/83 | | CPU: 2 UID: 0 PID: 83 Comm: kworker/2:1 Not tainted 7.1.0-rc6-next-20260601-dirty #6 PREEMPT(full) | Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 | Workqueue: events l2cap_chan_timeout | Call Trace: | <TASK> | instrument_atomic_read_write include/linux/instrumented.h:112 [inline] | atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline] | __mutex_trylock_fast kernel/locking/mutex.c:161 [inline] | mutex_lock+0x4f/0xa0 kernel/locking/mutex.c:318 | l2cap_chan_timeout+0x5d/0x1b0 net/bluetooth/l2cap_core.c:422 | process_one_work kernel/workqueue.c:3326 [inline] | process_scheduled_works+0x7c8/0xfb0 kernel/workqueue.c:3409 | worker_thread+0x8a9/0xcf0 kernel/workqueue.c:3490 | kthread+0x346/0x430 kernel/kthread.c:436 | ret_from_fork+0x1a3/0x470 arch/x86/kernel/process.c:158 | ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 | </TASK> | | Allocated by task 320: | l2cap_conn_add+0xa7/0x820 net/bluetooth/l2cap_core.c:7075 | l2cap_connect_cfm+0xdb/0xd70 net/bluetooth/l2cap_core.c:7452 | hci_connect_cfm include/net/bluetooth/hci_core.h:2139 [inline] | hci_remote_features_evt+0x52f/0x9f0 net/bluetooth/hci_event.c:3760 | hci_event_func net/bluetooth/hci_event.c:7796 [inline] | hci_event_packet+0x561/0xa70 net/bluetooth/hci_event.c:7847 | hci_rx_work+0x370/0x890 net/bluetooth/hci_core.c:4040 | process_one_work kernel/workqueue.c:3326 [inline] | process_scheduled_works+0x7c8/0xfb0 kernel/workqueue.c:3409 | worker_thread+0x8a9/0xcf0 kernel/workqueue.c:3490 | kthread+0x346/0x430 kernel/kthread.c:436 | ret_from_fork+0x1a3/0x470 arch/x86/kernel/process.c:158 | ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 | | Freed by task 322: | hci_disconn_cfm include/net/bluetooth/hci_core.h:2154 [inline] | hci_conn_hash_flush+0x101/0x1f0 net/bluetooth/hci_conn.c:2736 | hci_dev_close_sync+0x889/0xde0 net/bluetooth/hci_sync.c:5405 | hci_dev_do_close net/bluetooth/hci_core.c:502 [inline] | hci_unregister_dev+0x1f7/0x370 net/bluetooth/hci_core.c:2679 | vhci_release+0x12a/0x180 drivers/bluetooth/hci_vhci.c:690 | __fput+0x369/0x890 fs/file_table.c:510 | task_work_run+0x160/0x1d0 kernel/task_work.c:233 | get_signal+0xf5b/0x1120 kernel/signal.c:2810 | arch_do_signal_or_restart+0x4d/0x600 arch/x86/kernel/signal.c:337 | __exit_to_user_mode_loop kernel/entry/common.c:64 [inline] | exit_to_user_mode_loop+0x85/0x510 kernel/entry/common.c:98 | do_syscall_64+0x263/0x3d0 arch/x86/entry/syscall_64.c:100 | entry_SYSCALL_64_after_hwframe+0x77/0x7f | | The buggy address belongs to the object at ffff8881298d9400 | which belongs to the cache kmalloc-512 of size 512 | The buggy address is located 336 bytes inside of | freed 512-byte region [ffff8881298d9400, ffff8881298d9600)
Fix it by having chan->conn hold a reference to l2cap_conn (via l2cap_conn_get) when the channel is added to the connection, and releasing it in the channel destructor. This ensures the l2cap_conn remains alive as long as the channel exists.
A new FLAG_DEL channel flag is introduced to indicate that the channel has been deleted from its connection. l2cap_chan_del() atomically sets this flag using test_and_set_bit() instead of setting chan->conn to NULL. All asynchronous workers (l2cap_chan_timeout, l2cap_ack_timeout, l2cap_monitor_timeout, l2cap_retrans_timeout) and l2cap_chan_send() check FLAG_DEL to determine whether the channel has been torn down, rather than testing chan->conn for NULL.
--- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 33 ++++++++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-)
include/net/bluetooth/l2cap.h +1 -0
@@ -743,6 +743,7 @@ enum {FLAG_ECRED_CONN_REQ_SENT ,FLAG_PENDING_SECURITY ,FLAG_HOLD_HCI_CONN , + FLAG_DEL, };/* Lock nesting levels for L2CAP channels. We need these because lockdep
net/bluetooth/l2cap_core.c +20 -13
@@ -415,7 +415,7 @@ static void l2cap_chan_timeout(struct work_struct *work)BT_DBG ("chan %p state %s" , chan,state_to_string (chan->state)); -if (!conn) { +if (test_bit (FLAG_DEL , &chan->flags)) {l2cap_chan_put (chan);return ; }
@@ -426,6 +426,9 @@ static void l2cap_chan_timeout(struct work_struct *work)*/ l2cap_chan_lock (chan); +if (test_bit (FLAG_DEL , &chan->flags)) + goto unlock; +if (chan->state ==BT_CONNECTED || chan->state ==BT_CONFIG ) reason =ECONNREFUSED ; else if (chan->state == BT_CONNECT &&
@@ -438,10 +441,11 @@ static void l2cap_chan_timeout(struct work_struct *work) chan->ops->close (chan); +unlock:l2cap_chan_unlock (chan); -l2cap_chan_put (chan);mutex_unlock (&conn->chan_lock); +l2cap_chan_put (chan); }struct l2cap_chan *l2cap_chan_create (void )
@@ -494,6 +498,9 @@ static void l2cap_chan_destroy(struct kref *kref)list_del (&chan->global_l);write_unlock (&chan_list_lock); +if (chan->conn) +l2cap_conn_put (chan->conn); +kfree (chan); }
@@ -625,7 +632,7 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) conn->disc_reason =HCI_ERROR_REMOTE_USER_TERM ; - chan->conn = conn; + chan->conn =l2cap_conn_get (conn);switch (chan->chan_type) {case L2CAP_CHAN_CONN_ORIENTED :
@@ -680,30 +687,26 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)void l2cap_chan_del (struct l2cap_chan *chan,int err) { -struct l2cap_conn *conn = chan->conn; -__clear_chan_timer (chan); -BT_DBG ("chan %p, conn %p, err %d, state %s" , chan, conn, err, +BT_DBG ("chan %p, err %d, state %s" , chan, err,state_to_string (chan->state)); chan->ops->teardown (chan, err); -if (conn) { +if (!test_and_set_bit (FLAG_DEL , &chan->flags)) {/* Delete from channel list */ list_del (&chan->list);l2cap_chan_put (chan); - chan->conn =NULL ; -/* Reference was only held for non-fixed channels or * fixed channels that explicitly requested it using the * FLAG_HOLD_HCI_CONN flag. */ if (chan->chan_type !=L2CAP_CHAN_FIXED ||test_bit (FLAG_HOLD_HCI_CONN , &chan->flags)) -hci_conn_drop (conn->hcon); +hci_conn_drop (chan->conn->hcon); }if (test_bit (CONF_NOT_COMPLETE , &chan->conf_state))
@@ -1930,7 +1933,7 @@ static void l2cap_monitor_timeout(struct work_struct *work)l2cap_chan_lock (chan); -if (!chan->conn) { +if (test_bit (FLAG_DEL , &chan->flags)) {l2cap_chan_unlock (chan);l2cap_chan_put (chan);return ;
@@ -1951,7 +1954,7 @@ static void l2cap_retrans_timeout(struct work_struct *work)l2cap_chan_lock (chan); -if (!chan->conn) { +if (test_bit (FLAG_DEL , &chan->flags)) {l2cap_chan_unlock (chan);l2cap_chan_put (chan);return ;
@@ -2566,7 +2569,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)int err;struct sk_buff_head seg_queue; -if (!chan->conn) +if (test_bit (FLAG_DEL , &chan->flags))return -ENOTCONN ;/* Connectionless channel */
@@ -3167,12 +3170,16 @@ static void l2cap_ack_timeout(struct work_struct *work)l2cap_chan_lock (chan); +if (test_bit (FLAG_DEL , &chan->flags)) + goto unlock; + frames_to_ack =__seq_offset (chan, chan->buffer_seq, chan->last_acked_seq);if (frames_to_ack)l2cap_send_rr_or_rnr (chan,0 ); +unlock:l2cap_chan_unlock (chan);l2cap_chan_put (chan); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 484/609 Bluetooth: 6lowpan: Fix using chan->conn as indication to no remote netdev
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Augusto von Dentz <[email protected]>
[ Upstream commit d38eaf611839b85ade3dd3db309dbc8aaaaf0095 ]
b66774b48dd9 ("Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref") don't reset the chan->conn to NULL anymore making the bt# netdev not be remove once the last l2cap_chan_del is removed.
Instead of restoring the original behavior this remove the logic of keeping the interface after the last channel is removed because it never worked as intended and the l2cap_chan_del always detach its l2cap_conn which results in always removing the channel anyway.
--- net/bluetooth/6lowpan.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-)
net/bluetooth/6lowpan.c +3 -15
@@ -781,20 +781,10 @@ static void chan_close_cb(struct l2cap_chan *chan)struct lowpan_btle_dev *dev =NULL ;struct lowpan_peer *peer;int err = -ENOENT ; -bool last = false, remove = true; +bool last = false;BT_DBG ("chan %p conn %p" , chan, chan->conn); -if (chan->conn && chan->conn->hcon) { -if (!is_bt_6lowpan (chan->conn->hcon)) -return ; - -/* If conn is set, then the netdev is also there and we should -* not remove it. -*/ - remove = false; - } -spin_lock (&devices_lock);list_for_each_entry_rcu (entry, &bt_6lowpan_devices, list) {
@@ -821,10 +811,8 @@ static void chan_close_cb(struct l2cap_chan *chan)ifdown (dev->netdev); -if (remove) { -INIT_WORK (&entry->delete_netdev, delete_netdev); -schedule_work (&entry->delete_netdev); - } +INIT_WORK (&entry->delete_netdev, delete_netdev); +schedule_work (&entry->delete_netdev); }else {spin_unlock (&devices_lock); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 485/609 Bluetooth: hci_conn: fix potential UAF in create_big_sync
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
[ Upstream commit 0beddb0c380bed5f5b8e61ddbe14635bb73d0b41 ]
Add hci_conn_valid() check in create_big_sync() to detect stale connections before proceeding with BIG creation. Handle the resulting -ECANCELED in create_big_complete() and re-validate the connection under hci_dev_lock() before dereferencing, matching the pattern used by create_le_conn_complete() and create_pa_complete().
Keep the hci_conn object alive across the async boundary by taking a reference via hci_conn_get() when queueing create_big_sync(), and dropping it in the completion callback. The refcount and the lock are complementary: the refcount keeps the object allocated, while hci_dev_lock() serializes hci_conn_hash_del()'s list_del_rcu() on hdev->conn_hash, as required by hci_conn_del().
hci_conn_put() is called outside hci_dev_unlock() so the final put (which resolves to kfree() via bt_link_release) does not run under hdev->lock, though the release path would be safe either way.
Without this, create_big_complete() would unconditionally dereference the conn pointer on error, causing a use-after-free via hci_connect_cfm() and hci_conn_del().
[ Backported to 6.1.y: included inline helper hci_conn_valid() in
include/net/bluetooth/hci_core.h from upstream commit 881559af5f5c ]
--- include/net/bluetooth/hci_core.h | 18 ++++++++++++++++++ net/bluetooth/hci_conn.c | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-)
include/net/bluetooth/hci_core.h +18 -0
@@ -1069,6 +1069,24 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev)return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num; } +static inline bool hci_conn_valid (struct hci_dev *hdev,struct hci_conn *conn) +{ +struct hci_conn_hash *h = &hdev->conn_hash; +struct hci_conn *c; + +rcu_read_lock (); + +list_for_each_entry_rcu (c, &h->list, list) { +if (c == conn) { +rcu_read_unlock (); +return true; + } + } +rcu_read_unlock (); + +return false; +} +static inline __u8 hci_conn_lookup_type (struct hci_dev *hdev,__u16 handle) {struct hci_conn_hash *h = &hdev->conn_hash;
net/bluetooth/hci_conn.c +18 -1
@@ -2088,6 +2088,9 @@ static int create_big_sync(struct hci_dev *hdev, void *data)u32 flags =0 ;int err; +if (!hci_conn_valid (hdev, conn)) +return -ECANCELED ; +if (qos->out.phy ==0x02 ) flags |=MGMT_ADV_FLAG_SEC_2M ;
@@ -2194,11 +2197,24 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)bt_dev_dbg (hdev,"conn %p" , conn); +if (err == -ECANCELED ) + goto done; + +hci_dev_lock (hdev); + +if (!hci_conn_valid (hdev, conn)) + goto unlock; +if (err) {bt_dev_err (hdev,"Unable to create BIG: %d" , err);hci_connect_cfm (conn, err);hci_conn_del (conn); } + +unlock: +hci_dev_unlock (hdev); +done: +hci_conn_put (conn); } struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
@@ -2223,10 +2239,11 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, }/* Queue start periodic advertising and create BIG */ - err =hci_cmd_sync_queue (hdev, create_big_sync, conn, + err =hci_cmd_sync_queue (hdev, create_big_sync,hci_conn_get (conn), create_big_complete);if (err <0 ) {hci_conn_drop (conn); +hci_conn_put (conn);return ERR_PTR (err); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 486/609 mount: honour SB_NOUSER in the new mount API
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro <[email protected]>
[ Upstream commit 6dd3c6884cd9defb511284b566cef5ac8f657dbf ]
One should *not* be allowed to mount one of those, new API or not.
--- fs/namespace.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/namespace.c +5 -0
@@ -3744,6 +3744,11 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags, ret =PTR_ERR (newmount.mnt); goto err_unlock; } +if (newmount.mnt->mnt_sb->s_flags &SB_NOUSER ) { +mntput (newmount.mnt); + ret = -EINVAL ; + goto err_unlock; + } newmount.dentry =dget (fc->root); newmount.mnt->mnt_flags = mnt_flags;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 487/609 s390/zcrypt: Fix missing mem scrub at clear key import in cca_clr2cipherkey()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <[email protected]>
[ Upstream commit 01476391aecef36a3b789ee844357b22fbc90665 ]
The helper function _ip_cprb_helper() uses internal buffer memory for building and processing CPRBs. After use this buffer was never scrubbed which could lead to leaving for example clear key material in memory which could be exposed via tricky reuse of this same memory.
Extend the _ip_cprb_helper() function with another parameter 'scrub' used to steer scrubbing of this buffer. So now the caller has the opportunity to decide if scrubbing is needed or not.
Extend the clear key to secure key token import process in function cca_clr2cipherkey() to tell the helper function from above to scrub the cprb buffer when the clear key value is part of the request data.
Add explicit scrubbing on return from function cca_clr2cipherkey() for the random EXOR buffer and the cprb buffer.
Overall this cleans the internal used buffer in case of clear key import to prevent sensitive data to get exposed.
--- drivers/s390/crypto/zcrypt_ccamisc.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
drivers/s390/crypto/zcrypt_ccamisc.c +13 -7
@@ -946,7 +946,8 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,const u8 *clr_key_value, int clr_key_bit_size, u8 *key_token, - int *key_token_size) + int *key_token_size, + bool scrub) { int rc, n;u8 *mem, *ptr;
@@ -1087,7 +1088,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain, *key_token_size = t->len; out: -free_cprbmem (mem,PARMBSIZE ,0 ); +free_cprbmem (mem,PARMBSIZE , scrub);return rc; }
@@ -1130,7 +1131,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,* 4/4 COMPLETE the secure cipher key import */ rc =_ip_cprb_helper (card, dom,"AES " ,"FIRST " ,"MIN3PART" , - exorbuf, keybitsize, token, &tokensize); + exorbuf, keybitsize, token, &tokensize, + true);if (rc) { DEBUG_ERR( "%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n",
@@ -1138,7 +1140,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags, goto out; } rc =_ip_cprb_helper (card, dom,"AES " ,"ADD-PART" ,NULL , - clrkey, keybitsize, token, &tokensize); + clrkey, keybitsize, token, &tokensize, + true);if (rc) { DEBUG_ERR( "%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n",
@@ -1146,7 +1149,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags, goto out; } rc =_ip_cprb_helper (card, dom,"AES " ,"ADD-PART" ,NULL , - exorbuf, keybitsize, token, &tokensize); + exorbuf, keybitsize, token, &tokensize, + true);if (rc) { DEBUG_ERR( "%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n",
@@ -1154,7 +1158,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags, goto out; } rc =_ip_cprb_helper (card, dom,"AES " ,"COMPLETE" ,NULL , -NULL , keybitsize, token, &tokensize); +NULL , keybitsize, token, &tokensize, + true);if (rc) { DEBUG_ERR( "%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n",
@@ -1172,7 +1177,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags, *keybufsize = tokensize; out: -kfree (token); +memzero_explicit (exorbuf,sizeof (exorbuf)); +kfree_sensitive (token);return rc; }EXPORT_SYMBOL (cca_clr2cipherkey);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 488/609 NFS: Pin the struct nfs_server during a FREE_STATEID call
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anna Schumaker <[email protected]>
[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]
Dan Aloni reports that he was able to hit a use-after-free bug if a FREE_STATEID operation gets delayed for whatever reason. Fix this by bumping the refcount of the 'struct nfs_server' object for the duration of the FREE_STATEID so it doesn't get cleaned up from underneath us while operations are still in flight.
--- fs/nfs/nfs4proc.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/nfs/nfs4proc.c +5 -0
@@ -10388,6 +10388,7 @@ static void nfs41_free_stateid_release(void *calldata)struct nfs_free_stateid_data *data = calldata;struct nfs_client *clp = data->server->nfs_client; +nfs_sb_deactive (data->server->super);nfs_put_client (clp);kfree (calldata); }
@@ -10429,6 +10430,10 @@ static int nfs41_free_stateid(struct nfs_server *server,if (!refcount_inc_not_zero (&clp->cl_count))return -EIO ; +if (!nfs_sb_active (server->super)) { +nfs_put_client (clp); +return -EIO ; + }nfs4_state_protect (server->nfs_client,NFS_SP4_MACH_CRED_STATEID , &task_setup.rpc_client, &msg);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 489/609 ARM: npcm: Fix OF node refcount leaks in SMP setup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]
npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up the GCR and SCU nodes with of_find_compatible_node(). The returned nodes are used for of_iomap(), but the node references are never released.
of_iomap() does not consume the device node reference, and iounmap() only releases the MMIO mapping. Drop each node reference after the corresponding mapping attempt.
--- arch/arm/mach-npcm/platsmp.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/mach-npcm/platsmp.c +2 -0
@@ -35,6 +35,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu, goto out; } gcr_base =of_iomap (gcr_np,0 ); +of_node_put (gcr_np);if (!gcr_base) {pr_err ("could not iomap gcr" ); ret = -ENOMEM ;
@@ -63,6 +64,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)return ; } scu_base =of_iomap (scu_np,0 ); +of_node_put (scu_np);if (!scu_base) {pr_err ("could not iomap scu" );return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 490/609 Revert "net: thunderbolt: Enable end-to-end flow control also in transmit"
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Ye <[email protected]>
[ Upstream commit 1881f2efbf7f78dc0a79a387b29fde6ff56d3731 ]
This reverts commit a8065af3346ebd7c76ebc113451fb3ba94cf7769.
Per the USB4 spec, a Transmit Descriptor Ring with E2E flow control disabled does not require any credits to be available before the Host Interface Adapter Layer transmits a tunneled packet from it. Once E2E is enabled on that ring the controller must first obtain end-to-end credits.
The ASMedia ASM4242 USB4 host router (PCI 1b21:2425) never delivers those credits. The controller does accept the configuration: reading the ring OPTIONS register back right after tb_ring_start() returns exactly what was written, including RING_FLAG_E2E_FLOW_CONTROL (bit 28) and the E2E HopID field. No credit ever arrives though, so the Tx ring's hardware consumer index never advances and the link carries no traffic at all.
Measured on two hosts connected point to point, onboard ASM4242 on MSI X870E and X870, v6.17, stock drivers/net/thunderbolt/main.c with only this revert applied on top:
before: 100% packet loss to the peer; thunderbolt0 is up and the
XDomain handshake completes ("new host found"), but iperf3 fails with "No route to host" once the neighbour entry expires
after: 0% packet loss, 0.28 ms RTT; iperf3 4.21 Gb/s one way and
5.17 Gb/s the other (5 runs each, stddev <= 0.02), 1 retransmit in 10 s
An instrumented build additionally showed a frozen-Tx-consumer watchdog firing ~30k times in a 10 s window before this change.
Rx-side E2E is not touched by this revert, so peers that do return credits keep receive-side flow control.
ASMedia does not look like an isolated case. The out-of-tree thunderbolt-ibverbs project disables native E2E on AMD NHI by default, noting that "Strix Halo has reproduced TX completion wedges with multiple native E2E rings active" -- the same failure mode, on a different vendor. Since the driver has no way to tell in advance which host router returns the credits, going back to the previous behaviour looks safer than adding a quirk per affected part; Tx-side E2E can be reintroduced as an opt-in for controllers that are known to implement the credit return.
Note that the reverted commit was not fixing a reported problem, it was derived from the spec wording alone, so this revert is not expected to regress a known workload. Cc'ing the original author in case there was one.
--- drivers/net/thunderbolt.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/net/thunderbolt.c +7 -6
@@ -884,12 +884,8 @@ static int tbnet_open(struct net_device *dev)netif_carrier_off (dev); - flags =RING_FLAG_FRAME ; -/* Only enable full E2E if the other end supports it too */ -if (tbnet_e2e && net->svc->prtcstns &TBNET_E2E ) - flags |=RING_FLAG_E2E ; - - ring =tb_ring_alloc_tx (xd->tb->nhi,-1 ,TBNET_RING_SIZE , flags); + ring =tb_ring_alloc_tx (xd->tb->nhi,-1 ,TBNET_RING_SIZE , +RING_FLAG_FRAME );if (!ring) {netdev_err (dev,"failed to allocate Tx ring\n" );return -ENOMEM ;
@@ -908,6 +904,11 @@ static int tbnet_open(struct net_device *dev) sof_mask =BIT (TBIP_PDF_FRAME_START ); eof_mask =BIT (TBIP_PDF_FRAME_END ); + flags =RING_FLAG_FRAME ; +/* Only enable full E2E if the other end supports it too */ +if (tbnet_e2e && net->svc->prtcstns &TBNET_E2E ) + flags |=RING_FLAG_E2E ; + ring =tb_ring_alloc_rx (xd->tb->nhi,-1 ,TBNET_RING_SIZE , flags, net->tx_ring.ring->hop, sof_mask, eof_mask, tbnet_start_poll, net);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 491/609 bonding: alb: re-check primary_is_promisc under RTNL in bond_alb_monitor
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei (Microsoft) <[email protected]>
[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]
bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the active slave. In that window the active slave can change under RTNL (RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()), which already drops the promiscuity and clears primary_is_promisc. The monitor still acts on the stale decision: if the slave was removed with no failover, curr_active_slave is now NULL and the deref faults; if it failed over, the stale dev_set_promiscuity(-1) underflows the new slave's promiscuity counter and pins it in IFF_PROMISC.
Oops: general protection fault, probably for non-canonical address ... KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] Workqueue: b42 bond_alb_monitor RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600) process_one_work (kernel/workqueue.c:3322) worker_thread (kernel/workqueue.c:3486) kthread (kernel/kthread.c:436) ret_from_fork (arch/x86/kernel/process.c:158) Kernel panic - not syncing: Fatal exception
Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so the monitor only undoes an increment it still owns. The other bonding monitors already re-read state under RTNL in their commit phase (bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only one acting on the pre-trylock decision.
--- drivers/net/bonding/bond_alb.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/net/bonding/bond_alb.c +6 -4
@@ -1535,8 +1535,8 @@ void bond_alb_monitor(struct work_struct *work) struct bonding *bond = container_of(work, struct bonding, alb_work.work);struct alb_bond_info *bond_info = &(BOND_ALB_INFO (bond)); +struct slave *slave, *curr;struct list_head *iter; -struct slave *slave;if (!bond_has_slaves (bond)) {atomic_set (&bond_info->tx_rebalance_counter,0 );
@@ -1598,9 +1598,11 @@ void bond_alb_monitor(struct work_struct *work)* because a slave was disabled then * it can now leave promiscuous mode. */ -dev_set_promiscuity (rtnl_dereference (bond->curr_active_slave)->dev, --1 ); - bond_info->primary_is_promisc =0 ; + curr =rtnl_dereference (bond->curr_active_slave); +if (bond_info->primary_is_promisc && curr) { +dev_set_promiscuity (curr->dev,-1 ); + bond_info->primary_is_promisc =0 ; + }rtnl_unlock ();rcu_read_lock ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 492/609 netfilter: ipset: switch ext_size to atomic64_t
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jozsef Kadlecsik <[email protected]>
[ Upstream commit 712a6f545c359b427daa9a5a782e30d2f8331e25 ]
The hash types do not acquire set->lock, they use 'region locking' where only part of the hash table is locked. Parallel inserts and deletes are possible and CPUs can race on ->ext_size update. Switch to atomic64_t.
This leaves another bug unresolved: there still can be a race on comment extension re-init. This will be handled in a later commit when converting to rhashtable backend.
--- include/linux/netfilter/ipset/ip_set.h | 2 +- net/netfilter/ipset/ip_set_bitmap_gen.h | 4 ++-- net/netfilter/ipset/ip_set_core.c | 6 +++--- net/netfilter/ipset/ip_set_hash_gen.h | 2 +- net/netfilter/ipset/ip_set_list_set.c | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-)
include/linux/netfilter/ipset/ip_set.h +1 -1
@@ -273,7 +273,7 @@ struct ip_set {/* Number of elements (vs timeout) */ u32 elements;/* Size of the dynamic extensions (vs timeout) */ -size_t ext_size; +atomic64_t ext_size;/* Element data size */ size_t dsize;/* Offsets to extensions in elements */
net/netfilter/ipset/ip_set_bitmap_gen.h +2 -2
@@ -75,7 +75,7 @@ mtype_flush(struct ip_set *set)mtype_ext_cleanup (set);bitmap_zero (map->members, map->elements); set->elements =0 ; - set->ext_size =0 ; +atomic64_set (&set->ext_size,0 ); }/* Calculate the actual memory size of the set data */
@@ -91,7 +91,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb) {const struct mtype *map = set->data;struct nlattr *nested; -size_t memsize =mtype_memsize (map, set->dsize) + set->ext_size; +size_t memsize =mtype_memsize (map, set->dsize) +atomic64_read (&set->ext_size); nested =nla_nest_start (skb,IPSET_ATTR_DATA );if (!nested)
net/netfilter/ipset/ip_set_core.c +3 -3
@@ -350,7 +350,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,size_t len = ext->comment ?strlen (ext->comment) :0 ;if (unlikely (c)) { - set->ext_size -=sizeof (*c) +strlen (c->str) +1 ; +atomic64_sub (sizeof (*c) +strlen (c->str) +1 , &set->ext_size);rcu_assign_pointer (comment->c,NULL );kfree_rcu (c, rcu); }
@@ -362,7 +362,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,if (unlikely (!c))return ;strscpy (c->str, ext->comment, len +1 ); - set->ext_size +=sizeof (*c) +strlen (c->str) +1 ; +atomic64_add (sizeof (*c) +strlen (c->str) +1 , &set->ext_size);rcu_assign_pointer (comment->c, c); }EXPORT_SYMBOL_GPL (ip_set_init_comment);
@@ -392,7 +392,7 @@ ip_set_comment_free(struct ip_set *set, void *ptr) c =rcu_dereference_protected (comment->c,1 );if (unlikely (!c))return ; - set->ext_size -=sizeof (*c) +strlen (c->str) +1 ; +atomic64_sub (sizeof (*c) +strlen (c->str) +1 , &set->ext_size);rcu_assign_pointer (comment->c,NULL );kfree_rcu (c, rcu); }
net/netfilter/ipset/ip_set_hash_gen.h +1 -1
@@ -1276,7 +1276,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)rcu_read_lock_bh (); t =rcu_dereference_bh (h->table);mtype_ext_size (set, &elements, &ext_size); - memsize =mtype_ahash_memsize (h, t) + ext_size + set->ext_size; + memsize =mtype_ahash_memsize (h, t) + ext_size +atomic64_read (&set->ext_size); htable_bits = t->htable_bits;rcu_read_unlock_bh ();
net/netfilter/ipset/ip_set_list_set.c +2 -2
@@ -421,7 +421,7 @@ list_set_flush(struct ip_set *set)list_for_each_entry_safe (e, n, &map->members, list)list_set_del (set, e); set->elements =0 ; - set->ext_size =0 ; +atomic64_set (&set->ext_size,0 ); } static void
@@ -455,7 +455,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb) {const struct list_set *map = set->data;struct nlattr *nested; -size_t memsize =list_set_memsize (map, set->dsize) + set->ext_size; +size_t memsize =list_set_memsize (map, set->dsize) +atomic64_read (&set->ext_size); nested =nla_nest_start (skb,IPSET_ATTR_DATA );if (!nested)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 493/609 ipvs: avoid out-of-bounds write in ip_vs_nat_icmp
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Anastasov <[email protected]>
[ Upstream commit 646922a0379496154e8c8faca4f8e2fd9100cacc ]
Sashiko warns that local attacker can modify the packet while it is processed by IPVS. Some places read the IP ihl field multiple times which can cause out-of-bounds access. One such place is ip_vs_nat_icmp where we can write after the validated area.
Fix it by providing ciph argument just like it is done for IPv6 and use ciph->len as offset to the embedded transport header.
Modify some IPv4 header checks by reading the ihl field only once.
--- include/net/ip_vs.h | 2 +- net/netfilter/ipvs/ip_vs_core.c | 67 +++++++++++++++++---------------- net/netfilter/ipvs/ip_vs_xmit.c | 2 +- 3 files changed, 36 insertions(+), 35 deletions(-)
include/net/ip_vs.h +1 -1
@@ -1577,7 +1577,7 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)void ip_vs_nat_icmp (struct sk_buff *skb,struct ip_vs_protocol *pp,struct ip_vs_conn *cp,int dir,unsigned int toff, -bool has_ports); +bool has_ports,struct ip_vs_iphdr *ciph);#ifdef CONFIG_IP_VS_IPV6 void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
net/netfilter/ipvs/ip_vs_core.c +34 -33
180 lines not on this page · raw message
net/netfilter/ipvs/ip_vs_xmit.c +1 -1
@@ -1591,7 +1591,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,if (skb_cow (skb, rt->dst.dev->hard_header_len)) goto tx_error; -ip_vs_nat_icmp (skb, pp, cp,0 , toff, has_ports); +ip_vs_nat_icmp (skb, pp, cp,0 , toff, has_ports, ciph);/* Another hack: avoid icmp_send in ip_fragment */ skb->ignore_df =1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 494/609 ipvs: return the csum validation for forward hook
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Anastasov <[email protected]>
[ Upstream commit 99609cb0aa789c8d071050ce8579989551882cc6 ]
Sashiko notes that playing games with the skb dst and rt flags instead of providing hooknum is not a good idea when validating the checksums.
Also, skipping checksum validation for FORWARD packets risk silent data corruption, even if the only user is the FTP-CMD packets coming from the real server.
Sashiko also noticed that by using common checksum helper in the previous commit we actually fixed old bug where the TCP/UDP checksum for IPv6 on CHECKSUM_COMPLETE was not validated correctly.
--- include/net/ip_vs.h | 19 +++++-------------- net/netfilter/ipvs/ip_vs_proto_sctp.c | 2 +- 2 files changed, 6 insertions(+), 15 deletions(-)
include/net/ip_vs.h +5 -14
@@ -24,9 +24,7 @@#include <linux/netfilter.h> /* for union nf_inet_addr */ #include <linux/ip.h> #include <linux/ipv6.h> /* for struct ipv6hdr */ -#include <net/route.h> #include <net/ipv6.h> -#include <net/ip6_fib.h> #if IS_ENABLED (CONFIG_NF_CONNTRACK )#include <net/netfilter/nf_conntrack.h> #endif
@@ -1610,30 +1608,23 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)return csum_partial (diff,sizeof (diff), oldsum); } -static inline bool ip_vs_checksum_needed (struct sk_buff *skb,int af) +static inline bool ip_vs_checksum_needed (struct sk_buff *skb) {/* Checksum unnecessary or already validated? */ if (skb_csum_unnecessary (skb))return false; -/* LOCAL_OUT ? */ -if (!skb->dev || skb->dev->flags &IFF_LOOPBACK ) +/* Locally generated ? */ +if (!skb->dev)return false; -/* !LOCAL_IN (FORWARD) ? */ -if (af ==AF_INET6 ) { -if (!(dst_rt6_info (skb_dst (skb))->rt6i_flags &RTF_LOCAL )) -return false; - }else { -if (!(skb_rtable (skb)->rt_flags &RTCF_LOCAL )) -return false; - }return true; }static inline bool ip_vs_checksum_common_check (struct sk_buff *skb,int offset,int proto,int af) { -if (!ip_vs_checksum_needed (skb, af)) +if (!ip_vs_checksum_needed (skb))return true; +/* Validate csum even for FORWARD */ return !nf_checksum (skb,NF_INET_LOCAL_IN , offset, proto, af); }
net/netfilter/ipvs/ip_vs_proto_sctp.c +1 -1
@@ -193,7 +193,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,struct sctphdr *sh;__le32 cmp, val; -if (!ip_vs_checksum_needed (skb, af)) +if (!ip_vs_checksum_needed (skb))return 1 ; sh = (struct sctphdr *)(skb->data + sctphoff); cmp = sh->checksum;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 495/609 btrfs: fix memory leak in btrfs_do_encoded_write()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Antipov <[email protected]>
[ Upstream commit d2a4e4e626b2f4670b69b430c357f03f53eb6632 ]
Local fuzzing of 6.12.94 has found the following memory leak:
Unreferenced object 0xffff888018050a80 (size 64):
comm "syz.0.17", pid 10297, jiffies 4294953601 hex dump (first 32 bytes):
00 10 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
10 0a 05 18 80 88 ff ff 10 0a 05 18 80 88 ff ff ................
backtrace (crc a8a6fc29):
kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
slab_post_alloc_hook mm/slub.c:4152 [inline]
slab_alloc_node mm/slub.c:4197 [inline]
__kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
kmalloc_noprof include/linux/slab.h:878 [inline]
extent_changeset_alloc fs/btrfs/extent_io.h:207 [inline]
qgroup_reserve_data+0x1c5/0x7d0 fs/btrfs/qgroup.c:4305
btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:906 [inline]
__se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
do_syscall_x64 arch/x86/entry/common.c:47 [inline]
do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
entry_SYSCALL_64_after_hwframe+0x77/0x7fUnreferenced object 0xffff888018050a00 (size 64):
comm "syz.0.17", pid 10297, jiffies 4294953601 hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 ff 0f 00 00 00 00 00 00 ................
90 0a 05 18 80 88 ff ff 90 0a 05 18 80 88 ff ff ................
backtrace (crc cb5c9580):
kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
slab_post_alloc_hook mm/slub.c:4152 [inline]
slab_alloc_node mm/slub.c:4197 [inline]
__kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
kmalloc_noprof include/linux/slab.h:878 [inline]
kzalloc_noprof include/linux/slab.h:1014 [inline]
ulist_prealloc+0x9c/0x110 fs/btrfs/ulist.c:114
extent_changeset_prealloc fs/btrfs/extent_io.h:217 [inline]
__set_extent_bit+0x16b/0x1a70 fs/btrfs/extent-io-tree.c:1086
set_record_extent_bits+0x50/0x90 fs/btrfs/extent-io-tree.c:1821
qgroup_reserve_data+0x274/0x7d0 fs/btrfs/qgroup.c:4312
btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:906 [inline]
__se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
do_syscall_x64 arch/x86/entry/common.c:47 [inline]
do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
entry_SYSCALL_64_after_hwframe+0x77/0x7fFix this by freeing an extent changeset before returning from btrfs_do_encoded_write().
--- fs/btrfs/inode.c | 1 + 1 file changed, 1 insertion(+)
fs/btrfs/inode.c +1 -0
@@ -11181,6 +11181,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from, }kvfree (pages); out: +extent_changeset_free (data_reserved);if (ret >=0 ) iocb->ki_pos += encoded->len;return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 496/609 bpf: Preserve pointer state for commuted arithmetic
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yiyang Chen <[email protected]>
[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]
When scalar += pointer is handled in adjust_ptr_min_max_vals(), the destination register inherits the pointer state from the source pointer. Copying only selected fields is fragile because pointer provenance is tracked by several bpf_reg_state fields.
Use the caller's temporary offset register to preserve the scalar operand while replacing the destination with the full pointer state. This preserves the frame number for PTR_TO_STACK registers and keeps parent identity fields consistent.
--- kernel/bpf/verifier.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
kernel/bpf/verifier.c +8 -7
@@ -8491,11 +8491,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,break ; } -/* In case of 'scalar += pointer', dst_reg inherits pointer type and id. -* The id may be overwritten later if we create a new variable offset. +/* For 'scalar += pointer', dst_reg inherits the complete pointer +* register state. Individual fields may be adjusted later by pointer +* arithmetic. Callers guarantee that below does not overwrite off_reg. */ - dst_reg->type = ptr_reg->type; - dst_reg->id = ptr_reg->id; +if (dst_reg != ptr_reg) + *dst_reg = *ptr_reg;if (!check_reg_sane_offset (env, off_reg, ptr_reg->type) || !check_reg_sane_offset (env, ptr_reg, ptr_reg->type))
@@ -8563,7 +8564,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, }break ;case BPF_SUB : -if (dst_reg == off_reg) { +if (dst_reg != ptr_reg) {/* scalar -= pointer. Creates an unknown scalar */ verbose (env,"R%d tried to subtract pointer from scalar\n" , dst);
@@ -9422,8 +9423,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, err =mark_chain_precision (env, insn->dst_reg);if (err)return err; -return adjust_ptr_min_max_vals (env, insn, - src_reg, dst_reg); + off_reg = *dst_reg; +return adjust_ptr_min_max_vals (env, insn, src_reg, &off_reg); } }else if (ptr_reg) {/* pointer += scalar */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 497/609 net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in smc_llc_event_handler()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mahanta Jambigi <[email protected]>
[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]
The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in smc_llc_event_handler() stores an incoming qentry into the local LLC flow without first checking whether a qentry is already pending. If a malicious or buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the pointer without freeing the previous allocation, leaking one kmalloc-96 object per spurious message.
The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a duplicate message when qentry is already occupied falls through to break and is freed by the kfree(qentry) at the out: label, rather than silently leaking the existing allocation.
The response direction (smc_llc_rx_response()) is unaffected: it already guards with flow->qentry at the equivalent site and drops duplicate responses correctly.
--- net/smc/smc_llc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/smc/smc_llc.c +2 -1
@@ -1901,7 +1901,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)return ;case SMC_LLC_CONFIRM_LINK :case SMC_LLC_ADD_LINK_CONT : -if (lgr->llc_flow_lcl.type !=SMC_LLC_FLOW_NONE ) { +if (lgr->llc_flow_lcl.type !=SMC_LLC_FLOW_NONE && + !lgr->llc_flow_lcl.qentry) {/* a flow is waiting for this message */ smc_llc_flow_qentry_set (&lgr->llc_flow_lcl, qentry);wake_up (&lgr->llc_msg_waiter);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 498/609 net/sched: cls_route: fix fastmap use-after-free on filter
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]
The route4 classifier maintains a 16-slot fastmap cache that stores raw struct route4_filter pointers indexed by (id, iif). The reader (route4_classify) populates this cache via route4_set_fastmap() for every classified packet that hits a filter. The writer (route4_delete, route4_change) clears the cache via route4_reset_fastmap() before RCU-deferred kfree of the filter.
This creates a UAF race:
1. Reader walks the RCU-protected bucket chain, finds filter f
2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
3. Reader calls route4_set_fastmap() and writes f into the cache *after* the writer's reset, caching a pointer about to be freed
4. After the RCU grace period, kfree(f) executes
5. Next classified packet on the same (id, iif) tuple hits the stale
fastmap entry and reads f->res from freed memory
Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a concurrent add/delete stress test (provided by both zdi and Santosh). Both triggered KASAN slab-use-after-free reports in the route4 fastmap paths.
Fix:
Introduce a per-filter boolean dying flag to suppress stale fastmap republishing by in-flight readers.
--- net/sched/cls_route.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-)
net/sched/cls_route.c +26 -9
@@ -51,6 +51,7 @@ struct route4_filter {struct tcf_result res;struct tcf_exts exts;u32 handle; +bool dying;struct route4_bucket *bkt;struct tcf_proto *tp;struct rcu_work rwork;
@@ -65,9 +66,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)static DEFINE_SPINLOCK (fastmap_lock);static void -route4_reset_fastmap (struct route4_head *head) +route4_reset_fastmap (struct route4_head *head,struct route4_filter *f) {spin_lock_bh (&fastmap_lock); +if (f) + f->dying = true;memset (head->fastmap,0 ,sizeof (head->fastmap));spin_unlock_bh (&fastmap_lock); }
@@ -80,9 +83,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,/* fastmap updates must look atomic to aling id, iff, filter */ spin_lock_bh (&fastmap_lock); - head->fastmap[h].id = id; - head->fastmap[h].iif = iif; - head->fastmap[h].filter = f; +if (f ==ROUTE4_FAILURE || !f->dying) { + head->fastmap[h].id = id; + head->fastmap[h].iif = iif; + head->fastmap[h].filter = f; + }spin_unlock_bh (&fastmap_lock); }
@@ -295,6 +300,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held, next =rtnl_dereference (f->next);RCU_INIT_POINTER (b->ht[h2], next);tcf_unbind_filter (tp, &f->res); +/* Mark the filter dying under fastmap_lock so +* any in-flight reader that still holds it +* will skip the republish in route4_set_fastmap(). +*/ +spin_lock_bh (&fastmap_lock); + f->dying = true; +spin_unlock_bh (&fastmap_lock);if (tcf_exts_get_net (&f->exts))route4_queue_work (f);else
@@ -305,6 +317,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,kfree_rcu (b, rcu); } } + +/* All filters are unlinked and marked dying, so no in-flight +* reader can republish a stale entry after this reset. +*/ +route4_reset_fastmap (head,NULL );kfree_rcu (head, rcu); }
@@ -332,11 +349,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,/* unlink it */ RCU_INIT_POINTER (*fp,rtnl_dereference (f->next)); -/* Remove any fastmap lookups that might ref filter -* notice we unlink'd the filter so we can't get it -* back in the fastmap. +/* Clear any fastmap entries that may ref this filter and +* mark it dying so in-flight readers can't republish it +* after the reset. */ -route4_reset_fastmap (head); +route4_reset_fastmap (head, f);/* Delete it */ tcf_unbind_filter (tp, &f->res);
@@ -551,7 +568,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, } } -route4_reset_fastmap (head); +route4_reset_fastmap (head, fold); *arg = f;if (fold) {tcf_unbind_filter (tp, &fold->res);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 499/609 net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiawen Liu <[email protected]>
[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]
hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev(). This is not needed because free_netdev() deletes all NAPI instances attached to the net_device.
Remove the redundant call and let the networking core tear down the NAPI instance during unregister_netdev(). The probe error path still keeps its explicit netif_napi_del(), because the device has not been registered there.
--- drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +0 -1
@@ -1288,7 +1288,6 @@ static int hix5hd2_dev_remove(struct platform_device *pdev)struct net_device *ndev =platform_get_drvdata (pdev);struct hix5hd2_priv *priv =netdev_priv (ndev); -netif_napi_del (&priv->napi);unregister_netdev (ndev);mdiobus_unregister (priv->bus);mdiobus_free (priv->bus);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 500/609 net/mlx5: fw_tracer, return NULL on create error
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Guralnik <[email protected]>
[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]
Tracer creation can fail by returning either NULL or ERR_PTR. The return value is stored without a check on the device, and users treat ERR_PTR and NULL the same way.
This also causes a crash in the core dump logic, which is missing the ERR_PTR check and ends up dereferencing it, as shown in the trace below.
Switch tracer creation to return NULL on failure only, so callers only need a single NULL check.
Internal error: Oops: 0000000096000006 [#1] SMP Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none) Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core] pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--) pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core] sp : ffff800081cf3c40 x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000 x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05 x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000 x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0 x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650 x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8 x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000 x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030 x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e Call trace: mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P) mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core] devlink_health_do_dump+0x9c/0x160 devlink_health_report+0x1c0/0x288 mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core] process_one_work+0x15c/0x3d8 worker_thread+0x18c/0x320 kthread+0x148/0x228 ret_from_fork+0x10/0x20 Code: b9400000 5ac00800 7a401800 540003ca (3940a260) ---[ end trace 0000000000000000 ]--- Kernel panic - not syncing: Oops: Fatal exception SMP: stopping secondary CPUs Kernel Offset: disabled CPU features: 0x000000,00078031,75fce5a1,35fffe67 Memory Limit: none ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
--- .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +7 -9
@@ -1036,13 +1036,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev) tracer =kvzalloc (sizeof (*tracer),GFP_KERNEL );if (!tracer) -return ERR_PTR (-ENOMEM ); +return NULL ; tracer->work_queue =create_singlethread_workqueue ("mlx5_fw_tracer" ); -if (!tracer->work_queue) { - err = -ENOMEM ; +if (!tracer->work_queue) goto free_tracer; - } tracer->dev = dev;
@@ -1082,7 +1080,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)destroy_workqueue (tracer->work_queue); free_tracer:kvfree (tracer); -return ERR_PTR (err); +return NULL ; }static int fw_tracer_event (struct notifier_block *nb,unsigned long action,void *data);
@@ -1093,7 +1091,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)struct mlx5_core_dev *dev;int err; -if (IS_ERR_OR_NULL (tracer)) +if (!tracer)return 0 ; dev = tracer->dev;
@@ -1136,7 +1134,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)/* Stop tracer + Cleanup HW resources */ void mlx5_fw_tracer_cleanup (struct mlx5_fw_tracer *tracer) { -if (IS_ERR_OR_NULL (tracer)) +if (!tracer)return ; mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n",
@@ -1155,7 +1153,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)/* Free software resources (Buffers, etc ..) */ void mlx5_fw_tracer_destroy (struct mlx5_fw_tracer *tracer) { -if (IS_ERR_OR_NULL (tracer)) +if (!tracer)return ;mlx5_core_dbg (tracer->dev,"FWTracer: Destroy\n" );
@@ -1203,7 +1201,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)struct mlx5_core_dev *dev;int err; -if (IS_ERR_OR_NULL (tracer)) +if (!tracer)return 0 ; dev = tracer->dev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 501/609 counter: microchip-tcb-capture: Fix DT channel validation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Babanpreet Singh <[email protected]>
[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]
mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API contract of of_property_read_u32_index() - into a signed int, so the bounds check "channel > 2" fails to reject cell values at or above 0x80000000: reinterpreted as a negative int, they compare below 2 and pass validation.
A malformed devicetree can therefore drive a negative channel into the ATMEL_TC_REG() offset arithmetic, making the driver access syscon regmap offsets outside the TC block's register window, and into the "t%d_clk" clock-name formatting, where it truncates clk_name (sized for "t0_clk".."t2_clk").
Declare channel as u32, matching the API contract; the unsigned comparison then rejects everything except channels 0..2. Adjust the format specifier to %u accordingly, which also resolves the W=1 warning that exposed the gap:
microchip-tcb-capture.c:520:56: warning: '%d' directive output may
be truncated writing between 1 and 11 bytes into a region of size 6 [-Wformat-truncation=]
note: directive argument in the range [-2147483648, 2]
No behavior change for well-formed devicetrees: channels 0..2 take identical paths before and after.
--- drivers/counter/microchip-tcb-capture.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/counter/microchip-tcb-capture.c +2 -2
@@ -310,7 +310,7 @@ static int mchp_tc_probe(struct platform_device *pdev)char clk_name[7 ];struct regmap *regmap;struct clk *clk[3 ]; -int channel; +u32 channel;int ret, i; counter =devm_counter_alloc (&pdev->dev,sizeof (*priv));
@@ -344,7 +344,7 @@ static int mchp_tc_probe(struct platform_device *pdev) priv->channel[i] = channel; -snprintf (clk_name,sizeof (clk_name),"t%d_clk" , channel); +snprintf (clk_name,sizeof (clk_name),"t%u_clk" , channel); clk[i] =of_clk_get_by_name (np->parent, clk_name);if (IS_ERR (clk[i])) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 502/609 tcp: add a scheduling point in established_get_first()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jian Wen <[email protected]>
[ Upstream commit 9f4a7c930284bf2b5b84d3636a8e88857149328f ]
Kubernetes[1] is going to stick with /proc/net/tcp for a while.
This commit reduces the scheduling latency introduced by established_get_first(), similar to commit acffb584cda7 ("net: diag:
add a scheduling point in inet_diag_dump_icsk()").
In our environment, the scheduling latency affects the performance of latency-sensitive services like Redis.
Changes in V2 :
- call cond_resched() before checking if a bucket is empty as suggested by Eric Dumazet
- removed the delay of synchronize_net() from the commit message
[1] https://github.com/google/cadvisor/blob/v0.47.2/container/libcontainer/handler.go#L130
Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
--- net/ipv4/tcp_ipv4.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv4/tcp_ipv4.c +3 -0
@@ -57,6 +57,7 @@#include <linux/init.h> #include <linux/times.h> #include <linux/slab.h> +#include <linux/sched.h> #include <net/net_namespace.h> #include <net/icmp.h>
@@ -2412,6 +2413,8 @@ static void *established_get_first(struct seq_file *seq)struct hlist_nulls_node *node;spinlock_t *lock =inet_ehash_lockp (hinfo, st->bucket); +cond_resched (); +/* Lockless fast path for the common case of empty buckets */ if (empty_bucket (hinfo, st))continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 503/609 bpf: tcp: Make mem flags configurable through bpf_iter_tcp_realloc_batch
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jordan Rife <[email protected]>
[ Upstream commit 8271bec9fc1cfe522b1a18cacbefd6712a3d41c2 ]
Prepare for the next patch which needs to be able to choose either GFP_USER or GFP_NOWAIT for calls to bpf_iter_tcp_realloc_batch.
Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
--- net/ipv4/tcp_ipv4.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
net/ipv4/tcp_ipv4.c +5 -4
@@ -2759,12 +2759,12 @@ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter) }static int bpf_iter_tcp_realloc_batch (struct bpf_tcp_iter_state *iter, -unsigned int new_batch_sz) +unsigned int new_batch_sz,gfp_t flags) {struct sock **new_batch; new_batch =kvmalloc (sizeof (*new_batch) * new_batch_sz, -GFP_USER | __GFP_NOWARN); + flags | __GFP_NOWARN);if (!new_batch)return -ENOMEM ;
@@ -2876,7 +2876,8 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)return sk; } -if (!resized && !bpf_iter_tcp_realloc_batch (iter, expected *3 /2 )) { +if (!resized && !bpf_iter_tcp_realloc_batch (iter, expected *3 /2 , +GFP_USER )) { resized = true; goto again; }
@@ -3293,7 +3294,7 @@ static int bpf_iter_init_tcp(void *priv_data, struct bpf_iter_aux_info *aux)if (err)return err; - err =bpf_iter_tcp_realloc_batch (iter,INIT_BATCH_SZ ); + err =bpf_iter_tcp_realloc_batch (iter,INIT_BATCH_SZ ,GFP_USER );if (err) {bpf_iter_fini_seq_net (priv_data);return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 504/609 bpf: tcp: Make sure iter->batch always contains a full bucket snapshot
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jordan Rife <[email protected]>
[ Upstream commit cdec67a489d4fdae3e83e04fca0419136a83c4c2 ]
Require that iter->batch always contains a full bucket snapshot. This invariant is important to avoid skipping or repeating sockets during iteration when combined with the next few patches. Before, there were two cases where a call to bpf_iter_tcp_batch may only capture part of a bucket:
1. When bpf_iter_tcp_realloc_batch() returns -ENOMEM.
2. When more sockets are added to the bucket while calling bpf_iter_tcp_realloc_batch(), making the updated batch size insufficient.
In cases where the batch size only covers part of a bucket, it is possible to forget which sockets were already visited, especially if we have to process a bucket in more than two batches. This forces us to choose between repeating or skipping sockets, so don't allow this:
1. Stop iteration and propagate -ENOMEM up to userspace if reallocation fails instead of continuing with a partial batch.
2. Try bpf_iter_tcp_realloc_batch() with GFP_USER just as before, but if we still aren't able to capture the full bucket, call bpf_iter_tcp_realloc_batch() again while holding the bucket lock to guarantee the bucket does not change. On the second attempt use GFP_NOWAIT since we hold onto the spin lock.
I did some manual testing to exercise the code paths where GFP_NOWAIT is used and where ERR_PTR(err) is returned. I used the realloc test cases included later in this series to trigger a scenario where a realloc happens inside bpf_iter_tcp_batch and made a small code tweak to force the first realloc attempt to allocate a too-small batch, thus requiring another attempt with GFP_NOWAIT. Some printks showed both reallocs with the tests passing:
Jun 27 00:00:53 crow kernel: again GFP_USER Jun 27 00:00:53 crow kernel: again GFP_NOWAIT Jun 27 00:00:53 crow kernel: again GFP_USER Jun 27 00:00:53 crow kernel: again GFP_NOWAIT
With this setup, I also forced each of the bpf_iter_tcp_realloc_batch calls to return -ENOMEM to ensure that iteration ends and that the read() in userspace fails.
Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
--- net/ipv4/tcp_ipv4.c | 109 +++++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 32 deletions(-)
net/ipv4/tcp_ipv4.c +77 -32
@@ -2768,7 +2768,7 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,if (!new_batch)return -ENOMEM ; -bpf_iter_tcp_put_batch (iter); +memcpy (new_batch, iter->batch,sizeof (*iter->batch) * iter->end_sk);kvfree (iter->batch); iter->batch = new_batch; iter->max_sk = new_batch_sz;
@@ -2777,69 +2777,95 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter, }static unsigned int bpf_iter_tcp_listening_batch (struct seq_file *seq, -struct sock *start_sk) +struct sock **start_sk) { -struct inet_hashinfo *hinfo =seq_file_net (seq)->ipv4.tcp_death_row.hashinfo;struct bpf_tcp_iter_state *iter = seq->private; -struct tcp_iter_state *st = &iter->state;struct hlist_nulls_node *node;unsigned int expected =1 ;struct sock *sk; -sock_hold (start_sk); - iter->batch[iter->end_sk++] = start_sk; +sock_hold (*start_sk); + iter->batch[iter->end_sk++] = *start_sk; - sk =sk_nulls_next (start_sk); + sk =sk_nulls_next (*start_sk); + *start_sk =NULL ;sk_nulls_for_each_from (sk, node) {if (seq_sk_match (seq, sk)) {if (iter->end_sk < iter->max_sk) {sock_hold (sk); iter->batch[iter->end_sk++] = sk; + }else if (!*start_sk) { +/* Remember where we left off. */ + *start_sk = sk; } expected++; } } -spin_unlock (&hinfo->lhash2[st->bucket].lock);return expected; }static unsigned int bpf_iter_tcp_established_batch (struct seq_file *seq, -struct sock *start_sk) +struct sock **start_sk) { -struct inet_hashinfo *hinfo =seq_file_net (seq)->ipv4.tcp_death_row.hashinfo;struct bpf_tcp_iter_state *iter = seq->private; -struct tcp_iter_state *st = &iter->state;struct hlist_nulls_node *node;unsigned int expected =1 ;struct sock *sk; -sock_hold (start_sk); - iter->batch[iter->end_sk++] = start_sk; +sock_hold (*start_sk); + iter->batch[iter->end_sk++] = *start_sk; - sk =sk_nulls_next (start_sk); + sk =sk_nulls_next (*start_sk); + *start_sk =NULL ;sk_nulls_for_each_from (sk, node) {if (seq_sk_match (seq, sk)) {if (iter->end_sk < iter->max_sk) {sock_hold (sk); iter->batch[iter->end_sk++] = sk; + }else if (!*start_sk) { +/* Remember where we left off. */ + *start_sk = sk; } expected++; } } -spin_unlock_bh (inet_ehash_lockp (hinfo, st->bucket));return expected; } +static unsigned int bpf_iter_fill_batch (struct seq_file *seq, +struct sock **start_sk) +{ +struct bpf_tcp_iter_state *iter = seq->private; +struct tcp_iter_state *st = &iter->state; + +if (st->state ==TCP_SEQ_STATE_LISTENING ) +return bpf_iter_tcp_listening_batch (seq, start_sk); +else +return bpf_iter_tcp_established_batch (seq, start_sk); +} + +static void bpf_iter_tcp_unlock_bucket (struct seq_file *seq) +{ +struct inet_hashinfo *hinfo =seq_file_net (seq)->ipv4.tcp_death_row.hashinfo; +struct bpf_tcp_iter_state *iter = seq->private; +struct tcp_iter_state *st = &iter->state; + +if (st->state ==TCP_SEQ_STATE_LISTENING ) +spin_unlock (&hinfo->lhash2[st->bucket].lock); +else +spin_unlock_bh (inet_ehash_lockp (hinfo, st->bucket)); +} +static struct sock *bpf_iter_tcp_batch (struct seq_file *seq) {struct inet_hashinfo *hinfo =seq_file_net (seq)->ipv4.tcp_death_row.hashinfo;struct bpf_tcp_iter_state *iter = seq->private;struct tcp_iter_state *st = &iter->state;unsigned int expected; -bool resized = false;struct sock *sk; +int err;/* The st->bucket is done. Directly advance to the next * bucket instead of having the tcp_seek_last_pos() to skip
@@ -2856,33 +2882,52 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq) } } -again: -/* Get a new batch */ iter->cur_sk =0 ; iter->end_sk =0 ; - iter->st_bucket_done = false; + iter->st_bucket_done = true; sk =tcp_seek_last_pos (seq);if (!sk)return NULL ;/* Done */ -if (st->state ==TCP_SEQ_STATE_LISTENING ) - expected =bpf_iter_tcp_listening_batch (seq, sk); -else - expected =bpf_iter_tcp_established_batch (seq, sk); + expected =bpf_iter_fill_batch (seq, &sk); +if (likely (iter->end_sk == expected)) + goto done; -if (iter->end_sk == expected) { - iter->st_bucket_done = true; -return sk; - } +/* Batch size was too small. */ +bpf_iter_tcp_unlock_bucket (seq); +bpf_iter_tcp_put_batch (iter); + err =bpf_iter_tcp_realloc_batch (iter, expected *3 /2 , +GFP_USER ); +if (err) +return ERR_PTR (err); + + iter->cur_sk =0 ; + iter->end_sk =0 ; + + sk =tcp_seek_last_pos (seq); +if (!sk) +return NULL ;/* Done */ + + expected =bpf_iter_fill_batch (seq, &sk); +if (likely (iter->end_sk == expected)) + goto done; -if (!resized && !bpf_iter_tcp_realloc_batch (iter, expected *3 /2 , -GFP_USER )) { - resized = true; - goto again; +/* Batch size was still too small. Hold onto the lock while we try +* again with a larger batch to make sure the current bucket's size +* does not change in the meantime. +*/ + err =bpf_iter_tcp_realloc_batch (iter, expected,GFP_NOWAIT ); +if (err) { +bpf_iter_tcp_unlock_bucket (seq); +return ERR_PTR (err); } -return sk; + expected =bpf_iter_fill_batch (seq, &sk); +WARN_ON_ONCE (iter->end_sk != expected); +done: +bpf_iter_tcp_unlock_bucket (seq); +return iter->batch[0 ]; }static void *bpf_iter_tcp_seq_start (struct seq_file *seq,loff_t *pos)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 505/609 bpf: tcp: Get rid of st_bucket_done
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jordan Rife <[email protected]>
[ Upstream commit e25ab9b874a4bd8c6e3e5ce66cbe8a1dd4096e2e ]
Get rid of the st_bucket_done field to simplify TCP iterator state and logic. Before, st_bucket_done could be false if bpf_iter_tcp_batch returned a partial batch; however, with the last patch ("bpf: tcp: Make sure iter->batch always contains a full bucket snapshot"), st_bucket_done == true is equivalent to iter->cur_sk == iter->end_sk.
Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
--- net/ipv4/tcp_ipv4.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
net/ipv4/tcp_ipv4.c +6 -8
@@ -2731,7 +2731,6 @@ struct bpf_tcp_iter_state {unsigned int end_sk;unsigned int max_sk;struct sock **batch; -bool st_bucket_done; };struct bpf_iter__tcp {
@@ -2754,8 +2753,10 @@ static int tcp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,static void bpf_iter_tcp_put_batch (struct bpf_tcp_iter_state *iter) { -while (iter->cur_sk < iter->end_sk) -sock_gen_put (iter->batch[iter->cur_sk++]); +unsigned int cur_sk = iter->cur_sk; + +while (cur_sk < iter->end_sk) +sock_gen_put (iter->batch[cur_sk++]); } static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
@@ -2872,7 +2873,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)* one by one in the current bucket and eventually find out * it has to advance to the next bucket. */ -if (iter->st_bucket_done) { +if (iter->end_sk && iter->cur_sk == iter->end_sk) { st->offset =0 ; st->bucket++; if (st->state == TCP_SEQ_STATE_LISTENING &&
@@ -2884,7 +2885,6 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq) iter->cur_sk =0 ; iter->end_sk =0 ; - iter->st_bucket_done = true; sk =tcp_seek_last_pos (seq);if (!sk)
@@ -3032,10 +3032,8 @@ static void bpf_iter_tcp_seq_stop(struct seq_file *seq, void *v) (void )tcp_prog_seq_show (prog, &meta, v,0 ); } -if (iter->cur_sk < iter->end_sk) { +if (iter->cur_sk < iter->end_sk)bpf_iter_tcp_put_batch (iter); - iter->st_bucket_done = false; - } }static const struct seq_operations bpf_iter_tcp_seq_ops = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 506/609 bpf: tcp: Use bpf_tcp_iter_batch_item for bpf_tcp_iter_state batch items
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jordan Rife <[email protected]>
[ Upstream commit efeb820951ebf3778830256496ff72d00d135310 ]
Prepare for the next patch that tracks cookies between iterations by converting struct sock **batch to union bpf_tcp_iter_batch_item *batch inside struct bpf_tcp_iter_state.
Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
--- net/ipv4/tcp_ipv4.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
net/ipv4/tcp_ipv4.c +14 -10
@@ -2725,12 +2725,16 @@ static int tcp4_seq_show(struct seq_file *seq, void *v) }#ifdef CONFIG_BPF_SYSCALL +union bpf_tcp_iter_batch_item { +struct sock *sk; +}; +struct bpf_tcp_iter_state {struct tcp_iter_state state;unsigned int cur_sk;unsigned int end_sk;unsigned int max_sk; -struct sock **batch; +union bpf_tcp_iter_batch_item *batch; }; struct bpf_iter__tcp {
@@ -2756,13 +2760,13 @@ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)unsigned int cur_sk = iter->cur_sk;while (cur_sk < iter->end_sk) -sock_gen_put (iter->batch[cur_sk++]); +sock_gen_put (iter->batch[cur_sk++].sk); }static int bpf_iter_tcp_realloc_batch (struct bpf_tcp_iter_state *iter,unsigned int new_batch_sz,gfp_t flags) { -struct sock **new_batch; +union bpf_tcp_iter_batch_item *new_batch; new_batch =kvmalloc (sizeof (*new_batch) * new_batch_sz, flags | __GFP_NOWARN);
@@ -2786,7 +2790,7 @@ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,struct sock *sk;sock_hold (*start_sk); - iter->batch[iter->end_sk++] = *start_sk; + iter->batch[iter->end_sk++].sk = *start_sk; sk =sk_nulls_next (*start_sk); *start_sk =NULL ;
@@ -2794,7 +2798,7 @@ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,if (seq_sk_match (seq, sk)) {if (iter->end_sk < iter->max_sk) {sock_hold (sk); - iter->batch[iter->end_sk++] = sk; + iter->batch[iter->end_sk++].sk = sk; }else if (!*start_sk) {/* Remember where we left off. */ *start_sk = sk;
@@ -2815,7 +2819,7 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,struct sock *sk;sock_hold (*start_sk); - iter->batch[iter->end_sk++] = *start_sk; + iter->batch[iter->end_sk++].sk = *start_sk; sk =sk_nulls_next (*start_sk); *start_sk =NULL ;
@@ -2823,7 +2827,7 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,if (seq_sk_match (seq, sk)) {if (iter->end_sk < iter->max_sk) {sock_hold (sk); - iter->batch[iter->end_sk++] = sk; + iter->batch[iter->end_sk++].sk = sk; }else if (!*start_sk) {/* Remember where we left off. */ *start_sk = sk;
@@ -2927,7 +2931,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)WARN_ON_ONCE (iter->end_sk != expected); done:bpf_iter_tcp_unlock_bucket (seq); -return iter->batch[0 ]; +return iter->batch[0 ].sk; }static void *bpf_iter_tcp_seq_start (struct seq_file *seq,loff_t *pos)
@@ -2962,11 +2966,11 @@ static void *bpf_iter_tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)* st->bucket. See tcp_seek_last_pos(). */ st->offset++; -sock_gen_put (iter->batch[iter->cur_sk++]); +sock_gen_put (iter->batch[iter->cur_sk++].sk); }if (iter->cur_sk < iter->end_sk) - sk = iter->batch[iter->cur_sk]; + sk = iter->batch[iter->cur_sk].sk;else sk =bpf_iter_tcp_batch (seq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 507/609 bpf: tcp: Avoid socket skips and repeats during iteration
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jordan Rife <[email protected]>
[ Upstream commit f5080f612a1c587bf636bb23d2a2f4de276d60e4 ]
Replace the offset-based approach for tracking progress through a bucket in the TCP table with one based on socket cookies. Remember the cookies of unprocessed sockets from the last batch and use this list to pick up where we left off or, in the case that the next socket disappears between reads, find the first socket after that point that still exists in the bucket and resume from there.
This approach guarantees that all sockets that existed when iteration began and continue to exist throughout will be visited exactly once. Sockets that are added to the table during iteration may or may not be seen, but if they are they will be seen exactly once.
Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
--- net/ipv4/tcp_ipv4.c | 147 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 32 deletions(-)
net/ipv4/tcp_ipv4.c +115 -32
@@ -58,6 +58,7 @@#include <linux/times.h> #include <linux/slab.h> #include <linux/sched.h> +#include <linux/sock_diag.h> #include <net/net_namespace.h> #include <net/icmp.h>
@@ -2727,6 +2728,7 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)#ifdef CONFIG_BPF_SYSCALL union bpf_tcp_iter_batch_item {struct sock *sk; +__u64 cookie; }; struct bpf_tcp_iter_state {
@@ -2757,10 +2759,19 @@ static int tcp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,static void bpf_iter_tcp_put_batch (struct bpf_tcp_iter_state *iter) { +union bpf_tcp_iter_batch_item *item;unsigned int cur_sk = iter->cur_sk; +__u64 cookie; -while (cur_sk < iter->end_sk) -sock_gen_put (iter->batch[cur_sk++].sk); +/* Remember the cookies of the sockets we haven't seen yet, so we can +* pick up where we left off next time around. +*/ +while (cur_sk < iter->end_sk) { + item = &iter->batch[cur_sk++]; + cookie =sock_gen_cookie (item->sk); +sock_gen_put (item->sk); + item->cookie = cookie; + } } static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
@@ -2781,6 +2792,106 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,return 0 ; } +static struct sock *bpf_iter_tcp_resume_bucket (struct sock *first_sk, +union bpf_tcp_iter_batch_item *cookies, +int n_cookies) +{ +struct hlist_nulls_node *node; +struct sock *sk; +int i; + +for (i =0 ; i < n_cookies; i++) { + sk = first_sk; +sk_nulls_for_each_from (sk, node) +if (cookies[i].cookie ==atomic64_read (&sk->sk_cookie)) +return sk; + } + +return NULL ; +} + +static struct sock *bpf_iter_tcp_resume_listening (struct seq_file *seq) +{ +struct inet_hashinfo *hinfo =seq_file_net (seq)->ipv4.tcp_death_row.hashinfo; +struct bpf_tcp_iter_state *iter = seq->private; +struct tcp_iter_state *st = &iter->state; +unsigned int find_cookie = iter->cur_sk; +unsigned int end_cookie = iter->end_sk; +int resume_bucket = st->bucket; +struct sock *sk; + +if (end_cookie && find_cookie == end_cookie) + ++st->bucket; + + sk =listening_get_first (seq); + iter->cur_sk =0 ; + iter->end_sk =0 ; + +if (sk && st->bucket == resume_bucket && end_cookie) { + sk =bpf_iter_tcp_resume_bucket (sk, &iter->batch[find_cookie], + end_cookie - find_cookie); +if (!sk) { +spin_unlock (&hinfo->lhash2[st->bucket].lock); + ++st->bucket; + sk =listening_get_first (seq); + } + } + +return sk; +} + +static struct sock *bpf_iter_tcp_resume_established (struct seq_file *seq) +{ +struct inet_hashinfo *hinfo =seq_file_net (seq)->ipv4.tcp_death_row.hashinfo; +struct bpf_tcp_iter_state *iter = seq->private; +struct tcp_iter_state *st = &iter->state; +unsigned int find_cookie = iter->cur_sk; +unsigned int end_cookie = iter->end_sk; +int resume_bucket = st->bucket; +struct sock *sk; + +if (end_cookie && find_cookie == end_cookie) + ++st->bucket; + + sk =established_get_first (seq); + iter->cur_sk =0 ; + iter->end_sk =0 ; + +if (sk && st->bucket == resume_bucket && end_cookie) { + sk =bpf_iter_tcp_resume_bucket (sk, &iter->batch[find_cookie], + end_cookie - find_cookie); +if (!sk) { +spin_unlock_bh (inet_ehash_lockp (hinfo, st->bucket)); + ++st->bucket; + sk =established_get_first (seq); + } + } + +return sk; +} + +static struct sock *bpf_iter_tcp_resume (struct seq_file *seq) +{ +struct bpf_tcp_iter_state *iter = seq->private; +struct tcp_iter_state *st = &iter->state; +struct sock *sk =NULL ; + +switch (st->state) { +case TCP_SEQ_STATE_LISTENING : + sk =bpf_iter_tcp_resume_listening (seq); +if (sk) +break ; + st->bucket =0 ; + st->state =TCP_SEQ_STATE_ESTABLISHED ; + fallthrough; +case TCP_SEQ_STATE_ESTABLISHED : + sk =bpf_iter_tcp_resume_established (seq); +break ; + } + +return sk; +} +static unsigned int bpf_iter_tcp_listening_batch (struct seq_file *seq,struct sock **start_sk) {
@@ -2865,32 +2976,12 @@ static void bpf_iter_tcp_unlock_bucket(struct seq_file *seq)static struct sock *bpf_iter_tcp_batch (struct seq_file *seq) { -struct inet_hashinfo *hinfo =seq_file_net (seq)->ipv4.tcp_death_row.hashinfo;struct bpf_tcp_iter_state *iter = seq->private; -struct tcp_iter_state *st = &iter->state;unsigned int expected;struct sock *sk;int err; -/* The st->bucket is done. Directly advance to the next -* bucket instead of having the tcp_seek_last_pos() to skip -* one by one in the current bucket and eventually find out -* it has to advance to the next bucket. -*/ -if (iter->end_sk && iter->cur_sk == iter->end_sk) { - st->offset =0 ; - st->bucket++; -if (st->state ==TCP_SEQ_STATE_LISTENING && - st->bucket > hinfo->lhash2_mask) { - st->state =TCP_SEQ_STATE_ESTABLISHED ; - st->bucket =0 ; - } - } - - iter->cur_sk =0 ; - iter->end_sk =0 ; - - sk =tcp_seek_last_pos (seq); + sk =bpf_iter_tcp_resume (seq);if (!sk)return NULL ;/* Done */
@@ -2906,10 +2997,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)if (err)return ERR_PTR (err); - iter->cur_sk =0 ; - iter->end_sk =0 ; - - sk =tcp_seek_last_pos (seq); + sk =bpf_iter_tcp_resume (seq);if (!sk)return NULL ;/* Done */
@@ -2961,11 +3049,6 @@ static void *bpf_iter_tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)* meta.seq_num is used instead. */ st->num++; -/* Move st->offset to the next sk in the bucket such that -* the future start() will resume at st->offset in -* st->bucket. See tcp_seek_last_pos(). -*/ - st->offset++;sock_gen_put (iter->batch[iter->cur_sk++].sk); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 508/609 bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jose Fernandez (Anthropic) <[email protected]>
[ Upstream commit e5fd3f514e27db1f05fbd72ba615d74941e23c51 ]
reqsk_queue_hash_req() publishes a TCP_NEW_SYN_RECV request_sock onto the ehash chain, drops the bucket lock, and only afterwards sets rsk_refcnt to 3.
Lockless readers such as __inet_lookup_established() handle this with refcount_inc_not_zero(), but bpf_iter_tcp_established_batch() uses plain sock_hold() while holding the bucket lock, on the assumption that the lock guarantees sk_refcnt > 0. That assumption does not hold for request_sock:
CPU 0 CPU 1
----- -----
tcp_conn_request()
reqsk_queue_hash_req()
inet_ehash_insert(req)
spin_lock(bucket)
__sk_nulls_add_node_rcu(req) // rsk_refcnt == 0
spin_unlock(bucket)
bpf_iter_tcp_established_batch()
spin_lock(bucket)
sock_hold(req) <-- addition on 0
spin_unlock(bucket)
refcount_set(&req->rsk_refcnt, 3) // clobbers saturated valuewhich surfaces as:
refcount_t: addition on 0; use-after-free.
WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x48/0x90, CPU#1 Call Trace: bpf_iter_tcp_established_batch+0x14e/0x170 bpf_iter_tcp_batch+0x53/0x200 bpf_iter_tcp_seq_next+0x27/0x70 bpf_seq_read+0x107/0x410 vfs_read+0xb9/0x380
The iterator's stolen reference is lost when the publishing CPU's refcount_set() overwrites the count, leaving the socket one reference short. When the last legitimate owner drops its reference the reqsk is freed while still reachable, leading to use-after-free.
This reproduces in seconds with tcp_syncookies=0, a handful of threads doing connect()/close() to a local listener while others read an iter/tcp link in a tight loop.
Use refcount_inc_not_zero() and skip the socket on failure. A skipped socket is still part of the bucket, so keep counting it in expected. The reallocations are sized from expected, and a request sock whose refcount gets published while the lock is held across the last realloc must already have room.
A skipped socket is counted in expected but never batched, so end_sk can be short of expected on a batch that is actually complete. Decide completeness by whether the walk left any socket behind instead. The WARN after the locked realloc checks the same, replacing an end_sk == expected check that could not hold on that path since commit cdec67a489d4 ("bpf: tcp: Make sure iter->batch always contains a full bucket snapshot").
If every matching socket in a bucket is mid-init (refcount 0), end_sk stays 0. Advance to the next bucket rather than returning a batch entry that was never filled this round.
--- net/ipv4/tcp_ipv4.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-)
net/ipv4/tcp_ipv4.c +24 -19
@@ -2926,24 +2926,24 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq, {struct bpf_tcp_iter_state *iter = seq->private;struct hlist_nulls_node *node; -unsigned int expected =1 ; -struct sock *sk; - -sock_hold (*start_sk); - iter->batch[iter->end_sk++].sk = *start_sk; +struct sock *sk = *start_sk; +unsigned int expected =0 ; - sk =sk_nulls_next (*start_sk); *start_sk =NULL ;sk_nulls_for_each_from (sk, node) { -if (seq_sk_match (seq, sk)) { -if (iter->end_sk < iter->max_sk) { -sock_hold (sk); - iter->batch[iter->end_sk++].sk = sk; - }else if (!*start_sk) { -/* Remember where we left off. */ - *start_sk = sk; - } - expected++; +if (!seq_sk_match (seq, sk)) +continue ; + expected++; +if (iter->end_sk < iter->max_sk) { +/* reqsk_queue_hash_req() inserts with sk_refcnt == 0 +* and refcount_set()s it after the bucket lock drops. +*/ +if (unlikely (!refcount_inc_not_zero (&sk->sk_refcnt))) +continue ; + iter->batch[iter->end_sk++].sk = sk; + }else if (!*start_sk) { +/* Remember where we left off. */ + *start_sk = sk; } }
@@ -2981,12 +2981,13 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)struct sock *sk;int err; +again: sk =bpf_iter_tcp_resume (seq);if (!sk)return NULL ;/* Done */ expected =bpf_iter_fill_batch (seq, &sk); -if (likely (iter->end_sk == expected)) +if (likely (!sk)) goto done;/* Batch size was too small. */
@@ -3002,7 +3003,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)return NULL ;/* Done */ expected =bpf_iter_fill_batch (seq, &sk); -if (likely (iter->end_sk == expected)) +if (likely (!sk)) goto done;/* Batch size was still too small. Hold onto the lock while we try
@@ -3015,10 +3016,14 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)return ERR_PTR (err); } - expected =bpf_iter_fill_batch (seq, &sk); -WARN_ON_ONCE (iter->end_sk != expected); +bpf_iter_fill_batch (seq, &sk); +WARN_ON_ONCE (sk); done:bpf_iter_tcp_unlock_bucket (seq); +if (unlikely (!iter->end_sk)) { + ++iter->state.bucket; + goto again; + }return iter->batch[0 ].sk; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 509/609 vhost/vdpa: reject overflowing PA map page counts on 32-bit
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yousef Alhouseen <[email protected]>
[ Upstream commit 0619aaa34c0c2a2dcb07f0e9c8a34e7efb8c4cdf ]
vhost_vdpa_pa_map() adds the IOVA page offset to the user-controlled map size before computing the number of pages to pin. On 32-bit systems, where unsigned long is narrower than u64, that addition can overflow and the code can pin and map fewer pages than the requested IOTLB range.
Reject sizes that overflow the unsigned long page-count calculation.
Message-ID: <CAMuQ4bX-iDvcUOPPY+NLz95tkRJYwWqvzAr=U48uNaub_HZLGw@mail.gmail.com>
--- drivers/vhost/vdpa.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/vhost/vdpa.c +8 -1
@@ -920,6 +920,7 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,unsigned int gup_flags =FOLL_LONGTERM ;unsigned long npages, cur_base, map_pfn, last_pfn =0 ;unsigned long lock_limit, sz2pin, nchunks, i; +unsigned long page_offset;u64 start = iova;long pinned;int ret =0 ;
@@ -932,7 +933,13 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,if (perm &VHOST_ACCESS_WO ) gup_flags |=FOLL_WRITE ; - npages =PFN_UP (size + (iova & ~PAGE_MASK )); + page_offset = iova & ~PAGE_MASK ; +if (size >ULONG_MAX - page_offset) { + ret = -EINVAL ; + goto free; + } + + npages =PFN_UP (size + page_offset);if (!npages) { ret = -EINVAL ; goto free;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 510/609 udp: fix potential use-after-free in tunnel segmentation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]
__skb_udp_tunnel_segment() gets the UDP header before ensuring the tunnel header is in the skb head. If the pull reallocates skb->head, the saved UDP header pointer is no longer valid.
Get the UDP header after the pull to avoid a potential use-after-free.
--- net/ipv4/udp_offload.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/ipv4/udp_offload.c +3 -1
@@ -21,17 +21,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,int tnl_hlen =skb_inner_mac_header (skb) -skb_transport_header (skb);bool remcsum, need_csum, offload_csum, gso_partial;struct sk_buff *segs =ERR_PTR (-EINVAL ); -struct udphdr *uh =udp_hdr (skb);u16 mac_offset = skb->mac_header;__be16 protocol = skb->protocol;u16 mac_len = skb->mac_len;int udp_offset, outer_hlen; +struct udphdr *uh;__wsum partial;bool need_ipsec;if (unlikely (!pskb_may_pull (skb, tnl_hlen))) goto out; + uh =udp_hdr (skb); +/* Adjust partial header checksum to negate old length. * We cannot rely on the value contained in uh->len as it is * possible that the actual value exceeds the boundaries of the
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 511/609 net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK filter
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Toke Høiland-Jørgensen <[email protected]>
[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]
The sch_cake ACK filter parses packets to find the TCP header and filter duplicated ACKs if the flow is backlogged. The parsing code contains a WARN_ON(1) which can be triggered by a malformed IP header in certain cases. Depending on the system configuration, this leads either to either spamming dmesg with warnings, or a panic if panic_on_warn is set.
The code already correctly skips the offending packet in the branch that triggers the warning, so the WARN_ON itself doesn't really serve any purpose. So just drop it altogether to avoid the inconvenient side effects.
--- net/sched/sch_cake.c | 1 - 1 file changed, 1 deletion(-)
net/sched/sch_cake.c +0 -1
@@ -1281,7 +1281,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q, seglen =ntohs (ipv6h_check->payload_len); }else { -WARN_ON (1 );/* shouldn't happen */ continue ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 512/609 net/openvswitch: check Ethernet header length in key_extract()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft) <[email protected]>
[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]
When a packet arrives on an ARPHRD_NONE device (e.g. TUN), ovs_flow_key_extract() trusts the user-provided skb->protocol field: if it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes for MAC addresses and parse_ethertype() pulls 2 more, either of which triggers a kernel BUG in __skb_pull() when the linear area is too small.
kernel BUG at include/linux/skbuff.h:2848!
RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933 ovs_flow_key_extract+0x419/0xa70 ovs_vport_receive+0x222/0x390 netdev_frame_hook+0x3e0/0x630 tun_get_user+0x2d0c/0x38e0
Fixed by calling check_header() in key_extract() before accessing the Ethernet header.
--- net/openvswitch/flow.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
net/openvswitch/flow.c +7 -4
@@ -890,8 +890,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)* Ethernet header * @key: output flow key * -* The caller must ensure that skb->len >= ETH_HLEN. -* * Initializes @skb header fields as follows: * * - skb->mac_header: the L2 header.
@@ -911,8 +909,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)*/ static int key_extract (struct sk_buff *skb,struct sw_flow_key *key) { -struct ethhdr *eth; -/* Flags are always used as part of stats */ key->tp.flags =0 ;
@@ -927,6 +923,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)skb_reset_network_header (skb); key->eth.type = skb->protocol; }else { +struct ethhdr *eth; +int err; + + err =check_header (skb,ETH_HLEN ); +if (unlikely (err)) +return err; + eth =eth_hdr (skb);ether_addr_copy (key->eth.src, eth->h_source);ether_addr_copy (key->eth.dst, eth->h_dest);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 513/609 hwmon: (nzxt-smart2) Check return value of init_device() in probe
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingshuang Fu <[email protected]>
[ Upstream commit d533882ce1060866a590257f2c77ee23eabef5b8 ]
The init_device() call in nzxt_smart2_hid_probe() can fail because it sends HID output reports to the hardware to detect fans and set the update interval. If the hardware is not responding or the HID reports fail, init_device() returns a negative error code.
However, the return value was ignored, causing the probe to continue and register an hwmon device even though the device was never properly initialized. This leads to an inconsistent state where the driver reports stale data or blocks on wait queues that will never be woken.
The same function's return value is already checked in the reset_resume() handler, confirming the author's intent that errors should be propagated.
Note that this fix was not possible before commit 59d104b54b0b ("hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop") because the out_hw_close error path was missing hid_device_io_stop(), which would have opened a use-after-free risk window.
--- drivers/hwmon/nzxt-smart2.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/hwmon/nzxt-smart2.c +5 -1
@@ -754,7 +754,11 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,hid_device_io_start (hdev); -init_device (drvdata,UPDATE_INTERVAL_DEFAULT_MS ); + ret =init_device (drvdata,UPDATE_INTERVAL_DEFAULT_MS ); +if (ret) { +dev_err (&hdev->dev,"init_device failed: %d\n" , ret); + goto out_hw_close; + } drvdata->hwmon = hwmon_device_register_with_info(&hdev->dev, "nzxtsmart2", drvdata,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 514/609 hwmon: (lm25066) Use i2c_get_match_data()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rob Herring <[email protected]>
[ Upstream commit ac0c26bae662138eac9b49215e505b402f7e80e3 ]
Use preferred i2c_get_match_data() instead of of_match_device() and i2c_match_id() to get the driver match data. With this, adjust the includes to explicitly include the correct headers.
Adjust the 'chips' enum to not use 0, so that no match data can be distinguished from a valid enum value.
Stable-dep-of: 0dabe8a56f77 ("hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations")
--- drivers/hwmon/pmbus/lm25066.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-)
drivers/hwmon/pmbus/lm25066.c +3 -11
@@ -14,10 +14,10 @@#include <linux/slab.h> #include <linux/i2c.h> #include <linux/log2.h> -#include <linux/of_device.h> +#include <linux/of.h> #include "pmbus.h" -enum chips { lm25056, lm25066, lm5064, lm5066, lm5066i }; +enum chips { lm25056 =1 , lm25066, lm5064, lm5066, lm5066i };#define LM25066_READ_VAUX 0xd0#define LM25066_MFR_READ_IIN 0xd1
@@ -468,8 +468,6 @@ static int lm25066_probe(struct i2c_client *client)struct lm25066_data *data;struct pmbus_driver_info *info;const struct __coeff *coeff; -const struct of_device_id *of_id; -const struct i2c_device_id *i2c_id;if (!i2c_check_functionality (client->adapter,I2C_FUNC_SMBUS_READ_BYTE_DATA ))
@@ -484,14 +482,8 @@ static int lm25066_probe(struct i2c_client *client)if (config <0 )return config; - i2c_id =i2c_match_id (lm25066_id, client); + data->id = (enum chips )(unsigned long )i2c_get_match_data (client); - of_id =of_match_device (lm25066_of_match, &client->dev); -if (of_id && (unsigned long )of_id->data != i2c_id->driver_data) -dev_notice (&client->dev,"Device mismatch: %s in device tree, %s detected\n" , - of_id->name, i2c_id->name); - - data->id = i2c_id->driver_data; info = &data->info; info->pages =1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 515/609 hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 0dabe8a56f772f0ece46d2597799f412c277d874 ]
In lm25066_probe(), the PMBus coefficients for current and power are scaled based on the shunt resistor value. The calculation evaluates the multiplication using 32-bit arithmetic because info->m is an int and shunt is a u32:
static int lm25066_probe(struct i2c_client *client) {
...
info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
...
}For large coefficients like 26882 (LM25056) or 15076 (LM5066i), a device tree shunt-resistor-micro-ohms value exceeding approximately 159,000 (159 mOhm, which is physically valid for low-current applications) causes the intermediate product to exceed UINT_MAX (4,294,967,295). This results in a silent wraparound before the division by 1000.
Furthermore, if the wrapped value has the most significant bit set, converting it back to the signed int info->m results in negative coefficients. This logic error leads to drastically corrupted current and power readings, which can cause erratic thermal or power management behavior in the system.
Fix the problem by using 64-bit operations for the multiply/divide operations. This can still overflow, but only for unreasonably large shunt resistor values.
--- drivers/hwmon/pmbus/lm25066.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/hwmon/pmbus/lm25066.c +3 -2
@@ -14,6 +14,7 @@#include <linux/slab.h> #include <linux/i2c.h> #include <linux/log2.h> +#include <linux/math.h> #include <linux/of.h> #include "pmbus.h"
@@ -540,8 +541,8 @@ static int lm25066_probe(struct i2c_client *client)if (of_property_read_u32 (client->dev.of_node,"shunt-resistor-micro-ohms" , &shunt)) shunt =1000 ; - info->m[PSC_CURRENT_IN ] = info->m[PSC_CURRENT_IN ] * shunt /1000 ; - info->m[PSC_POWER ] = info->m[PSC_POWER ] * shunt /1000 ; + info->m[PSC_CURRENT_IN ] =DIV_ROUND_CLOSEST_ULL ((u64 )info->m[PSC_CURRENT_IN ] * shunt,1000 ); + info->m[PSC_POWER ] =DIV_ROUND_CLOSEST_ULL ((u64 )info->m[PSC_POWER ] * shunt,1000 );#if IS_ENABLED (CONFIG_SENSORS_LM25066_REGULATOR )/* LM25056 doesn't support OPERATION */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 516/609 selftests/ftrace: refactor eprobes test to fix argument checks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Kaiser <[email protected]>
[ Upstream commit 6e3abef2a27e7402a94111c9eff85d887e64a309 ]
The add/remove eprobe test installs an eprobe for the openat syscall and runs ls. It checks the filenames that were opened by ls against a whitelist and a blacklist.
Commit 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING pointer") fixed access to some string fields in eprobes. This triggers test failures as the blacklist does not allow relative paths for the openat parameters.
What makes this test unstable is the fact that the openat calls vary a lot between different systems.
Refactor the test to make it more robust. "cd <directory>" will issue a chdir syscall with the target directory as parameter. Set an eprobe on the sys_enter_chdir event and filter for the exact directory name. Allow (fault) as fallback.
--- .../ftrace/test.d/dynevent/add_remove_eprobe.tc | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-)
tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc +5 -11
@@ -1,16 +1,16 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 # description: Generic dynamic event - add/remove eprobe events -# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README +# requires: dynamic_events events/syscalls/sys_enter_chdir "<attached-group>.<attached-event> [<args>]":README echo 0 > events/enable clear_dynamic_events SYSTEM="syscalls" -EVENT="sys_enter_openat" +EVENT="sys_enter_chdir" FIELD="filename" -EPROBE="eprobe_open" +EPROBE="eprobe_chdir" OPTIONS="file=+0(\$filename):ustring" echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
@@ -18,20 +18,14 @@ grep -q "$EPROBE" dynamic_events test -d events/eprobes/$EPROBE echo 1 > events/eprobes/$EPROBE/enable -ls +cd /sys/kernel/tracing echo 0 > events/eprobes/$EPROBE/enable -content=`grep '^ *ls-' trace | grep 'file='` -nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."' -e '(fault)' ` || true - +content=`grep -e 'file="/sys/kernel/tracing"\|(fault)' trace` if [ -z "$content" ]; then exit_fail fi -if [ ! -z "$nocontent" ]; then - exit_fail -fi - echo "-:$EPROBE" >> dynamic_events ! grep -q "$EPROBE" dynamic_events
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 517/609 bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Chan <[email protected]>
[ Upstream commit 30f253f8d9a01d532fdb7ec6c8a9d4c15fe29241 ]
With End-of-Packet padding (EOP) set, the chip will disable Relaxed Ordering (RO) of TPA data packets. A TPA segment with EOP set will be padded to the next cache boundary and can potentially overwrite the beginning bytes of the next TPA segment when RO is enabled on 5760X. To prevent that, the chip disables RO for TPA when EOP is set.
To take advantge of RO and higher performance, do not set EOP on 5760X chips when TPA is enabled. Define a proper RX_BD_FLAGS_AGG_EOP constant to make it clear that we are setting EOP.
Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption")
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +8 -1
@@ -3764,7 +3764,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)if ((bp->flags &BNXT_FLAG_AGG_RINGS )) { type = ((u32 )BNXT_RX_PAGE_SIZE <<RX_BD_LEN_SHIFT ) | -RX_BD_TYPE_RX_AGG_BD |RX_BD_FLAGS_SOP ; +RX_BD_TYPE_RX_AGG_BD ; + +/* On P7, setting EOP will cause the chip to disable +* Relaxed Ordering (RO) for TPA data. Disable EOP for +* potentially higher performance with RO. +*/ +if (BNXT_CHIP_P5_AND_MINUS (bp) || !(bp->flags &BNXT_FLAG_TPA )) + type |=RX_BD_FLAGS_AGG_EOP ;bnxt_init_rxbd_pages (ring, type); }
drivers/net/ethernet/broadcom/bnxt/bnxt.h +1 -0
@@ -103,6 +103,7 @@ struct rx_bd {#define RX_BD_TYPE_48B_BD_SIZE (2 << 4)#define RX_BD_TYPE_64B_BD_SIZE (3 << 4)#define RX_BD_FLAGS_SOP (1 << 6) +#define RX_BD_FLAGS_AGG_EOP (1 << 6)#define RX_BD_FLAGS_EOP (1 << 7)#define RX_BD_FLAGS_BUFFERS (3 << 8)#define RX_BD_FLAGS_1_BUFFER_PACKET (0 << 8)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 518/609 bnxt_en: Disable EOP for TPA on all chips to prevent data corruption
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Chan <[email protected]>
[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]
EOP (End of frame padding) on the AGG ring may cause overlapping of zero padding at the end of one segment with the next segment's data. If Relaxed Ordering (RO) is enabled, the zero padding may overwrite valid data in the next segment and corrupt the data. Older chips (P5 and older) do not automatically disable RO when EOP is enabled. On some ARM systems, data corruption was reported on 57508 (P5) chips with RO enabled.
Always disable EOP on all chips on the AGG rings when TPA is enabled to fix the data corruption.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +7 -4
@@ -3766,11 +3766,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr) type = ((u32 )BNXT_RX_PAGE_SIZE <<RX_BD_LEN_SHIFT ) |RX_BD_TYPE_RX_AGG_BD ; -/* On P7, setting EOP will cause the chip to disable -* Relaxed Ordering (RO) for TPA data. Disable EOP for -* potentially higher performance with RO. +/* Disable EOP if TPA is enabled to prevent overlapping zero +* padding with the next segment's data. On P7_PLUS, EOP will +* automatically disable Relaxed Ordering (RO) to prevent +* potential data corruption (and may degrade performance). On +* older chips, RO will not be automatically disabled and may +* cause corruption. */ -if (BNXT_CHIP_P5_AND_MINUS (bp) || !(bp->flags &BNXT_FLAG_TPA )) +if (!(bp->flags &BNXT_FLAG_TPA )) type |=RX_BD_FLAGS_AGG_EOP ;bnxt_init_rxbd_pages (ring, type);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 519/609 bnxt_en: Fix PTP PPS setting bug
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keegan Freyhof <[email protected]>
[ Upstream commit 80eaf88efec33ac77ed7726d066c4f2f932cc329 ]
The existing driver logic is always turning on PTP_CLK_REQ_PPS regardless of the "on" parameter passed to bnxt_ptp_enable(). During shutdown, PTP_CLK_REQ_PPS may be turned off and this bug will do the opposite and may trigger a PCIe PTM request TLP. On some systems this can trigger a PCIe AER.
Fix it by properly configuring PTP_CLK_REQ_PPS based on the "on" parameter.
--- drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c +5 -2
@@ -460,12 +460,15 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info,return rc;case PTP_CLK_REQ_PPS :/* Configure PHC PPS IN */ - rc =bnxt_ptp_cfg_pin (bp,0 ,BNXT_PPS_PIN_PPS_IN ); + pin_id =0 ; +if (!on) +break ; + rc =bnxt_ptp_cfg_pin (bp, pin_id,BNXT_PPS_PIN_PPS_IN );if (rc)return rc; rc =bnxt_ptp_cfg_event (bp,BNXT_PPS_EVENT_INTERNAL );if (!rc) - ptp->pps_info.pins[0 ].event =BNXT_PPS_EVENT_INTERNAL ; + ptp->pps_info.pins[pin_id].event =BNXT_PPS_EVENT_INTERNAL ;return rc;default :netdev_err (ptp->bp->dev,"Unrecognized PIN function\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 520/609 sctp: fix addip_serial increment on ASCONF_ACK allocation failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qing Luo <[email protected]>
[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]
In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate the ASCONF_ACK chunk due to memory pressure, the code jumps to the done label where asoc->peer.addip_serial is unconditionally incremented.
This leaves the peer's ASCONF (serial N) unacknowledged while the local endpoint now expects serial N+1. When the peer retransmits serial N, it falls into the serial < addip_serial + 1 branch ,
which attempts to look up a cached ACK for serial N. No cached ACK exists since the allocation failed, so the retransmission is silently discarded. The peer eventually times out and ABORTs the association.
Move the addip_serial increment inside the if (asconf_ack) block so that the serial number is only advanced when the ASCONF_ACK is successfully created and cached. This way, on allocation failure, the serial number is unchanged and the peer's retransmitted ASCONF will be correctly re-processed.
--- net/sctp/sm_make_chunk.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/sctp/sm_make_chunk.c +1 -2
@@ -3362,12 +3362,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, goto done; } done: - asoc->peer.addip_serial++; -/* If we are sending a new ASCONF_ACK hold a reference to it in assoc * after freeing the reference to old asconf ack if any. */ if (asconf_ack) { + asoc->peer.addip_serial++;sctp_chunk_hold (asconf_ack);list_add_tail (&asconf_ack->transmitted_list, &asoc->asconf_ack_list);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 521/609 tcp: fix TFO max_qlen accounting across reuseport migration
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
[ Upstream commit a0ab2ba83e35159d81cec830a92e885ecf8139be ]
A listener's TCP_FASTOPEN max_qlen stops being accurate and lets through far more pending Fast Open requests than it was configured for.
This only shows up with SO_REUSEPORT listener migration, where closing a listener hands its still-pending TFO children over to a surviving one.
fastopenq.qlen is charged in tcp_fastopen_create_child() when the child is created and uncharged in reqsk_fastopen_remove() when the handshake completes. The uncharge follows rsk_listener of the request the child points at, and inet_reqsk_clone() has repointed the child at a new request owned by the new listener, so the ++ and the -- land on two different sockets. The new listener's qlen drifts negative and its limit no longer binds.
Charge the new listener during migration, like reqsk_queue_migrated() already does for queue->young and queue->qlen.
--- net/ipv4/inet_connection_sock.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
net/ipv4/inet_connection_sock.c +16 -4
@@ -927,11 +927,23 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req, nreq->rsk_listener = sk; -/* We need not acquire fastopenq->lock -* because the child socket is locked in inet_csk_listen_stop(). -*/ -if (sk->sk_protocol ==IPPROTO_TCP &&tcp_rsk (nreq)->tfo_listener) +if (sk->sk_protocol ==IPPROTO_TCP &&tcp_rsk (nreq)->tfo_listener) { +struct fastopen_queue *fastopenq; + +/* reqsk_fastopen_remove() will uncharge nreq->rsk_listener, +* that is @sk, so charge it here. Unlike the listener +* being closed, @sk is live and needs its lock. +*/ + fastopenq = &inet_csk (sk)->icsk_accept_queue.fastopenq; +spin_lock_bh (&fastopenq->lock); + fastopenq->qlen++; +spin_unlock_bh (&fastopenq->lock); + +/* We need not acquire fastopenq->lock +* because the child socket is locked in inet_csk_listen_stop(). +*/ rcu_assign_pointer (tcp_sk (nreq->sk)->fastopen_rsk, nreq); + }return nreq; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 522/609 net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Henry Martin <[email protected]>
[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]
ncsi_send_cmd_nl() takes the number of bytes to copy from the attacker-controlled ncsi_pkt_hdr.length field of the in-band packet header, while the source buffer is the NCSI_ATTR_DATA netlink attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr). The two length sources are never cross-checked: only nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.
With hdr->length set larger than the attribute payload (up to 65535 against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies past the end of the netlink attribute buffer with unsafe_memcpy(), leaking up to ~64KB of kernel heap memory into the transmitted NCSI command packet. The destination skb is sized by the declared payload, so the write side does not overflow - this is a pure OOB read / information leak, reachable with CAP_NET_ADMIN on systems with a registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where NET_NCSI=y is standard).
Reject commands whose declared payload extends past the end of the data attribute.
The issue was found by the autokbug dynamic kernel fuzzer at Tencent Yunding Lab.
--- net/ncsi/ncsi-netlink.c | 4 ++++ 1 file changed, 4 insertions(+)
net/ncsi/ncsi-netlink.c +4 -0
@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info) nca.req_flags =NCSI_REQ_FLAG_NETLINK_DRIVEN ; nca.info = info; nca.payload =ntohs (hdr->length); +if (nca.payload > len -sizeof (*hdr)) { + ret = -EINVAL ; + goto out_netlink; + } nca.data = data +sizeof (*hdr); ret =ncsi_xmit_cmd (&nca);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 523/609 net: prestera: validate firmware header length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]
prestera_fw_hdr_parse() reads the firmware header before checking that the firmware image contains that header.
Reject images shorter than struct prestera_fw_header before decoding the magic and version fields.
--- drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/prestera/prestera_pci.c +3 -0
@@ -673,6 +673,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)struct prestera_fw_header *hdr;u32 magic; +if (fw->bin->size <sizeof (*hdr)) +return -EINVAL ; + hdr = (struct prestera_fw_header *)fw->bin->data; magic =be32_to_cpu (hdr->magic_number);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 524/609 net: remove WARN_ON_ONCE() from sk_mc_loop()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]
sk_mc_loop() can be called for sockets that are neither AF_INET nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet socket over virtual devices such as VRF or ipvlan).
In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls through the switch statement and triggers WARN_ON_ONCE(1).
Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP options, so loopback should default to true without generating a warning.
--- net/core/sock.c | 1 - 1 file changed, 1 deletion(-)
net/core/sock.c +0 -1
@@ -772,7 +772,6 @@ bool sk_mc_loop(struct sock *sk)return inet6_sk (sk)->mc_loop;#endif } -WARN_ON_ONCE (1 );return true; }EXPORT_SYMBOL (sk_mc_loop);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 525/609 net/smc: fix TOCTOU race between smc_listen_out() and listener close
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sidraya Jayagond <[email protected]>
[ Upstream commit 185a4caeecabc150106deda1da170b09f2ad803f ]
smc_listen_out() reads lsmc->sk.sk_state without the listener lock, then acquires lock_sock_nested() only after the check passes. This opens a window where smc_close_active() can transition the listener to SMC_CLOSED, call smc_close_cleanup_listen() to drain the accept queue, and release the lock, all between the lockless read and the delayed lock acquisition:
smc_listen_work (smc_hs_wq) smc_close_active()
------------------------------- -------------------------
release_sock(child)
if (sk_state == SMC_LISTEN) TRUE
lock_sock(listener) sk_state = SMC_CLOSED smc_close_cleanup_listen() release_sock(listener) flush_work(tcp_listen_work)
lock_sock_nested(listener)
smc_accept_enqueue(listener, child) /* child enqueued on dead listener */
smc_close_active() flushes only tcp_listen_work. Work items already dispatched onto smc_hs_wq for the CLC handshake continue running unguarded. smc_accept_enqueue() takes a sock_hold() on the child that is never released, so the child smc_sock, its clcsock, and the reference all leak. A remote peer that opens TCP connections while the server calls close() can exhaust kernel memory.
Move lock_sock_nested() to before the sk_state check so that the test and the enqueue are atomic under the listener lock.
--- net/smc/af_smc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/smc/af_smc.c +2 -1
@@ -1874,11 +1874,12 @@ static void smc_listen_out(struct smc_sock *new_smc)atomic_dec (&lsmc->queued_smc_hs);release_sock (newsmcsk);/* lock in smc_listen_work() */ +lock_sock_nested (&lsmc->sk,SINGLE_DEPTH_NESTING );if (lsmc->sk.sk_state ==SMC_LISTEN ) { -lock_sock_nested (&lsmc->sk,SINGLE_DEPTH_NESTING );smc_accept_enqueue (&lsmc->sk, newsmcsk);release_sock (&lsmc->sk); }else {/* no longer listening */ +release_sock (&lsmc->sk);smc_close_non_accepted (newsmcsk); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 526/609 net: qrtr: ns: Raise lookup limit to 128
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Łukasz Patron <[email protected]>
[ Upstream commit 7fc1c937b6b37c77df4ba374c37435ab06a2e945 ]
Current limit of 64 is not enough for Sony Xperia 10 VII (SM6475).
After merging v6.6.142 into a downstream AOSP device, it's stuck on boot animation and following log spam can be observed in dmesg:
E qrtr : ctrl_cmd_new_lookup(): QRTR client node exceeds max lookup limit!
E qrtr : qrtr_ns_worker(): failed while handling packet from 1:16600
No idea why it needs more than 64 client lookups, but it appears to work fine with 128 as it did when there were no limits.
I don't really have a good way to investigate what it needs all these lookups for as most of the userspace is closed source.
--- net/qrtr/ns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/qrtr/ns.c +1 -1
@@ -77,7 +77,7 @@ struct qrtr_node {*/ #define QRTR_NS_MAX_NODES 512#define QRTR_NS_MAX_SERVERS 256 -#define QRTR_NS_MAX_LOOKUPS 64 +#define QRTR_NS_MAX_LOOKUPS 128static u16 node_count;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 527/609 net: thunderbolt: Tear down DMA paths before stopping the rings
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan XinRan <[email protected]>
[ Upstream commit 68bf02b6b4ad3f748c6db71fd77b6c0402d252f4 ]
tbnet_tear_down() stops both rings and frees their frame buffers before calling tb_xdomain_disable_paths(). tb_ring_stop() zeroes the ring's descriptor base and tbnet_free_buffers() unmaps and frees the pages the frames sit in, so by the time __tb_path_deactivate_hop() polls the hop's 'pending' bit, anything still in flight has nowhere to drain to.
The teardown sequence has been in this order since the driver was added. The setup path has not: commit ff7cd07f3064 ("net: thunderbolt: Enable DMA paths only after rings are enabled") moved the path enable to the end of tbnet_connected_work() and documented why:
/* Both logins successful so enable the rings, high-speed DMA
* paths and start the network device queue.
*
* Note we enable the DMA paths last to make sure we have primed
* the Rx ring before any incoming packets are allowed to
* arrive.
*/
Teardown was never updated to match, so the rings and the paths now come down in the same order they go up instead of in reverse.
On an ASMedia ASM4242 host router the 'pending' bit then never clears:
every teardown burns the full 500 ms timeout and __tb_path_deactivate_hop() returns -ETIMEDOUT. Raising the timeout to 5 s does not help, so the hop is not slow to drain, it never drains at all.
The failure is invisible above the thunderbolt core. __tb_path_deactivate_hops() is void and only calls tb_port_warn(); tb_path_deactivate(), tb_tunnel_deactivate() and __tb_disconnect_xdomain_paths() are void as well, and tb_disconnect_xdomain_paths() ends in an unconditional "return 0". So tb_xdomain_disable_paths() reports success and the netdev_warn() below it never fires. Repeated teardowns eventually take the XDomain control channel down, after which the peer node is gone and only a power cycle brings the controller back.
Deactivating the paths first fixes it. Measured with kretprobes on a stock v6.17 tree with no other patches applied, on a link that was up and had just carried traffic:
before: __tb_path_deactivate_hop() returns 0 for the first hop, then
-ETIMEDOUT for the second 500335 us later
after: 0 for both, 525 us apart
Alternating the two orderings ABBA over three load levels, four teardowns per arm: every teardown failed before the change (21 of 21 that ran), none failed after (0 of 24). The before arms ran short because the link died partway through. The same split shows up when the interface is enslaved to a bond instead of just brought down, which is how I ran into this in the first place. Throughput and latency after the change are unchanged.
Hosts whose routers drain the hop despite the stale descriptor base see no functional difference, since the paths end up deactivated either way.
--- drivers/net/thunderbolt.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
drivers/net/thunderbolt.c +15 -5
@@ -379,11 +379,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)break ; } -tb_ring_stop (net->rx_ring.ring); -tb_ring_stop (net->tx_ring.ring); -tbnet_free_buffers (&net->rx_ring); -tbnet_free_buffers (&net->tx_ring); - +/* Tear the paths down before stopping the rings. This mirrors +* tbnet_connected_work(), which enables the paths last so the +* Rx ring is primed before packets can arrive. Stopping a +* ring zeroes its descriptor base and tbnet_free_buffers() +* unmaps and frees the frame buffers, leaving anything still +* in flight with nowhere to drain to; +* __tb_path_deactivate_hop() then waits for the hop's +* 'pending' bit, which on some host routers never clears in +* that state. +*/ ret = tb_xdomain_disable_paths(net->xd, net->local_transmit_path, net->tx_ring.ring->hop,
@@ -392,6 +397,11 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)if (ret)netdev_warn (net->dev,"failed to disable DMA paths\n" ); +tb_ring_stop (net->rx_ring.ring); +tb_ring_stop (net->tx_ring.ring); +tbnet_free_buffers (&net->rx_ring); +tbnet_free_buffers (&net->tx_ring); +tb_xdomain_release_in_hopid (net->xd, net->remote_transmit_path); net->remote_transmit_path =0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 528/609 ata: pata_sl82c105: fix bridge revision use-after-free
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]
pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision") replaced a configuration-space read with direct access to the cached revision field, but left that access after pci_dev_put(). The bridge may therefore be freed before its revision is read.
Read the revision before dropping the reference.
--- drivers/ata/pata_sl82c105.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/ata/pata_sl82c105.c +3 -1
@@ -265,6 +265,7 @@ static struct ata_port_operations sl82c105_port_ops = {static int sl82c105_bridge_revision (struct pci_dev *pdev) {struct pci_dev *bridge; +u8 revision;/* * The bridge should be part of the same device, but function 0.
@@ -286,8 +287,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)/* * We need to find function 0's revision, not function 1 */ + revision = bridge->revision;pci_dev_put (bridge); -return bridge->revision; +return revision; }static void sl82c105_fixup (struct pci_dev *pdev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 529/609 net/atm: fix slab-out-of-bounds read in vcc_setsockopt()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit d0c80dbb970439bd2eeb0e5effff8c16a5f4e1e3 ]
vcc_setsockopt() contained an ineffective optlen check:
if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
return -EINVAL;
If __SO_LEVEL_MATCH(optname, level) evaluated to false (e.g. if the caller passed a mismatched level), the length check optlen != __SO_SIZE(optname) was short-circuited and bypassed. Execution then fell through to switch(optname), calling copy_from_sockptr() assuming optval contained sufficient space.
Furthermore, even if level matched, a cgroup BPF setsockopt filter could shrink optlen after entry. Because copy_from_sockptr() on kernel pointers uses memcpy(), this leads to a KASAN slab-out-of-bounds read when optlen is smaller than the expected structure size.
Fix this by using copy_safe_from_sockptr(), which unconditionally validates that optlen is at least the expected size before copying. Also change the local 'value' variable type from 'unsigned long' to 'int' so that SO_SETCLP matches its sizeof(int) ABI encoding on 64-bit systems.
--- net/atm/common.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
net/atm/common.c +9 -5
@@ -760,7 +760,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, unsigned int optlen) {struct atm_vcc *vcc; -unsigned long value; +int value;int error;if (__SO_LEVEL_MATCH (optname, level) && optlen !=__SO_SIZE (optname))
@@ -772,8 +772,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname, {struct atm_qos qos; -if (copy_from_sockptr (&qos, optval,sizeof (qos))) -return -EFAULT ; + error =copy_safe_from_sockptr (&qos,sizeof (qos), optval, + optlen); +if (error) +return error; error =check_qos (&qos);if (error)return error;
@@ -786,8 +788,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,return 0 ; }case SO_SETCLP : -if (copy_from_sockptr (&value, optval,sizeof (value))) -return -EFAULT ; + error =copy_safe_from_sockptr (&value,sizeof (value), optval, + optlen); +if (error) +return error;if (value) vcc->atm_options |=ATM_ATMOPT_CLP ;else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 530/609 sctp: clear control chunk transport if it is being removed
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]
sctp_make_heartbeat_ack() caches the destination transport in chunk->transport without taking a reference. When src_out_of_asoc_ok is enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead of being transmitted immediately.
If the peer transport is removed while the chunk is still queued, sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing, but only clears cached transport pointers in out_chunk_list. The queued control chunk therefore retains a dangling transport pointer.
Once an ASCONF_ACK clears the suppression and the queued control chunk is transmitted, SCTP dereferences the stale transport pointer, leading to a use-after-free.
Fix this by also clearing chunk->transport for queued control chunks in control_chunk_list when removing the transport.
--- net/sctp/associola.c | 4 ++++ 1 file changed, 4 insertions(+)
net/sctp/associola.c +4 -0
@@ -575,6 +575,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,if (ch->transport == peer) ch->transport =NULL ; +list_for_each_entry (ch, &asoc->outqueue.control_chunk_list, list) +if (ch->transport == peer) + ch->transport =NULL ; + asoc->peer.transport_count--;sctp_ulpevent_notify_peer_addr_change (peer,SCTP_ADDR_REMOVED ,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 531/609 tls: dont abort the connection on signal-interrupted sends
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maximilian Immanuel Brandtner <[email protected]>
[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]
When a signal interrupts a blocking send, tls_tx_records() treats the resulting -ERESTARTSYS as a transmission failure and marks the socket errored via tls_err_abort() with the raw error code. Later syscalls return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the signal it stems from is no longer pending during syscall exit and thus never translated.
An interrupted send is not a connection error: the partially sent record stays queued and is resent later. Interrupt error codes are therefore excluded from the abort in the same way as -EAGAIN.
--- net/tls/tls_sw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/tls/tls_sw.c +1 -1
@@ -457,7 +457,7 @@ int tls_tx_records(struct sock *sk, int flags) } tx_err: -if (rc <0 && rc != -EAGAIN ) +if (rc <0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS )tls_err_abort (sk, rc);return rc;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 532/609 hwmon: (corsair-psu) fix possible out-of-bounds access on missing string termination
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wilken Gottwalt <[email protected]>
[ Upstream commit 36c4d73ce05d1d8896c2669eb0730d35a02a2ec1 ]
In theory it could be possible that the REPLY_SIZE sized buffers for holding the vendor and product strings could be end up missing the null termination (for example by malicious hardware built on purpose) required by the seq_printf() call. That limits the debugfs printf calls to a maximum string length of REPLY_SIZE.
--- drivers/hwmon/corsair-psu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwmon/corsair-psu.c +2 -2
@@ -647,7 +647,7 @@ static int vendor_show(struct seq_file *seqf, void *unused) {struct corsairpsu_data *priv = seqf->private; -seq_printf (seqf,"%s\n" , priv->vendor); +seq_printf (seqf,"%.*s\n" ,REPLY_SIZE , priv->vendor);return 0 ; }
@@ -657,7 +657,7 @@ static int product_show(struct seq_file *seqf, void *unused) {struct corsairpsu_data *priv = seqf->private; -seq_printf (seqf,"%s\n" , priv->product); +seq_printf (seqf,"%.*s\n" ,REPLY_SIZE , priv->product);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 533/609 regulator: devres: add API for reference voltage supplies
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lechner <[email protected]>
[ Upstream commit b250c20b64290808aa4b5cc6d68819a7ee28237f ]
A common use case for regulators is to supply a reference voltage to an analog input or output device. This adds a new devres API to get, enable, and get the voltage in a single call. This allows eliminating boilerplate code in drivers that use reference supplies in this way.
Stable-dep-of: fddb5ceaf901 ("hwmon: (ads7828) Fix external VREF regulator handling")
--- .../driver-api/driver-model/devres.rst | 1 + drivers/regulator/devres.c | 59 +++++++++++++++++++ include/linux/regulator/consumer.h | 7 +++ 3 files changed, 67 insertions(+)
Documentation/driver-api/driver-model/devres.rst +1 -0
@@ -413,6 +413,7 @@ REGULATOR devm_regulator_bulk_put() devm_regulator_get() devm_regulator_get_enable() + devm_regulator_get_enable_read_voltage() devm_regulator_get_enable_optional() devm_regulator_get_exclusive() devm_regulator_get_optional()
drivers/regulator/devres.c +59 -0
65 lines not on this page · raw message
include/linux/regulator/consumer.h +7 -0
@@ -209,6 +209,7 @@ struct regulator *__must_check devm_regulator_get_optional(struct device *dev, const char *id);int devm_regulator_get_enable (struct device *dev,const char *id);int devm_regulator_get_enable_optional (struct device *dev,const char *id); +int devm_regulator_get_enable_read_voltage (struct device *dev,const char *id);void regulator_put (struct regulator *regulator);void devm_regulator_put (struct regulator *regulator);
@@ -372,6 +373,12 @@ static inline int devm_regulator_get_enable_optional(struct device *dev,return 0 ; } +static inline int devm_regulator_get_enable_read_voltage (struct device *dev, +const char *id) +{ +return -ENODEV ; +} +static inline struct regulator *__must_check regulator_get_optional (struct device *dev,const char *id) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 534/609 hwmon: (ads7828) Fix external VREF regulator handling
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingshuang Fu <[email protected]>
[ Upstream commit fddb5ceaf901b050ed2a1a7deeecbf97e003435a ]
The driver currently has two issues with the external VREF regulator handling in ads7828_probe():
1. All errors from devm_regulator_get_optional() are ignored, causing the driver to incorrectly fall back to internal VREF even for transient errors like -EPROBE_DEFER or genuine failures like -ENOMEM.
2. The external regulator is never enabled. The driver calls regulator_get_voltage() without first calling regulator_enable(), so the VREF pin may remain unpowered if the regulator is not configured as always-on.
Fix both issues by switching to devm_regulator_get_enable_read_voltage(), which handles regulator get, enable, and voltage read in one call. Only -ENODEV (no regulator specified in device tree) should trigger the fallback to internal VREF. All other errors are propagated to the caller.
--- drivers/hwmon/ads7828.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/hwmon/ads7828.c +6 -5
@@ -108,12 +108,11 @@ static int ads7828_probe(struct i2c_client *client)struct ads7828_data *data;struct device *hwmon_dev;unsigned int vref_mv =ADS7828_INT_VREF_MV ; -unsigned int vref_uv; +int vref_uv;bool diff_input = false;bool ext_vref = false;unsigned int regval;enum ads7828_chips chip; -struct regulator *reg; data =devm_kzalloc (dev,sizeof (struct ads7828_data ),GFP_KERNEL );if (!data)
@@ -127,9 +126,11 @@ static int ads7828_probe(struct i2c_client *client) }else if (dev->of_node) { diff_input =of_property_read_bool (dev->of_node,"ti,differential-input" ); - reg =devm_regulator_get_optional (dev,"vref" ); -if (!IS_ERR (reg)) { - vref_uv =regulator_get_voltage (reg); + vref_uv =devm_regulator_get_enable_read_voltage (dev,"vref" ); +if (vref_uv <0 ) { +if (vref_uv != -ENODEV ) +return vref_uv; + }else { vref_mv =DIV_ROUND_CLOSEST (vref_uv,1000 );if (vref_mv <ADS7828_EXT_VREF_MV_MIN || vref_mv >ADS7828_EXT_VREF_MV_MAX )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 535/609 KVM: x86/mmu: Rename __direct_map() to direct_map()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Matlack <[email protected]>
[ Upstream commit 6c882ef4fc7bd99b67ad152e75428b669281c521 ]
Rename __direct_map() to direct_map() since the leading underscores are unnecessary. This also makes the page fault handler names more
consistent: kvm_tdp_mmu_page_fault() calls kvm_tdp_mmu_map() and direct_page_fault() calls direct_map().
Opportunistically make some trivial cleanups to comments that had to be modified anyway since they mentioned __direct_map(). Specifically, use "()" when referring to functions, and include kvm_tdp_mmu_map() among the various callers of disallowed_hugepage_adjust().
No functional change intended.
Message-Id: <[email protected]>
Stable-dep-of: 2abd5287f083 ("KVM: x86: Check for invalid/obsolete root *after* making MMU pages available")
--- arch/x86/kvm/mmu/mmu.c | 61 ++++++++++++++++----------------- arch/x86/kvm/mmu/mmu_internal.h | 3 +- arch/x86/kvm/mmu/paging_tmpl.h | 6 +--- 3 files changed, 33 insertions(+), 37 deletions(-)
arch/x86/kvm/mmu/mmu.c +30 -31
@@ -3102,11 +3102,11 @@ void disallowed_hugepage_adjust(struct kvm_page_fault *fault, u64 spte, int cur_ is_shadow_present_pte(spte) && !is_large_pte(spte)) {/* -* A small SPTE exists for this pfn, but FNAME(fetch) -* and __direct_map would like to create a large PTE -* instead: just force them to go down another level, -* patching back for them into pfn the next 9 bits of -* the address. +* A small SPTE exists for this pfn, but FNAME(fetch), +* direct_map(), or kvm_tdp_mmu_map() would like to create a +* large PTE instead: just force them to go down another level, +* patching back for them into pfn the next 9 bits of the +* address. */ u64 page_mask =KVM_PAGES_PER_HPAGE (cur_level) -KVM_PAGES_PER_HPAGE (cur_level -1 );
@@ -3115,7 +3115,7 @@ void disallowed_hugepage_adjust(struct kvm_page_fault *fault, u64 spte, int cur_ } } -static int __direct_map (struct kvm_vcpu *vcpu,struct kvm_page_fault *fault) +static int direct_map (struct kvm_vcpu *vcpu,struct kvm_page_fault *fault) {struct kvm_shadow_walk_iterator it;struct kvm_mmu_page *sp;
@@ -4157,6 +4157,9 @@ static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)struct kvm_memory_slot *slot = fault->slot;bool async; + fault->mmu_seq = vcpu->kvm->mmu_invalidate_seq; +smp_rmb (); +/* * Retry the page fault if the gfn hit a memslot that is being deleted * or moved. This ensures any existing SPTEs for the old memslot will
@@ -4213,8 +4216,7 @@ static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)* root was invalidated by a memslot update or a relevant mmu_notifier fired. */ static bool is_page_fault_stale (struct kvm_vcpu *vcpu, -struct kvm_page_fault *fault, -unsigned long mmu_seq) +struct kvm_page_fault *fault) {struct kvm_mmu_page *sp =to_shadow_page (vcpu->arch.mmu->root.hpa);
@@ -4234,14 +4236,13 @@ static bool is_page_fault_stale(struct kvm_vcpu *vcpu,return true;return fault->slot && -mmu_invalidate_retry_hva (vcpu->kvm, mmu_seq, fault->hva); +mmu_invalidate_retry_hva (vcpu->kvm, fault->mmu_seq, fault->hva); }static int direct_page_fault (struct kvm_vcpu *vcpu,struct kvm_page_fault *fault) {bool is_tdp_mmu_fault =is_tdp_mmu (vcpu->arch.mmu); -unsigned long mmu_seq;kvm_pfn_t orig_pfn;int r;
@@ -4259,43 +4260,41 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *faultif (r)return r; - mmu_seq = vcpu->kvm->mmu_invalidate_seq; -smp_rmb (); - r =kvm_faultin_pfn (vcpu, fault);if (r !=RET_PF_CONTINUE )return r; - r =handle_abnormal_pfn (vcpu, fault,ACC_ALL );if (r !=RET_PF_CONTINUE )return r; orig_pfn = fault->pfn; +if (is_tdp_mmu_fault) { + r =RET_PF_RETRY ; +read_lock (&vcpu->kvm->mmu_lock); + +if (!is_page_fault_stale (vcpu, fault)) + r =kvm_tdp_mmu_map (vcpu, fault); + +read_unlock (&vcpu->kvm->mmu_lock); +kvm_release_pfn_clean (orig_pfn); +return r; + } + r =RET_PF_RETRY ; +write_lock (&vcpu->kvm->mmu_lock); -if (is_tdp_mmu_fault) -read_lock (&vcpu->kvm->mmu_lock); -else -write_lock (&vcpu->kvm->mmu_lock); +if (is_page_fault_stale (vcpu, fault)) + goto out_unlock; -if (is_page_fault_stale (vcpu, fault, mmu_seq)) + r =make_mmu_pages_available (vcpu); +if (r) goto out_unlock; -if (is_tdp_mmu_fault) { - r =kvm_tdp_mmu_map (vcpu, fault); - }else { - r =make_mmu_pages_available (vcpu); -if (r) - goto out_unlock; - r =__direct_map (vcpu, fault); - } + r =direct_map (vcpu, fault); out_unlock: -if (is_tdp_mmu_fault) -read_unlock (&vcpu->kvm->mmu_lock); -else -write_unlock (&vcpu->kvm->mmu_lock); +write_unlock (&vcpu->kvm->mmu_lock);kvm_release_pfn_clean (orig_pfn);return r; }
arch/x86/kvm/mmu/mmu_internal.h +2 -1
@@ -197,7 +197,7 @@ struct kvm_page_fault {/* * Maximum page size that can be created for this fault; input to -* FNAME(fetch), __direct_map and kvm_tdp_mmu_map. +* FNAME(fetch), direct_map() and kvm_tdp_mmu_map(). */ u8 max_level;
@@ -220,6 +220,7 @@ struct kvm_page_fault {struct kvm_memory_slot *slot;/* Outputs of kvm_faultin_pfn. */ +unsigned long mmu_seq;kvm_pfn_t pfn;hva_t hva;bool map_writable;
arch/x86/kvm/mmu/paging_tmpl.h +1 -5
@@ -792,7 +792,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *faultstruct guest_walker walker;kvm_pfn_t orig_pfn;int r; -unsigned long mmu_seq;bool is_self_change_mapping;pgprintk ("%s: addr %lx err %x\n" , __func__, fault->addr, fault->error_code);
@@ -837,9 +836,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *faultelse fault->max_level = walker.level; - mmu_seq = vcpu->kvm->mmu_invalidate_seq; -smp_rmb (); - r =kvm_faultin_pfn (vcpu, fault);if (r !=RET_PF_CONTINUE )return r;
@@ -872,7 +868,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault r =RET_PF_RETRY ;write_lock (&vcpu->kvm->mmu_lock); -if (is_page_fault_stale (vcpu, fault, mmu_seq)) +if (is_page_fault_stale (vcpu, fault)) goto out_unlock; r =make_mmu_pages_available (vcpu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 536/609 KVM: x86: Check for invalid/obsolete root *after* making MMU pages available
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
[ Upstream commit 2abd5287f08319fa35764566b15c6e22cb1068db ]
Check for a "stale" page fault, i.e. for an invalid and/or obsolete root, after making MMU pages available for the shadow MMU. If reclaiming shadow pages zaps an in-use root, i.e. marks it invalid, then KVM will attempt to map memory into an invalid root. On its own, populating an invalid root is "fine", but because child shadow pages inherit their parent's role, any children created during the map/fetch will be created as invalid pages, thus violating KVM's invariant that invalid pages are never on the list of active MMU pages.
Note, the underlying flaw has existed since KVM first started tracking invalid roots in 2008 (commit 2e53d63acba7, "KVM: MMU: ignore zapped root pagetables"), but the true badness only came along in 2020 (Linux 5.9) with the invariant that invalid shadow pages can't be on the list of active pages.
Note #2, inheriting role.invalid when creating child shadow pages is also far from ideal; that flaw will be addressed separately.
--- arch/x86/kvm/mmu/mmu.c | 9 +++++---- arch/x86/kvm/mmu/paging_tmpl.h | 10 ++++++---- 2 files changed, 11 insertions(+), 8 deletions(-)
arch/x86/kvm/mmu/mmu.c +5 -4
@@ -4281,16 +4281,17 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *faultreturn r; } - r =RET_PF_RETRY ;write_lock (&vcpu->kvm->mmu_lock); -if (is_page_fault_stale (vcpu, fault)) - goto out_unlock; - r =make_mmu_pages_available (vcpu);if (r) goto out_unlock; +if (is_page_fault_stale (vcpu, fault)) { + r =RET_PF_RETRY ; + goto out_unlock; + } + r =direct_map (vcpu, fault); out_unlock:
arch/x86/kvm/mmu/paging_tmpl.h +6 -4
@@ -865,15 +865,17 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault orig_pfn = fault->pfn; - r =RET_PF_RETRY ;write_lock (&vcpu->kvm->mmu_lock); -if (is_page_fault_stale (vcpu, fault)) - goto out_unlock; - r =make_mmu_pages_available (vcpu);if (r) goto out_unlock; + +if (is_page_fault_stale (vcpu, fault)) { + r =RET_PF_RETRY ; + goto out_unlock; + } + r =FNAME (fetch)(vcpu, fault, &walker); out_unlock:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 537/609 spi: spi-fsl-dspi: Avoid setup_accel logic for DMA transfers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Larisa Grigore <[email protected]>
[ Upstream commit cac7e5054115fcc41b1cb050af8e8971f7c9b22b ]
Repacking multiple smaller words into larger ones to make use of the full FIFO doesn't save anything in DMA mode, so don't bother doing it.
--- drivers/spi/spi-fsl-dspi.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/spi/spi-fsl-dspi.c +7 -6
@@ -751,8 +751,12 @@ static void dspi_setup_accel(struct fsl_dspi *dspi)struct spi_transfer *xfer = dspi->cur_transfer;bool odd = !!(dspi->len &1 ); -/* No accel for frames not multiple of 8 bits at the moment */ -if (xfer->bits_per_word %8 ) +/* +* No accel for DMA transfers or frames not multiples of 8 bits at the +* moment. +*/ +if (dspi->devtype_data->trans_mode ==DSPI_DMA_MODE || + xfer->bits_per_word %8 ) goto no_accel;if (!odd && dspi->len <= dspi->devtype_data->fifo_size *2 ) {
@@ -761,10 +765,7 @@ static void dspi_setup_accel(struct fsl_dspi *dspi) dspi->oper_bits_per_word =8 ; }else {/* Start off with maximum supported by hardware */ -if (dspi->devtype_data->trans_mode ==DSPI_XSPI_MODE ) - dspi->oper_bits_per_word =32 ; -else - dspi->oper_bits_per_word =16 ; + dspi->oper_bits_per_word =32 ;/* * And go down only if the buffer can't be sent with
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 538/609 Input: evdev - sanitize event type index when fetching event masks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit 3abd29c61d2ef37c4102cf755b18be53bb9dbea6 upstream.
The user-supplied event type index passed to EVIOCGMASK / EVIOCSMASK ioctls is used to index the static counts array in evdev_get_mask_cnt() and client evmasks array in evdev_get_mask().
While the event type is architecturally bounded by EV_CNT, speculative execution may mispredict bounds checks and perform out-of-bounds loads.
Sanitize the event type index in evdev_get_mask_cnt() branchlessly using array_index_mask_nospec(). This clamps the index to 0 for safe array access and forces the returned count to 0 speculatively when the index is out of bounds.
We do not need additional array_index_nospec() calls in evdev_get_mask() because evdev_get_mask_cnt() speculatively forces the count (and resulting xfer_size) to 0 for out-of-bounds types, preventing any speculative memory access to client evmasks array.
--- drivers/input/evdev.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/input/evdev.c +4 -1
@@ -21,6 +21,7 @@#include <linux/init.h> #include <linux/input/mt.h> #include <linux/major.h> +#include <linux/nospec.h> #include <linux/device.h> #include <linux/cdev.h> #include "input-compat.h"
@@ -67,8 +68,10 @@ static size_t evdev_get_mask_cnt(unsigne [EV_SND] = SND_CNT, [EV_FF] = FF_CNT, }; +unsigned long mask =array_index_mask_nospec (type,EV_CNT ); -return (type <EV_CNT ) ? counts[type] :0 ; +/* Returns 0 for out-of-bounds types, including speculatively */ +return counts[type & mask] & mask; }/* requires the buffer lock to be held */
Greg Kroah-Hartman
maintainerPATCH 539/609 ALSA: usb-audio: fix OOB write on Type II inbound URBs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 69ee44e1a23be62318189dc4b37fa4ad94053269 upstream.
data_ep_set_params() sizes each URB transfer buffer before it adds the Format Type II transfer delimiter:
u->packets = urb_packs; u->buffer_size = maxsize * u->packets; if (fmt->fmt_type == UAC_FORMAT_TYPE_II) u->packets++; /* for transfer delimiter */ u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
buffer_size is computed from the pre-increment packet count and never recomputed, so for a Type II endpoint the buffer is one packet short of the packet count the URB is built with.
prepare_inbound_urb() then lays out one iso frame per packet and never consults buffer_size:
offs = 0;
for (i = 0; i < urb_ctx->packets; i++) {
urb->iso_frame_desc[i].offset = offs;
urb->iso_frame_desc[i].length = ep->curpacksize;
offs += ep->curpacksize;
}
urb->transfer_buffer_length = offs;
urb->number_of_packets = urb_ctx->packets;The last descriptor therefore points one packet past the end of the transfer buffer, where the host controller writes device data on every inbound transfer. prepare_silent_urb() and prepare_playback_urb() bound their fill loops by ctx->buffer_size, so only capture is affected.
fmt_type comes from the device's audio streaming descriptors, so any device advertising a Type II capture format hits this once userspace sets hw_params on the stream.
KASAN on 7.2.0-rc5 (arm64) with a dummy_hcd/raw-gadget device, one report per inbound transfer:
BUG: KASAN: slab-out-of-bounds in dummy_timer Write of size 64 at addr ffff0000186171c0 by task cons02/166 __asan_memcpy dummy_timer hrtimer_run_softirq Allocated by task 166: usb_alloc_coherent snd_usb_endpoint_set_params The buggy address is located 0 bytes to the right of allocated 64-byte region [ffff000018617180, ffff0000186171c0)
Compute buffer_size after the delimiter packet has been accounted for, and bound the fill loop by buffer_size, as prepare_silent_urb() already does on the outbound side. This grows every Type II URB allocation by one maxsize packet.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/usb/endpoint.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
sound/usb/endpoint.c +4 -2
@@ -388,13 +388,15 @@ static int prepare_inbound_urb(struct sncase SND_USB_ENDPOINT_TYPE_DATA : offs =0 ;for (i =0 ; i < urb_ctx->packets; i++) { +if (offs + ep->curpacksize > urb_ctx->buffer_size) +break ; urb->iso_frame_desc[i].offset = offs; urb->iso_frame_desc[i].length = ep->curpacksize; offs += ep->curpacksize; } urb->transfer_buffer_length = offs; - urb->number_of_packets = urb_ctx->packets; + urb->number_of_packets = i;break ;case SND_USB_ENDPOINT_TYPE_SYNC :
@@ -1256,10 +1258,10 @@ static int data_ep_set_params(struct snd u->index = i; u->ep = ep; u->packets = urb_packs; - u->buffer_size = maxsize * u->packets;if (fmt->fmt_type ==UAC_FORMAT_TYPE_II ) u->packets++;/* for transfer delimiter */ + u->buffer_size = maxsize * u->packets; u->urb =usb_alloc_urb (u->packets,GFP_KERNEL );if (!u->urb) goto out_of_memory;
Greg Kroah-Hartman
maintainerPATCH 540/609 usb: atm: cxacru: properly kill rcv_urb on error in cxacru_cm()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <[email protected]>
commit c2f811314be351d86b6ab41e9297ae80d8da6f86 upstream.
If cxacru_cm() encounters an error while submitting or waiting for snd_urb, it aborts and returns the error without killing the already submitted rcv_urb. This leaves the rcv_urb active.
When this happens during initialization (e.g., in cxacru_atm_start()), the driver may ignore the error and proceed to call cxacru_poll_status(), which invokes cxacru_cm() again. Attempting to submit the still-active rcv_urb triggers a warning in usb_submit_urb():
cxacru 1-1:1.0: send of cm 0x84 failed (-104)
ATM dev 0: cxacru_atm_start: CHIP_ADSL_LINE_START returned -104
------------[ cut here ]------------ URB ffff88812658d200 submitted while active WARNING: drivers/usb/core/urb.c:379 at usb_submit_urb+0x79/0x18b0 drivers/usb/core/urb.c:379 ... Call Trace: <TASK> cxacru_cm+0x21a/0xf10 drivers/usb/atm/cxacru.c:631 cxacru_cm_get_array drivers/usb/atm/cxacru.c:722 [inline] cxacru_poll_status+0x178/0x1110 drivers/usb/atm/cxacru.c:828 cxacru_atm_start+0x185/0x360 drivers/usb/atm/cxacru.c:814 usbatm_atm_init+0x144/0x3a0 drivers/usb/atm/usbatm.c:927 usbatm_usb_probe+0x15cb/0x1db0 drivers/usb/atm/usbatm.c:1178 cxacru_usb_probe+0x17f/0x220 drivers/usb/atm/cxacru.c:1370
...
To fix this, ensure that rcv_urb is properly killed if cxacru_cm() aborts early. We can safely call usb_kill_urb() on rcv_urb in the error path, as it is safe to call even if the URB is not active (e.g., if it failed to submit in the first place, or if it already completed).
--- drivers/usb/atm/cxacru.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/atm/cxacru.c +2 -0
@@ -700,6 +700,8 @@ static int cxacru_cm(struct cxacru_data ret = offd;usb_dbg (instance->usbatm,"cm %#x\n" , cm); fail: +if (ret <0 ) +usb_kill_urb (instance->rcv_urb);mutex_unlock (&instance->cm_serialize); err:return ret;
Greg Kroah-Hartman
maintainerPATCH 541/609 thunderbolt: icm: Preserve USB4 proxy data-valid bit
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit e48844ece5e3ed1d1eb865f6da2b16f62cd9f86d upstream.
The ICM USB4 switch operation request encodes two values in request.data_len_valid: bit 4 marks the data payload valid, while bits 3:0 hold the payload length in dwords. A zero length with the valid bit set represents the full 16-dword data array.
icm_usb4_switch_op() sets the valid bit when a transmit payload is present. For payloads shorter than the full 16 dwords, it then assigns the length to the whole field and clears the valid bit that was just set. The payload is still copied into the request, but the descriptor sent to firmware marks that data as invalid.
This affects USB4 router operations that send short payloads through the firmware connection manager. In particular, USB4 NVM writes can send a short final block when the image size is not aligned to the 64-byte proxy payload size. Firmware may then ignore or reject that final block, while full 16-dword blocks are unaffected because they are encoded as length 0 with the valid bit set.
OR the short payload length into data_len_valid so the valid bit is preserved.
--- drivers/thunderbolt/icm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/thunderbolt/icm.c +1 -1
@@ -2293,7 +2293,7 @@ static int icm_usb4_switch_op(struct tb_if (tx_data_len) { request.data_len_valid |=ICM_USB4_SWITCH_DATA_VALID ;if (tx_data_len <ARRAY_SIZE (request.data)) - request.data_len_valid = + request.data_len_valid |= tx_data_len &ICM_USB4_SWITCH_DATA_LEN_MASK ;memcpy (request.data, tx_data, tx_data_len *sizeof (u32)); }
Greg Kroah-Hartman
maintainerPATCH 542/609 usb: cdnsp: fix incorrect endian conversions for APB timeout register
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pawel Laszczak <[email protected]>
commit 50b303f3d0f7de543ee90d50879970783d06da33 upstream.
readl() already returns a CPU-endian value. Passing its return value to le32_to_cpu() is therefore redundant and causes an incorrect double byte swap on big-endian systems.
Similarly, writel() expects a CPU-endian value, so passing the result of cpu_to_le32() is incorrect.
Remove the unnecessary conversions and operate on the MMIO register value as a CPU-endian u32.
--- drivers/usb/cdns3/cdnsp-gadget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/cdns3/cdnsp-gadget.c +2 -2
@@ -154,9 +154,9 @@ static void cdnsp_set_apb_timeout_value( offset =cdnsp_find_next_ext_cap (base, offset,D_XEC_PRE_REGS_CAP ); reg = base + offset +REG_CHICKEN_BITS_3_OFFSET ; - val =le32_to_cpu (readl (reg)); + val =readl (reg); val =CHICKEN_APB_TIMEOUT_SET (val, cdns->override_apb_timeout); -writel (cpu_to_le32 (val), reg); +writel (val, reg); }static void cdnsp_set_chicken_bits_2 (struct cdnsp_device *pdev,u32 bit)
Greg Kroah-Hartman
maintainerPATCH 543/609 usb: gadget: f_ncm: Use unsigned int for ndp_index
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sonali Pradhan <[email protected]>
commit 6b1c8a9403a26cb0fed7a648916c74dc236da591 upstream.
The variable ndp_index is declared as a signed integer, but it stores the return value of get_ncm(), which is unsigned.
A malicious host can supply a large offset that overflows the signed ndp_index, making it negative. Because ndp_index is compared against unsigned bounds, this negative value bypasses sanity checks and leads to an out-of-bounds read when calculating the address of the NDP block (ntb_ptr + ndp_index).
Fix this by changing ndp_index to unsigned int to ensure consistent unsigned comparisons throughout the function.
--- drivers/usb/gadget/function/f_ncm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/f_ncm.c +1 -1
@@ -1176,7 +1176,7 @@ static int ncm_unwrap_ntb(struct getherunsigned char *ntb_ptr = skb->data;__le16 *tmp;unsigned index, index2; -int ndp_index; +unsigned int ndp_index;unsigned dg_len, dg_len2;unsigned ndp_len;unsigned block_len;