5.10.265-rc1 review
Greg Kroah-Hartman
maintainerPATCH 138/389 media: vb2: use ssize_t for vb2_read/vb2_write
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zile Xiong <[email protected]>
commit a562d6dc86bdfdd299e1b4734977a8d63e803583 upstream.
vb2_read() and vb2_write() return size_t, but propagate negative errno values from __vb2_perform_fileio().
This relies on implicit signed/unsigned conversions in callers (e.g. vb2_fop_read()) to recover error codes:
__vb2_perform_fileio() -> -EINVAL
vb2_read() -> (size_t)-EINVAL
vb2_fop_read() -> -EINVALThis relies on implicit conversions that are not obvious.
These helpers are exported (EXPORT_SYMBOL_GPL) and part of the vb2 API, so changing their return type may affect existing users.
However, they conceptually follow read/write semantics, where ssize_t is typically used to return either a byte count or a negative error code.
Switch vb2_read() and vb2_write() to ssize_t, and update __vb2_perform_fileio() accordingly.
--- drivers/media/common/videobuf2/videobuf2-core.c | 12 ++++++------ include/media/videobuf2-core.h | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-)
drivers/media/common/videobuf2/videobuf2-core.c +6 -6
@@ -2706,8 +2706,8 @@ static int __vb2_cleanup_fileio(struct v* @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) * @read: access mode selector (1 means read, 0 means write) */ -static size_t __vb2_perform_fileio (struct vb2_queue *q,char __user *data,size_t count, -loff_t *ppos,int nonblock,int read) +static ssize_t __vb2_perform_fileio (struct vb2_queue *q,char __user *data,size_t count, +loff_t *ppos,int nonblock,int read) {struct vb2_fileio_data *fileio;struct vb2_fileio_buf *buf;
@@ -2867,15 +2867,15 @@ static size_t __vb2_perform_fileio(strucreturn ret; } -size_t vb2_read (struct vb2_queue *q,char __user *data,size_t count, -loff_t *ppos,int nonblocking) +ssize_t vb2_read (struct vb2_queue *q,char __user *data,size_t count, +loff_t *ppos,int nonblocking) {return __vb2_perform_fileio (q, data, count, ppos, nonblocking,1 ); }EXPORT_SYMBOL_GPL (vb2_read); -size_t vb2_write (struct vb2_queue *q,const char __user *data,size_t count, -loff_t *ppos,int nonblocking) +ssize_t vb2_write (struct vb2_queue *q,const char __user *data,size_t count, +loff_t *ppos,int nonblocking) {return __vb2_perform_fileio (q, (char __user *) data, count, ppos, nonblocking,0 );
include/media/videobuf2-core.h +4 -4
@@ -1040,8 +1040,8 @@ __poll_t vb2_core_poll(struct vb2_queue* @ppos: file handle position tracking pointer * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) */ -size_t vb2_read (struct vb2_queue *q,char __user *data,size_t count, -loff_t *ppos,int nonblock); +ssize_t vb2_read (struct vb2_queue *q,char __user *data,size_t count, +loff_t *ppos,int nonblock);/** * vb2_read() - implements write() syscall logic. * @q: pointer to &struct vb2_queue with videobuf2 queue.
@@ -1050,8 +1050,8 @@ size_t vb2_read(struct vb2_queue *q, cha* @ppos: file handle position tracking pointer * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) */ -size_t vb2_write (struct vb2_queue *q,const char __user *data,size_t count, -loff_t *ppos,int nonblock); +ssize_t vb2_write (struct vb2_queue *q,const char __user *data,size_t count, +loff_t *ppos,int nonblock);/** * typedef vb2_thread_fnc - callback function for use with vb2_thread.
Greg Kroah-Hartman
maintainerPATCH 139/389 media: vidtv: fix reference leak on failed device registration
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 9aa21e1549db8882ff77b691e7714153df21dff0 upstream.
When platform_device_register() fails in vidtv_bridge_init(), the embedded struct device in vidtv_bridge_dev has already been initialized by device_initialize(), but the failure path returns the error without dropping the device reference for the current platform device:
vidtv_bridge_init()
-> platform_device_register(&vidtv_bridge_dev)
-> device_initialize(&vidtv_bridge_dev.dev)
-> setup_pdev_dma_masks(&vidtv_bridge_dev)
-> platform_device_add(&vidtv_bridge_dev)This leads to a reference leak when platform_device_register() fails. Fix this by calling platform_device_put() before returning the error.
The issue was identified by a static analysis tool I developed and confirmed by manual review.
--- drivers/media/test-drivers/vidtv/vidtv_bridge.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/media/test-drivers/vidtv/vidtv_bridge.c +3 -1
@@ -562,8 +562,10 @@ static int __init vidtv_bridge_init(voidint ret; ret =platform_device_register (&vidtv_bridge_dev); -if (ret) +if (ret) { +platform_device_put (&vidtv_bridge_dev);return ret; + } ret =platform_driver_register (&vidtv_bridge_driver);if (ret)
Greg Kroah-Hartman
maintainerPATCH 140/389 media: vimc: fix reference leak on failed device registration
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 33e2b833c66b890a0d71c4fa82d4c97143f7f75f upstream.
When platform_device_register() fails in vimc_init(), the embedded struct device in vimc_pdev has already been initialized by device_initialize(), but the failure path returns the error without dropping the device reference for the current platform device:
vimc_init()
-> platform_device_register(&vimc_pdev)
-> device_initialize(&vimc_pdev.dev)
-> setup_pdev_dma_masks(&vimc_pdev)
-> platform_device_add(&vimc_pdev)This leads to a reference leak when platform_device_register() fails. Fix this by calling platform_device_put() before returning the error.
The issue was identified by a static analysis tool I developed and confirmed by manual review.
--- drivers/media/test-drivers/vimc/vimc-core.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/test-drivers/vimc/vimc-core.c +1 -0
@@ -350,6 +350,7 @@ static int __init vimc_init(void)if (ret) {dev_err (&vimc_pdev.dev,"platform device registration failed (err=%d)\n" , ret); +platform_device_put (&vimc_pdev);return ret; }
Greg Kroah-Hartman
maintainerPATCH 141/389 media: vivid: check for vb2_is_busy() when toggling caps
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hans Verkuil <[email protected]>
commit c2d1a2130c93f6d758af58590b86b2254c7a1dec upstream.
The vivid_update_format_cap/out() functions must only be called if the capture/output queue are not busy. But for the controls that select the CROP/COMPOSE/SCALE capability that is not checked.
Only when streaming starts will they be set to 'grabbed' and it is impossible to change the control, but between REQBUFS and STREAMON you are still allowed to set these controls. Since vivid_update_format_cap/out will change the format, this can cause unexpected results.
Besides adding these checks, also add a WARN_ON in vivid_update_format_cap/out() if the queue is busy.
I'm 90% certain that this is the cause of this syzbot bug:
https://syzkaller.appspot.com/bug?extid=dac8f5eaa46837e97b89
But since we never have reproducers, it is hard to be certain. In any case, these checks are needed regardless.
--- drivers/media/test-drivers/vivid/vivid-ctrls.c | 12 ++++++++++++ drivers/media/test-drivers/vivid/vivid-vid-cap.c | 6 ++++++ drivers/media/test-drivers/vivid/vivid-vid-out.c | 6 ++++++ 3 files changed, 24 insertions(+)
drivers/media/test-drivers/vivid/vivid-ctrls.c +12 -0
@@ -464,14 +464,20 @@ static int vivid_vid_cap_s_ctrl(struct vvivid_update_format_cap (dev, true);break ;case VIVID_CID_HAS_CROP_CAP : +if (vb2_is_busy (&dev->vb_vid_cap_q)) +return -EBUSY ; dev->has_crop_cap = ctrl->val;vivid_update_format_cap (dev, true);break ;case VIVID_CID_HAS_COMPOSE_CAP : +if (vb2_is_busy (&dev->vb_vid_cap_q)) +return -EBUSY ; dev->has_compose_cap = ctrl->val;vivid_update_format_cap (dev, true);break ;case VIVID_CID_HAS_SCALER_CAP : +if (vb2_is_busy (&dev->vb_vid_cap_q)) +return -EBUSY ; dev->has_scaler_cap = ctrl->val;vivid_update_format_cap (dev, true);break ;
@@ -947,14 +953,20 @@ static int vivid_vid_out_s_ctrl(struct vswitch (ctrl->id) {case VIVID_CID_HAS_CROP_OUT : +if (vb2_is_busy (&dev->vb_vid_out_q)) +return -EBUSY ; dev->has_crop_out = ctrl->val;vivid_update_format_out (dev);break ;case VIVID_CID_HAS_COMPOSE_OUT : +if (vb2_is_busy (&dev->vb_vid_out_q)) +return -EBUSY ; dev->has_compose_out = ctrl->val;vivid_update_format_out (dev);break ;case VIVID_CID_HAS_SCALER_OUT : +if (vb2_is_busy (&dev->vb_vid_out_q)) +return -EBUSY ; dev->has_scaler_out = ctrl->val;vivid_update_format_out (dev);break ;
drivers/media/test-drivers/vivid/vivid-vid-cap.c +6 -0
@@ -385,6 +385,12 @@ void vivid_update_format_cap(struct viviunsigned size;u64 pixelclock; +/* +* This resets the format, so must never be called while vb2_is_busy(). +*/ +if (WARN_ON (vb2_is_busy (&dev->vb_vid_cap_q))) +return ; +switch (dev->input_type[dev->input]) {case WEBCAM :default :
drivers/media/test-drivers/vivid/vivid-vid-out.c +6 -0
@@ -222,6 +222,12 @@ void vivid_update_format_out(struct viviunsigned size, p;u64 pixelclock; +/* +* This resets the format, so must never be called while vb2_is_busy(). +*/ +if (WARN_ON (vb2_is_busy (&dev->vb_vid_out_q))) +return ; +switch (dev->output_type[dev->output]) {case SVID :default :
Greg Kroah-Hartman
maintainerPATCH 142/389 wifi: ath6kl: fix OOB access from firmware ADDBA window size
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 44126b6994eeb28f2103b638e698f40a1244f327 upstream.
aggr_recv_addba_req_evt() logs a debug message when the firmware-supplied win_sz is outside [AGGR_WIN_SZ_MIN, AGGR_WIN_SZ_MAX] but does not return. The out-of-range win_sz is then used in TID_WINDOW_SZ() to compute a kzalloc size and stored in rxtid->hold_q_sz, leading to zero-size or overflowed allocations and subsequent out-of-bounds access.
Clean up any previously active aggregation session for the TID first, then return early when win_sz is out of the valid range, instead of proceeding with a broken allocation size.
--- drivers/net/wireless/ath/ath6kl/txrx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/net/wireless/ath/ath6kl/txrx.c +6 -4
@@ -1722,13 +1722,15 @@ void aggr_recv_addba_req_evt(struct ath6 rxtid = &aggr_conn->rx_tid[tid]; -if (win_sz <AGGR_WIN_SZ_MIN || win_sz >AGGR_WIN_SZ_MAX ) -ath6kl_dbg (ATH6KL_DBG_WLAN_RX ,"%s: win_sz %d, tid %d\n" , - __func__, win_sz, tid); -if (rxtid->aggr)aggr_delete_tid_state (aggr_conn, tid); +if (win_sz <AGGR_WIN_SZ_MIN || win_sz >AGGR_WIN_SZ_MAX ) { +ath6kl_dbg (ATH6KL_DBG_WLAN_RX ,"%s: win_sz %d, tid %d\n" , + __func__, win_sz, tid); +return ; + } + rxtid->seq_next = seq_no; hold_q_size =TID_WINDOW_SZ (win_sz) *sizeof (struct skb_hold_q ); rxtid->hold_q =kzalloc (hold_q_size,GFP_KERNEL );
Greg Kroah-Hartman
maintainerPATCH 143/389 wifi: mwifiex: fix NULL dereference when the AP has HT-cap but no HT-oper
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit c3d68e294cbb6a4090bb219d3dcaca85a011809b upstream.
mwifiex_tdls_add_ht_oper() gates its follow-the-AP-bandwidth path on bss_desc->bcn_ht_cap being present, but then dereferences a different pointer, bss_desc->bcn_ht_oper:
if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) && bss_desc->bcn_ht_cap && ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param))
bcn_ht_cap and bcn_ht_oper are populated independently while parsing the associated AP's beacon in mwifiex_update_bss_desc_with_ie(): an AP that advertises an HT Capabilities element but no HT Operation element leaves bcn_ht_cap non-NULL and bcn_ht_oper NULL. Setting up a TDLS link to a peer while associated to such an AP then dereferences the NULL bcn_ht_oper and crashes the kernel. Every other bcn_ht_oper user in the driver NULL-checks it first.
Guard on the pointer that is actually dereferenced.
Found by 0sec automated security-research tooling (https://0sec.ai).
--- drivers/net/wireless/marvell/mwifiex/tdls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/marvell/mwifiex/tdls.c +1 -1
@@ -215,7 +215,7 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_/* follow AP's channel bandwidth */ if (ISSUPP_CHANWIDTH40 (priv->adapter->hw_dot_11n_dev_cap) && - bss_desc->bcn_ht_cap && + bss_desc->bcn_ht_oper &&ISALLOWED_CHANWIDTH40 (bss_desc->bcn_ht_oper->ht_param)) ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param;
Greg Kroah-Hartman
maintainerPATCH 144/389 wifi: wilc1000: validate assoc response length before subtracting header
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huihui Huang <[email protected]>
commit 4c4c97b60a5e978121d9ee8cb0ab3916e5d6a8de upstream.
wilc_parse_assoc_resp_info() computes the trailing IE length as
ies_len = buffer_len - sizeof(*res);
without first checking that buffer_len is at least sizeof(struct wilc_assoc_resp) (6 bytes). buffer_len is the length reported for a received association response (host_int_parse_assoc_resp_info() passes hif_drv->assoc_resp / assoc_resp_info_len straight in) and must be validated before the driver accesses the fixed header.
For a frame shorter than the 6-byte fixed header, the subtraction wraps. For a four-byte response the result is truncated to a u16 ies_len of 65534, so kmemdup() then attempts to copy 65534 bytes starting at buffer + sizeof(*res), beyond the valid association-response data (CWE-125). A response shorter than four bytes can also cause an out-of-bounds read of res->status_code at offsets 2 and 3.
Reject frames too short to hold the fixed header before touching the header or computing ies_len. Also set the connection status to a failure on this path: the caller falls through to a "conn_info->status == WLAN_STATUS_SUCCESS" check after the parser returns, so leaving the status untouched could let a malformed short response be treated as a successful association.
--- drivers/net/wireless/microchip/wilc1000/hif.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/wireless/microchip/wilc1000/hif.c +5 -0
@@ -582,6 +582,11 @@ static s32 wilc_parse_assoc_resp_info(u8u16 ies_len;struct wilc_assoc_resp *res = (struct wilc_assoc_resp *)buffer; +if (buffer_len <sizeof (*res)) { + ret_conn_info->status =WLAN_STATUS_UNSPECIFIED_FAILURE ; +return -EINVAL ; + } + ret_conn_info->status =le16_to_cpu (res->status_code);if (ret_conn_info->status ==WLAN_STATUS_SUCCESS ) { ies = &buffer[sizeof (*res)];
Greg Kroah-Hartman
maintainerPATCH 145/389 wifi: brcmfmac: make release_scratchbuffers idempotent
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 538c51e9d124cf656f2dd0c0394a8545efc7102d upstream.
brcmf_pcie_release_scratchbuffers() frees the shared.scratch and shared.ringupd DMA buffers with dma_free_coherent() but does not clear the pointers afterwards, unlike the sibling release_ringbuffers() which NULLs commonrings/flowrings/idxbuf on release.
Both the bus_reset .reset callback (brcmf_pcie_reset) and brcmf_pcie_remove() call release_scratchbuffers. When reset teardown has run before removal, remove's own teardown would call dma_free_coherent() a second time on the already-freed DMA allocation.
NULL the pointers after free, matching release_ringbuffers(), so a later release observes that the allocation has already been released. This patch makes repeated sequential release safe; the reset-work lifetime is handled separately by the following patch.
This issue was found by an in-house static analysis tool.
--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +6 -2
@@ -1246,16 +1246,20 @@ fail:static void brcmf_pcie_release_scratchbuffers (struct brcmf_pciedev_info *devinfo) { -if (devinfo->shared.scratch) +if (devinfo->shared.scratch) {dma_free_coherent (&devinfo->pdev->dev,BRCMF_DMA_D2H_SCRATCH_BUF_LEN , devinfo->shared.scratch, devinfo->shared.scratch_dmahandle); -if (devinfo->shared.ringupd) + devinfo->shared.scratch =NULL ; + } +if (devinfo->shared.ringupd) {dma_free_coherent (&devinfo->pdev->dev,BRCMF_DMA_D2H_RINGUPD_BUF_LEN , devinfo->shared.ringupd, devinfo->shared.ringupd_dmahandle); + devinfo->shared.ringupd =NULL ; + } }static int brcmf_pcie_init_scratchbuffers (struct brcmf_pciedev_info *devinfo)
Greg Kroah-Hartman
maintainerPATCH 146/389 Bluetooth: RFCOMM: Fix session UAF in set_termios
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit c783399efc22d035443f1dfbf2a09bf9562aaa5e upstream.
rfcomm_tty_set_termios() tests dlc->session without rfcomm_mutex and later passes the pointer to rfcomm_send_rpn(). The latter dereferences both session->initiator and session->sock. Meanwhile, krfcommd can unlink the DLC and free the session while holding rfcomm_mutex.
The race can proceed as follows:
TTY ioctl task krfcommd
-------------- --------
load dlc->session
enter rfcomm_send_rpn()
lock rfcomm_mutex
clear dlc->session
free session
unlock rfcomm_mutex read session->initiator
KASAN reported:
BUG: KASAN: slab-use-after-free in rfcomm_send_rpn+0x297/0x2a0 Read of size 4 at addr ffff88810012a850 by task poc/92 Call Trace: rfcomm_send_rpn+0x297/0x2a0 rfcomm_tty_set_termios+0x50d/0x850 tty_set_termios+0x596/0x950 set_termios+0x46a/0x6e0 tty_mode_ioctl+0x152/0xbd0 tty_ioctl+0x915/0x1240 __x64_sys_ioctl+0x134/0x1c0 Allocated by task 92: rfcomm_session_add+0x9e/0x2e0 rfcomm_dlc_open+0x8b1/0xe00 rfcomm_dev_activate+0x85/0x1a0 rfcomm_tty_open+0x90/0x280 Freed by task 68: kfree+0x131/0x3c0 rfcomm_session_del+0x119/0x180 rfcomm_run+0x737/0x4710
Add rfcomm_dlc_send_rpn(), which holds rfcomm_mutex while it verifies that the DLC is still attached and sends the RPN frame. Have the TTY path use the helper and drop its unlocked session check. This keeps the session valid through both the frame construction and socket send.
--- include/net/bluetooth/rfcomm.h | 3 +++ net/bluetooth/rfcomm/core.c | 17 +++++++++++++++++ net/bluetooth/rfcomm/tty.c | 7 +++---- 3 files changed, 23 insertions(+), 4 deletions(-)
include/net/bluetooth/rfcomm.h +3 -0
@@ -229,6 +229,9 @@ int rfcomm_send_rpn(struct rfcomm_sessio u8 bit_rate, u8 data_bits, u8 stop_bits, u8 parity, u8 flow_ctrl_settings, u8 xon_char, u8 xoff_char, u16 param_mask); +int rfcomm_dlc_send_rpn (struct rfcomm_dlc *d,u8 bit_rate,u8 data_bits, +u8 stop_bits,u8 parity,u8 flow_ctrl_settings, +u8 xon_char,u8 xoff_char,u16 param_mask);/* ---- RFCOMM DLCs (channels) ---- */ struct rfcomm_dlc *rfcomm_dlc_alloc (gfp_t prio);
net/bluetooth/rfcomm/core.c +17 -0
@@ -1027,6 +1027,23 @@ int rfcomm_send_rpn(struct rfcomm_sessioreturn rfcomm_send_frame (s, buf, ptr - buf); } +int rfcomm_dlc_send_rpn (struct rfcomm_dlc *d,u8 bit_rate,u8 data_bits, +u8 stop_bits,u8 parity,u8 flow_ctrl_settings, +u8 xon_char,u8 xoff_char,u16 param_mask) +{ +int err = -ENOTCONN ; + +rfcomm_lock (); +if (d->session) + err =rfcomm_send_rpn (d->session,1 , d->dlci, bit_rate, + data_bits, stop_bits, parity, + flow_ctrl_settings, xon_char, xoff_char, + param_mask); +rfcomm_unlock (); + +return err; +} +static int rfcomm_send_rls (struct rfcomm_session *s,int cr,u8 dlci,u8 status) {struct rfcomm_hdr *hdr;
net/bluetooth/rfcomm/tty.c +3 -4
@@ -866,7 +866,7 @@ static void rfcomm_tty_set_termios(strucBT_DBG ("tty %p termios %p" , tty, old); -if (!dev || !dev->dlc || !dev->dlc->session) +if (!dev || !dev->dlc)return ;/* Handle turning off CRTSCTS */
@@ -987,9 +987,8 @@ static void rfcomm_tty_set_termios(struc }if (changes) -rfcomm_send_rpn (dev->dlc->session,1 , dev->dlc->dlci, baud, - data_bits, stop_bits, parity, -RFCOMM_RPN_FLOW_NONE , x_on, x_off, changes); +rfcomm_dlc_send_rpn (dev->dlc, baud, data_bits, stop_bits, parity, +RFCOMM_RPN_FLOW_NONE , x_on, x_off, changes); }static void rfcomm_tty_throttle (struct tty_struct *tty)
Greg Kroah-Hartman
maintainerPATCH 147/389 exec: fix unsigned loop counter wrap in transfer_args_to_stack()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 16cc4f5c1c4b9e45eca7f7deefa5410a292db599 upstream.
The stop value is derived from bprm->p >> PAGE_SHIFT. The index variable is an unsigned long. If bprm->p drops below PAGE_SIZE and stop becomes zero the loop condition index >= stop is always true.
After the index == 0 iteration the decrement wraps to ULONG_MAX and bprm->page[ULONG_MAX] reads sizeof(void *) bytes in front of the array. The pointer has wrapped to -1. That garbage pointer is then passed to kmap_local_page() and PAGE_SIZE bytes are copied from wherever that lands into the stack of the process being created. And the loop doesn't terminate either...
Getting there only requires bprm->p < PAGE_SIZE. On !MMU bprm_set_stack_limit() and bprm_hit_stack_limit() are empty. So the only constraint on how far bprm->p is pushed down is valid_arg_len(), i.e. that each individual string still fits in what is left.
bprm->p starts at PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *) so a single argument or environment string of a little over 31 pages leaves it in the first page:
Oops - load access fault [#1]
CPU: 0 UID: 0 PID: 1 Comm: victim Not tainted 7.2.0-rc4 #1 epc : __memcpy+0xd4/0xf8 ra : transfer_args_to_stack+0xaa/0xae s4 : ffffffffffffffff s2 : 0000000000000000 a1 : ffffffdc98000000 a2 : 0000000000001000 status: 0000000a00001880 badaddr: ffffffdc98000000 cause: 0000000000000005 [<801a5324>] __memcpy+0xd4/0xf8 [<800d5f6a>] load_flat_binary+0x43a/0x65e [<800a2de4>] bprm_execve+0x1d4/0x316 [<800a351a>] do_execveat_common+0x12e/0x138 [<800a3d44>] __riscv_sys_execve+0x38/0x4e Kernel panic - not syncing: Fatal exception in interrupt
This is an arcane bug but we should still fix it.
Count down from MAX_ARG_PAGES so the loop ends when index reaches stop, stop == 0 included. The iterations performed are unchanged for every other value of stop.
Only CONFIG_MMU=n builds are affected, transfer_args_to_stack() is used by binfmt_flat and binfmt_elf_fdpic on nommu only.
The loop predates git history. commit 7e7ec6a93434 ("elf_fdpic_transfer_args_to_stack(): make it generic") only moved it from binfmt_elf_fdpic.c into fs/exec.c and narrowed the copy to the used part of the first page. The condition and the decrement are unchanged from 2.6.12-rc2.
--- fs/exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/exec.c +1 -1
@@ -876,7 +876,7 @@ int transfer_args_to_stack(struct linux_ stop = bprm->p >>PAGE_SHIFT ; sp = *sp_location; -for (index =MAX_ARG_PAGES -1 ; index >= stop; index--) { +for (index =MAX_ARG_PAGES ; index-- > stop; ) {unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK :0 ;char *src =kmap (bprm->page[index]) + offset; sp -=PAGE_SIZE - offset;
Greg Kroah-Hartman
maintainerPATCH 148/389 binfmt_misc: set have_execfd only once the interpreter is opened
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit bbf5f639918dc011aaf60aab8480218758ee68c5 upstream.
load_misc_binary() raises bprm->have_execfd as soon as it sees the 'O' (or 'C') flag. This happens well before it opens the interpreter. If that open fails the flag stays set on the bprm. binfmt_misc is at the head of the format list so an interpreter open failure that returns -ENOEXEC lets the search fall through to a later format. This means it runs the matched binary directly having never staged an interpreter. So bprm->executable is NULL while have_execfd falsely claims a descriptor is present.
Consequently, begin_new_exec() dereferences the missing executable:
would_dump(bprm, bprm->executable);
and NULL derefs. Had it not, the hand-off later in the same function would have failed anyway. FD_ADD(0, bprm->executable) rejects a NULL file with -ENOMEM. Both sites are past the point of no return so the exec cannot be unwound either way.
This can be reached by unprivileged users as binfmt_misc can be mounted in user namespaces. So a user can register an 'O' entry whose interpreter lives on a FUSE mount, have the FUSE server fail the open with -ENOEXEC and execute a native ELF file that matches the entry.
have_execfd only means anything alongside the executable it describes which is not set until the interpreter has been opened and staged. So lets raise it there, next to execfd_creds, which is already set at that point. An open failure now leaves it clear, so the fallback format derives credentials from the binary and emits no AT_EXECFD, as it would for any native exec. The argv rewrite load_misc_binary() performs before the open is still not undone. This means the binary sees the interpreter path in argv[0] and its own path in argv[1] but that predates this change and only became observable once the exec stopped faulting.
--- fs/binfmt_misc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
fs/binfmt_misc.c +2 -3
@@ -199,9 +199,6 @@ static int load_misc_binary(struct linux goto ret; } -if (fmt->flags &MISC_FMT_OPEN_BINARY ) - bprm->have_execfd =1 ; -/* make argv[1] be the path to the binary */ retval =copy_string_kernel (bprm->interp, bprm);if (retval <0 )
@@ -231,6 +228,8 @@ static int load_misc_binary(struct linux goto ret; bprm->interpreter = interp_file; +if (fmt->flags &MISC_FMT_OPEN_BINARY ) + bprm->have_execfd =1 ;if (fmt->flags &MISC_FMT_CREDENTIALS ) bprm->execfd_creds =1 ;
Greg Kroah-Hartman
maintainerPATCH 149/389 cdrom: fix stack out-of-bounds read in CDROMVOLCTRL
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit b27e195d4db8dea263050bdbeb11881b2999c9c6 upstream.
mmc_ioctl_cdrom_volume() first reads the audio control mode page into a 32-byte stack buffer with cgc->buflen set to 24. If the device reports a block descriptor, the function increases cgc->buflen to include that descriptor and reads the page again.
For CDROMVOLCTRL, the function then builds a MODE SELECT parameter list by moving cgc->buffer forward by offset - 8 bytes. This drops the block descriptor from the outgoing payload and leaves a new 8-byte mode parameter header in front of the audio control page. However, cgc->buflen is left unchanged.
With a standard 8-byte block descriptor, cgc->buffer points at buffer + 8 but cgc->buflen remains 32. cdrom_mode_select() therefore asks the low level packet path to write 32 bytes from that adjusted pointer, reading 8 bytes past the end of the 32-byte stack buffer.
This is not hit by CDROMVOLREAD, and CDROMVOLCTRL only triggers it on drives that return a non-zero block descriptor length, which helps explain why it has gone unnoticed. The overread is also sent to the device as extra MODE SELECT payload, so it may not produce an obvious local failure.
Reduce cgc->buflen by the same amount as the buffer pointer adjustment so the MODE SELECT transfer covers only the intended parameter list.
--- drivers/cdrom/cdrom.c | 1 + 1 file changed, 1 insertion(+)
drivers/cdrom/cdrom.c +1 -0
@@ -3218,6 +3218,7 @@ static noinline int mmc_ioctl_cdrom_volu/* set volume */ cgc->buffer = buffer + offset -8 ; + cgc->buflen -= offset -8 ;memset (cgc->buffer,0 ,8 );return cdrom_mode_select (cdi, cgc); }
Greg Kroah-Hartman
maintainerPATCH 150/389 comedi: comedi_parport: deal with premature interrupt
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Abbott <[email protected]>
commit 17221216ae8ce6a24e8a4e787382e3ebc81b88a8 upstream.
Syzbot reported a general protection fault in comedi_get_is_subdevice_running(), which was called from the interrupt handler parport_interrupt() in the "comedi_parport" driver, but it does not currently have a C reproducer for the problem. It's probably due to a premature interrupt for one of two reasons:
1. The driver sets up the interrupt handler before the comedi subdevices used by the interrupt handler have been allocated, but does not disable the interrupt in the parallel port's CTRL register first.
2. The driver uses a user-supplied I/O port base address which Syzbot would have supplied, but it might not be backed by real parallel port hardware.
Change the initialization order in the driver's comedi "attach" handler (parport_attach()) so that the hardware registers are initialized before the interrupt handler is requested. This should prevent premature interrupts occurring for real hardware.
Also add a test to the interrupt handler to ensure the comedi device is fully attached and return early if it isn't.
--- drivers/staging/comedi/drivers/comedi_parport.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/staging/comedi/drivers/comedi_parport.c +10 -3
@@ -211,6 +211,13 @@ static irqreturn_t parport_interrupt(intstruct comedi_subdevice *s = dev->read_subdev;unsigned int ctrl; +/* +* Check device is fully attached. Device interrupts should have +* been disabled, but do this in case of bad hardware. +*/ +if (!dev->attached) +return IRQ_NONE ; + ctrl =inb (dev->iobase +PARPORT_CTRL_REG );if (!(ctrl &PARPORT_CTRL_IRQ_ENA ))return IRQ_NONE ;
@@ -231,6 +238,9 @@ static int parport_attach(struct comedi_if (ret)return ret; +outb (0 , dev->iobase +PARPORT_DATA_REG ); +outb (0 , dev->iobase +PARPORT_CTRL_REG ); +if (it->options[1 ]) { ret =request_irq (it->options[1 ], parport_interrupt,0 , dev->board_name, dev);
@@ -286,9 +296,6 @@ static int parport_attach(struct comedi_ s->cancel = parport_intr_cancel; } -outb (0 , dev->iobase +PARPORT_DATA_REG ); -outb (0 , dev->iobase +PARPORT_CTRL_REG ); -return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 151/389 intel_th: fix MSC output device reference leak
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 761b785a0cfbce43761227bc42a7f984f31f8921 upstream.
intel_th_output_open() looks up the output device with bus_find_device_by_devt(), which returns the device with a reference that must be dropped after use.
commit 95fc36a234da ("intel_th: fix device leak on output open()") attempted to drop the reference from intel_th_output_release(). However, a successful open replaces file->f_op with the output driver file operations before returning, so close runs the output driver release callback instead.
For MSC outputs, close runs intel_th_msc_release(), which only removes the per-file iterator and does not drop the device reference taken by intel_th_output_open(). Consequently, every successful MSC output open leaks one device reference.
Drop the device reference from intel_th_msc_release(), which is the release path actually used for MSC output files. Remove the now-unused intel_th_output_release() callback from intel_th_output_fops.
--- drivers/hwtracing/intel_th/core.c | 10 ---------- drivers/hwtracing/intel_th/msu.c | 2 ++ 2 files changed, 2 insertions(+), 10 deletions(-)
drivers/hwtracing/intel_th/core.c +0 -10
@@ -843,18 +843,8 @@ out_put_device:return err; } -static int intel_th_output_release (struct inode *inode,struct file *file) -{ -struct intel_th_device *thdev = file->private_data; - -put_device (&thdev->dev); - -return 0 ; -} -static const struct file_operations intel_th_output_fops = { .open = intel_th_output_open, - .release = intel_th_output_release, .llseek = noop_llseek, };
drivers/hwtracing/intel_th/msu.c +2 -0
@@ -1463,8 +1463,10 @@ static int intel_th_msc_release(struct i {struct msc_iter *iter = file->private_data;struct msc *msc = iter->msc; +struct intel_th_device *thdev = msc->thdev;msc_iter_remove (iter, msc); +put_device (&thdev->dev);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 152/389 tracing: Fix mmiotrace possible NULL dereferencing of hiter->dev
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
commit 144f29e85702234b23d2a62abf723e6a17eb5427 upstream.
If the mmio_pipe_open() fails to find a PCI device, the hiter->dev will be assigned to NULL. The mmiotrace read() function dereferences the hiter->dev if hiter exists.
Change the test of the read to not only check hiter being NULL, but also the hiter->dev before dereferencing it.
--- kernel/trace/trace_mmiotrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_mmiotrace.c +1 -1
@@ -148,7 +148,7 @@ static ssize_t mmio_read(struct trace_it goto print_out; } -if (!hiter) +if (!hiter || !hiter->dev)return 0 ;mmio_print_pcidev (s, hiter->dev);
Greg Kroah-Hartman
maintainerPATCH 153/389 tracing: Fix resource leak on mmiotrace trace_pipe close
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: deepakraog <[email protected]>
commit c1d87e724ae55e781b7cc7ccafb34d9e668582b2 upstream.
The mmiotrace tracer was added May 12th 2008. At that time, resources created in pipe_open() could not be freed because there was not pipe_close function pointer of the tracer. The pipe_close function pointer was added in December 7th, 2009, but the mmiotrace tracer was not updated.
mmio_pipe_open() allocates a header_iter and takes a pci_dev reference when trace_pipe is opened. mmio_close() frees them, but it was only wired to the tracer's .close callback.
tracing_release_pipe() invokes .pipe_close, not .close, when the trace_pipe file is released. As a result, closing trace_pipe with the mmiotrace tracer active leaked the header_iter allocation and left a stale pci_dev reference.
Set .pipe_close to mmio_close, matching how function_graph wires both callbacks to the same handler.
Note, if the trace_pipe is read to completion, it will clean up the resources, but if one were to run:
# head -n 1 /sys/kernel/tracing/trace_pipe VERSION 20070824
Over and over again, it would trigger a massive leak.
--- kernel/trace/trace_mmiotrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_mmiotrace.c +1 -1
@@ -111,7 +111,6 @@ static void mmio_pipe_open(struct trace_ iter->private = hiter; } -/* XXX: This is not called when the pipe is closed! */ static void mmio_close (struct trace_iterator *iter) {struct header_iter *hiter = iter->private;
@@ -281,6 +280,7 @@ static struct tracer mmio_tracer __read_ .start = mmio_trace_start, .pipe_open = mmio_pipe_open, .close = mmio_close, + .pipe_close = mmio_close, .read = mmio_read, .print_line = mmio_print_line, .noboot = true,
Greg Kroah-Hartman
maintainerPATCH 154/389 tracing/probes: Avoid temporary buffer truncation in trace_probe_match_command_args()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit 15f197856d68882af9416fc97516bb55079b7677 upstream.
In trace_probe_match_command_args(), a stack buffer buf[MAX_ARGSTR_LEN + 1] (256 bytes) is used to format "<name>=<comm>". However, since name can be up to 32 bytes (MAX_ARG_NAME_LEN) and comm up to 255 bytes (MAX_ARGSTR_LEN), the formatted string can exceed 256 bytes and get truncated by snprintf(), causing spurious argument matching failures.
Instead of formatting into a temporary buffer on stack, compare the argument name, the '=' delimiter, and the comm expression directly.
--- kernel/trace/trace_probe.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
kernel/trace/trace_probe.c +5 -4
@@ -1150,16 +1150,17 @@ int trace_probe_compare_arg_type(structbool trace_probe_match_command_args (struct trace_probe *tp,int argc,const char **argv) { -char buf[MAX_ARGSTR_LEN +1 ];int i;if (tp->nr_args < argc)return false;for (i =0 ; i < argc; i++) { -snprintf (buf,sizeof (buf),"%s=%s" , - tp->args[i].name, tp->args[i].comm); -if (strcmp (buf, argv[i])) +int len =strlen (tp->args[i].name); + +if (strncmp (argv[i], tp->args[i].name, len) || + argv[i][len] !='=' || +strcmp (argv[i] + len +1 , tp->args[i].comm))return false; }return true;
Greg Kroah-Hartman
maintainerPATCH 155/389 tracing/probes: Fix potential underflow in LEN_OR_ZERO macro
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit 8ce20bfba48902e1382187cd1a852f7cf3a1e739 upstream.
In __set_print_fmt(), LEN_OR_ZERO is defined as (len ? len - pos : 0). If len is non-zero but smaller than pos, len - pos evaluates to a negative integer. When passed as a size argument to snprintf(), this negative value is cast to a large unsigned size_t, bypassing buffer size limits.
Ensure len > pos before subtracting to avoid integer underflow.
--- kernel/trace/trace_probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_probe.c +1 -1
@@ -842,7 +842,7 @@ int traceprobe_update_arg(struct probe_a }/* When len=0, we just calculate the needed length */ -#define LEN_OR_ZERO (len ? len - pos : 0) +#define LEN_OR_ZERO (len > pos ? len - pos : 0)static int __set_print_fmt (struct trace_probe *tp,char *buf,int len,bool is_return) {
Greg Kroah-Hartman
maintainerPATCH 156/389 tracing/probes: Prevent out-of-bounds write in __trace_probe_log_err()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit a9d6fb284039a5d3858a1d9f9a0d7e46cfb7c2d4 upstream.
If trace_probe_log.argc is 0 in __trace_probe_log_err(), the loop constructing the command string will not execute and p will remain equal to command. Writing to *(p - 1) will cause an out-of-bounds access before command. This should not happen, but better to be treated.
Reject if trace_probe_log.argc is 0.
--- kernel/trace/trace_probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_probe.c +1 -1
@@ -165,7 +165,7 @@ void __trace_probe_log_err(int offset, ichar *command, *p;int i, len =0 , pos =0 ; -if (!trace_probe_log.argv) +if (!trace_probe_log.argv || !trace_probe_log.argc)return ;/* Recalcurate the length and allocate buffer */
Greg Kroah-Hartman
maintainerPATCH 157/389 arm64: syscall: Ensure saved x0 is kept in-sync with tracer updates
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Will Deacon <[email protected]>
commit e057b94772328221405b067c3a85fe479b915dc8 upstream.
When seccomp support was originally added to arm64 in a1ae65b21941 ("arm64: add seccomp support"), seccomp was erroneously called _before_ the ptrace syscall-enter-stop and therefore the tracer could trivially manipulate the syscall register state after the seccomp check had passed. This was subsequently fixed in a5cd110cb836 ("arm64/ptrace: run seccomp after ptrace") by moving the seccomp check after the tracer has run. Unfortunately, a decade later, that fix has been reported to be incomplete.
On arm64, both the first argument to a syscall and its eventual return value are allocated to register x0. In order to facilitate syscall restarting and querying of syscall arguments on the syscall exit path, the original value of x0 is stashed in 'struct pt_regs::orig_x0' early during the syscall entry path and is returned for the first argument by syscall_get_arguments(). Unlike 32-bit Arm, this stashed value is not directly exposed via ptrace() and so changes to register x0 made by the tracer on a syscall-enter-stop are not reflected in 'orig_x0'. This means that seccomp, syscall tracepoints and audit can observe a stale value for the register compared to the argument that will be observed by the actual syscall.
Re-sync 'orig_x0' from x0 on the syscall entry path following a potential ptrace stop (i.e. PTRACE_EVENTMSG_SYSCALL_ENTRY or SECCOMP_RET_TRACE). This behaviour is limited to native tasks (because compat tasks expose 'orig_r0' to ptrace) where the syscall is not being skipped (because x0 is updated to hold the return value of -ENOSYS in that case).
--- arch/arm64/kernel/ptrace.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
arch/arm64/kernel/ptrace.c +29 -0
@@ -1797,6 +1797,21 @@ static void tracehook_report_syscall(str } } +static void update_syscall_orig_x0_after_ptrace (struct pt_regs *regs) +{ +/* +* Keep orig_x0 authoritative so that seccomp (via +* syscall_get_arguments()), audit and the restart path all see the same +* first argument the syscall is dispatched with, even if it has been +* updated by a tracer. Skip this for NO_SYSCALL (set either by the user +* or the tracer), as regs[0] holds the return value (see the comment in +* el0_svc_common()) and can be unwound using syscall_rollback(). +* For compat tasks, orig_r0 is provided directly through GPR index 17. +*/ +if (!is_compat_task () && regs->syscallno !=NO_SYSCALL ) + regs->orig_x0 = regs->regs[0 ]; +} +int syscall_trace_enter (struct pt_regs *regs) {unsigned long flags =READ_ONCE (current_thread_info ()->flags);
@@ -1805,12 +1820,26 @@ int syscall_trace_enter(struct pt_regs *tracehook_report_syscall (regs,PTRACE_SYSCALL_ENTER );if (flags & _TIF_SYSCALL_EMU)return NO_SYSCALL ; + +/* +* Ensure ptrace changes to x0 during a regular +* syscall-enter-stop (PTRACE_SYSCALL) are visible to +* subsequent seccomp checks, tracepoints and audit. +*/ +update_syscall_orig_x0_after_ptrace (regs); }/* Do the secure computing after ptrace; failures should be fast. */ if (secure_computing () ==-1 )return NO_SYSCALL ; +/* +* Ensure tracer changes to x0 during seccomp ptrace exit +* processing (SECCOMP_RET_TRACE) are visible to tracepoints and +* audit. +*/ +update_syscall_orig_x0_after_ptrace (regs); +if (test_thread_flag (TIF_SYSCALL_TRACEPOINT ))trace_sys_enter (regs, regs->syscallno);
Greg Kroah-Hartman
maintainerPATCH 158/389 Revert "arm64: syscall: Ensure saved x0 is kept in-sync with tracer updates"
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Will Deacon <[email protected]>
commit 26b483d52417253d88a3a01262ac85914a7aec8e upstream.
This reverts commit e057b94772328221405b067c3a85fe479b915dc8.
Sashiko points out that updating 'orig_x0' after secure_computing() has returned is too late to handle the case where a seccomp filter is re-evaluated after initially returning SECCOMP_RET_TRACE. This means that a tracer can manipulate the first argument of the syscall behind seccomp's back.
For now, revert the initial fix and we'll have another crack at it soon. Since the incorrect fix was cc'd to stable, do the same here with an appropriate fixes tag.
--- arch/arm64/kernel/ptrace.c | 29 ----------------------------- 1 file changed, 29 deletions(-)
arch/arm64/kernel/ptrace.c +0 -29
@@ -1797,21 +1797,6 @@ static void tracehook_report_syscall(str } } -static void update_syscall_orig_x0_after_ptrace (struct pt_regs *regs) -{ -/* -* Keep orig_x0 authoritative so that seccomp (via -* syscall_get_arguments()), audit and the restart path all see the same -* first argument the syscall is dispatched with, even if it has been -* updated by a tracer. Skip this for NO_SYSCALL (set either by the user -* or the tracer), as regs[0] holds the return value (see the comment in -* el0_svc_common()) and can be unwound using syscall_rollback(). -* For compat tasks, orig_r0 is provided directly through GPR index 17. -*/ -if (!is_compat_task () && regs->syscallno !=NO_SYSCALL ) - regs->orig_x0 = regs->regs[0 ]; -} -int syscall_trace_enter (struct pt_regs *regs) {unsigned long flags =READ_ONCE (current_thread_info ()->flags);
@@ -1820,26 +1805,12 @@ int syscall_trace_enter(struct pt_regs *tracehook_report_syscall (regs,PTRACE_SYSCALL_ENTER );if (flags & _TIF_SYSCALL_EMU)return NO_SYSCALL ; - -/* -* Ensure ptrace changes to x0 during a regular -* syscall-enter-stop (PTRACE_SYSCALL) are visible to -* subsequent seccomp checks, tracepoints and audit. -*/ -update_syscall_orig_x0_after_ptrace (regs); }/* Do the secure computing after ptrace; failures should be fast. */ if (secure_computing () ==-1 )return NO_SYSCALL ; -/* -* Ensure tracer changes to x0 during seccomp ptrace exit -* processing (SECCOMP_RET_TRACE) are visible to tracepoints and -* audit. -*/ -update_syscall_orig_x0_after_ptrace (regs); -if (test_thread_flag (TIF_SYSCALL_TRACEPOINT ))trace_sys_enter (regs, regs->syscallno);
Greg Kroah-Hartman
maintainerPATCH 159/389 sctp: dont free the ASCONFs own transport in DEL-IP processing
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jun Yang <[email protected]>
commit 9b2854f86f0b56e9027d68e7a3fc909d1a9b566f upstream.
sctp_process_asconf() caches the transport the ASCONF chunk is processed against in asconf->transport (== chunk->transport, set once in sctp_rcv()). For an ASCONF located through its Address Parameter by __sctp_rcv_asconf_lookup(), that cached transport corresponds to the Address Parameter, which need not be the packet's source address.
sctp_process_asconf_param() rejects a DEL-IP for the packet source address (ADDIP D8, SCTP_ERROR_DEL_SRC_IP), but nothing protects asconf->transport. A single ASCONF can therefore carry, in order:
[Address Parameter L] [DEL-IP L] [DEL-IP 0.0.0.0]
where L differs from the source. The DEL-IP for L passes the D8 check and calls sctp_assoc_rm_peer() on the transport that asconf->transport still points at, freeing it (RCU-deferred). The following wildcard DEL-IP then reuses the now-dangling asconf->transport in sctp_assoc_set_primary() and sctp_assoc_del_nonprimary_peers(): set_primary() dereferences the freed transport (->ipaddr, ->state) and plants the dangling pointer into asoc->peer.primary_path / active_path, and del_nonprimary_peers(), keeping only the pointer that is no longer on the list, removes every real transport, leaving the association with a transport_count of 0 and primary_path/active_path pointing at freed memory.
Reject a DEL-IP that targets the transport the ASCONF is being processed against, mirroring the existing source-address guard, so the wildcard branch can never reuse a freed transport.
--- net/sctp/sm_make_chunk.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/sctp/sm_make_chunk.c +6 -0
@@ -3133,6 +3133,12 @@ static __be16 sctp_process_asconf_param(if (!peer)return SCTP_ERROR_DNS_FAILED ; +/* Don't free asconf->transport; a later wildcard DEL-IP +* parameter reuses it. +*/ +if (peer == asconf->transport) +return SCTP_ERROR_REQ_REFUSED ; +sctp_assoc_rm_peer (asoc, peer);break ;case SCTP_PARAM_SET_PRIMARY :
Greg Kroah-Hartman
maintainerPATCH 160/389 ceph: fix pre-auth out-of-bounds read on snaptrace in ceph_handle_caps()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 4dbc71bcaf9a30abf3920a4e2cc4ed33bba78c02 upstream.
ceph_handle_caps() reads snap_trace_len from the wire-format ceph_mds_caps header and uses it unconditionally to build a fake end pointer (snaptrace + snaptrace_len) that is later handed to ceph_update_snap_trace() in the CEPH_CAP_OP_IMPORT case:
snaptrace = h + 1;
snaptrace_len = le32_to_cpu(h->snap_trace_len);
p = snaptrace + snaptrace_len;
...
case CEPH_CAP_OP_IMPORT:
if (snaptrace_len) {
...
if (ceph_update_snap_trace(mdsc, snaptrace,
snaptrace + snaptrace_len,
false, &realm)) { ... }ceph_update_snap_trace() then decodes a struct ceph_mds_snap_realm from snaptrace using ceph_decode_need(&p, e, sizeof(*ri), bad) with the attacker-supplied fake end e == snaptrace + snaptrace_len. With snaptrace_len == 0xFFFFFFFF the bound check is trivially satisfied, ri = p reads sizeof(struct ceph_mds_snap_realm) past the legitimate msg->front buffer, and ri->num_snaps / ri->num_prior_parent_snaps then drive further out-of-bounds reads of the encoded snap arrays.
The eleven msg_version >= 2 .. msg_version >= 12 decoder blocks above the op switch each catch this OOB through their ceph_decode_*_safe() / ceph_decode_need() helpers, but they sit behind a hdr.version-gated if, so a malicious or compromised MDS that sets msg->hdr.version = 1 reaches the IMPORT path with no version-gated decoder having validated snap_trace_len. The shape has been present since ceph_handle_caps() was introduced.
Validate snap_trace_len against the message front buffer before consuming it, using the canonical ceph_decode_need() / ceph_has_room() helper. The helper bounds the length with subtraction (n <= end - p, guarded by end >= p) rather than pointer addition, so it is wrap-safe for the attacker-controlled u32 length on 32-bit builds where p + snap_trace_len could overflow the address space. This matches the rest of the ceph decode path (e.g. the pool_ns_len check a few lines below), and the existing goto bad cleanup already covers this exit path.
--- fs/ceph/caps.c | 1 + 1 file changed, 1 insertion(+)
fs/ceph/caps.c +1 -0
@@ -4125,6 +4125,7 @@ void ceph_handle_caps(struct ceph_mds_se snaptrace = h +1 ; snaptrace_len =le32_to_cpu (h->snap_trace_len); +ceph_decode_need (&snaptrace, end, snaptrace_len, bad); p = snaptrace + snaptrace_len;if (msg_version >=2 ) {
Greg Kroah-Hartman
maintainerPATCH 161/389 libceph: bound get_version reply decode to front len
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Douya Le <[email protected]>
commit d3c32939fa0e3ee9b883b9a0fd1972c5c444e3d0 upstream.
handle_get_version_reply() uses msg->front_alloc_len as the decode boundary for MON_GET_VERSION_REPLY. That is the size of the reused reply buffer, not the number of bytes actually received.
A truncated reply can therefore pass ceph_decode_need() and decode the second u64 from stale tail bytes left in the buffer by an earlier message, causing an uninitialized memory read.
Use msg->front.iov_len as the receive-side decode boundary, matching other libceph reply handlers and limiting decoding to the bytes that were actually read from the wire.
--- net/ceph/mon_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ceph/mon_client.c +1 -1
@@ -748,7 +748,7 @@ static void handle_get_version_reply(strstruct ceph_mon_generic_request *req;u64 tid =le64_to_cpu (msg->hdr.tid);void *p = msg->front.iov_base; -void *end = p + msg->front_alloc_len; +void *const end = p + msg->front.iov_len;u64 handle;dout ("%s msg %p tid %llu\n" , __func__, msg, tid);
Greg Kroah-Hartman
maintainerPATCH 162/389 libceph: Fix multiplication overflow in decode_new_up_state_weight()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit 98917a499ec7064c14fc56d180a4fd636fc2784c upstream.
If a message of type CEPH_MSG_OSD_MAP contains a (maliciously) corrupted osdmap, out-of-bounds memory accesses may occur in decode_new_up_state_weight(). This happens because the bounds check for the new_state part is based on calculating its length depending on a len value read from the incoming message. This calculation may overflow leading to an incorrect bounds check. Subsequently, out-of-bounds reads may occur when decoding this part.
This patch switches the multiplication to use check_mul_overflow() to abort processing the osdmap if an overflow occurred. Therefore, osdmaps/messages containing large values for len that result in a multiplication overflow are treated as invalid.
[ idryomov: rename new_state_len -> new_state_item_size, formatting ]
--- net/ceph/osdmap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/ceph/osdmap.c +4 -1
@@ -1822,6 +1822,8 @@ static int decode_new_up_state_weight(vovoid *new_up_client;void *new_state;void *new_weight_end; +const u32 new_state_item_size = +sizeof (u32) + (struct_v >=5 ?sizeof (u32) :sizeof (u8));u32 len;int i;
@@ -1837,7 +1839,8 @@ static int decode_new_up_state_weight(vo new_state = *p;ceph_decode_32_safe (p, end, len, e_inval); - len *=sizeof (u32) + (struct_v >=5 ?sizeof (u32) :sizeof (u8)); +if (check_mul_overflow (len, new_state_item_size, &len)) + goto e_inval;ceph_decode_need (p, end, len, e_inval); *p += len;
Greg Kroah-Hartman
maintainerPATCH 163/389 libceph: guard missing CRUSH type name lookup
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Zhang <[email protected]>
commit bbeae12fda3384a90fbebc8a19ba9d33f85b5361 upstream.
Localized read selection can walk a parent bucket whose name exists in the CRUSH map while its type has no matching entry in type_names. get_immediate_parent() then dereferences a NULL type_cn and passes an invalid pointer into strcmp(), causing a null-ptr-deref.
Skip such malformed parent buckets unless both the bucket name and type name metadata are present. This keeps malformed hierarchy data from crashing locality lookup and safely falls back to "not local".
[ idryomov: add WARN_ON_ONCE ]
--- net/ceph/osdmap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/ceph/osdmap.c +4 -1
@@ -3021,8 +3021,11 @@ static int get_immediate_parent(struct cif (b->items[j] != id)continue ; - *parent_type_id = b->type; type_cn =lookup_crush_name (&c->type_names, b->type); +if (WARN_ON_ONCE (!type_cn)) +continue ; + + *parent_type_id = b->type; parent_loc->cl_type_name = type_cn->cn_name; parent_loc->cl_name = cn->cn_name;return b->id;
Greg Kroah-Hartman
maintainerPATCH 164/389 libceph: refresh auth->authorizer_buf{,_len} after authorizer update
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
commit 937d61f86d377a3aa578adae7a3dfcecdddf9d89 upstream.
ceph_x_create_authorizer() caches au->buf->vec.iov_base and au->buf->vec.iov_len in struct ceph_auth_handshake. These cached values are then used by the messenger connect code when sending the authorizer.
ceph_x_update_authorizer() can rebuild the authorizer when a newer service ticket is available. If the rebuilt authorizer no longer fits in the existing buffer, ceph_x_build_authorizer() drops its reference to au->buf and allocates a new one. If this is the final reference, ceph_buffer_put() frees the old ceph_buffer and its vec.iov_base, but auth->authorizer_buf still points at that freed memory.
A subsequent msgr1 reconnect can therefore queue the stale pointer and trigger a KASAN slab-use-after-free in _copy_from_iter() while tcp_sendmsg() copies the authorizer.
Refresh auth->authorizer_buf and auth->authorizer_buf_len after a successful authorizer rebuild so the messenger sends the current buffer.
--- net/ceph/auth_x.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
net/ceph/auth_x.c +8 -1
@@ -671,9 +671,16 @@ static int ceph_x_update_authorizer( au = (struct ceph_x_authorizer *)auth->authorizer;if (au->secret_id < th->secret_id) { +int ret; +dout ("ceph_x_update_authorizer service %u secret %llu < %llu\n" , au->service, au->secret_id, th->secret_id); -return ceph_x_build_authorizer (ac, th, au); + ret =ceph_x_build_authorizer (ac, th, au); +if (ret) +return ret; + + auth->authorizer_buf = au->buf->vec.iov_base; + auth->authorizer_buf_len = au->buf->vec.iov_len; }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 165/389 libceph: reject zero bucket types in crush_decode
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Douya Le <[email protected]>
commit 05f90284223381005d6bcddab3fda4a97f9c3401 upstream.
CRUSH bucket type 0 is reserved for devices. The mapper relies on that invariant and uses type 0 to identify leaf devices.
If crush_decode() accepts a bucket with type 0, a malformed CRUSH map can make the mapper treat a negative bucket ID as a device and pass it to is_out(), which then indexes the OSD weight array with a negative value.
Reject zero bucket types while decoding the CRUSH map so the invalid state never reaches the mapper.
--- net/ceph/osdmap.c | 2 ++ 1 file changed, 2 insertions(+)
net/ceph/osdmap.c +2 -0
@@ -504,6 +504,8 @@ static struct crush_map *crush_decode(voceph_decode_need (p, end,4 *sizeof (u32), bad); b->id =ceph_decode_32 (p); b->type =ceph_decode_16 (p); +if (b->type ==0 ) + goto bad; b->alg =ceph_decode_8 (p);if (b->alg != alg) { b->alg =0 ;
Greg Kroah-Hartman
maintainerPATCH 166/389 libceph: remove debugfs files before client teardown
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Douya Le <[email protected]>
commit e4c804726c4afce3ba648b982d564f6af2cfa328 upstream.
ceph_destroy_client() tears down the monitor client before removing the per-client debugfs files. A concurrent read of the monmap debugfs file can enter monmap_show() after ceph_monc_stop() has freed monc->monmap, triggering a use-after-free.
Remove the debugfs files before stopping the OSD and monitor clients. debugfs_remove() drains active handlers and prevents new accesses, so the debugfs callbacks can no longer race the rest of client teardown.
--- net/ceph/ceph_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/ceph/ceph_common.c +2 -2
@@ -727,13 +727,13 @@ void ceph_destroy_client(struct ceph_cliatomic_set (&client->msgr.stopping,1 ); +ceph_debugfs_client_cleanup (client); +/* unmount */ ceph_osdc_stop (&client->osdc);ceph_monc_stop (&client->monc);ceph_messenger_fini (&client->msgr); -ceph_debugfs_client_cleanup (client); -ceph_destroy_options (client->options);kfree (client);
Greg Kroah-Hartman
maintainerPATCH 167/389 binfmt_elf_fdpic: only honour the first PT_INTERP
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 3349ef6a366a61d631f6a263d12cea240957719d upstream.
The program header scan handles PT_INTERP from a switch nested in the scan loop, so its break leaves the switch and not the loop. A binary carrying more than one PT_INTERP runs the case again and overwrites both interpreter_name and interpreter. The previous name allocation leaks and so does the previous interpreter reference, along with the write denial open_exec() took on it. The denial is never released, so the file stays unwritable for as long as the system runs.
An unprivileged caller reaches this with a crafted binary and repeats it at will. binfmt_elf stops at the first PT_INTERP. Do the same here.
The flaw dates back to the driver's introduction in the pre-git history tree introduced in v2.6.11 by 91808d6ebe39 ("[PATCH] FRV: Add FDPIC ELF binary format driver").
--- fs/binfmt_elf_fdpic.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/binfmt_elf_fdpic.c +4 -0
@@ -231,6 +231,10 @@ static int load_elf_fdpic_binary(structfor (i =0 ; i < exec_params.hdr.e_phnum; i++, phdr++) {switch (phdr->p_type) {case PT_INTERP : +/* elf ABI allows only one interpreter */ +if (interpreter_name) +continue ; + retval = -ENOMEM ;if (phdr->p_filesz >PATH_MAX ) goto error;
Greg Kroah-Hartman
maintainerPATCH 168/389 iommu/vt-d: Disallow SVA if page walk is not coherent
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Baolu <[email protected]>
commit 780dfed688622ea01be3c9c2c55eec2207f05e04 upstream.
Hardware implementations report Scalable-Mode Page-walk Coherency Support via the SMPWCS field in the extended capability register. If the hardware does not support page-walk coherency, a clflush is required every time the page table entries (which are walked by the IOMMU hardware) are updated.
In the SVA case, page tables are managed by the CPU mm core, not by the IOMMU driver. Because the IOMMU driver has no way of knowing whether the CPU page table management code has ensured coherency via clflush, the driver must deny SVA if the hardware does not support coherent paging.
--- drivers/iommu/intel/svm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/intel/svm.c +1 -1
@@ -98,7 +98,7 @@ static inline bool intel_svm_capable(strvoid intel_svm_check (struct intel_iommu *iommu) { -if (!pasid_supported (iommu)) +if (!pasid_supported (iommu) || !ecap_smpwc (iommu->ecap))return ; if (cpu_feature_enabled(X86_FEATURE_GBPAGES) &&
Greg Kroah-Hartman
maintainerPATCH 169/389 phonet: pep: fix use-after-free in pep_get_sb()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
commit 0f71f852a96af9685858ce59fda34ecbf85c283d upstream.
pep_get_sb() doesn't consider that pskb_may_pull() might have relocated the skb data, and continue to access the older pointer, causing UAF.
Reproduced under KASAN:
BUG: KASAN: slab-use-after-free in pep_get_sb+0x234/0x3b0 Read of size 1 at addr ff11000105510f50 by task repro/157 pep_get_sb+0x234/0x3b0 pipe_handler_do_rcv+0x5f7/0xa10 pep_do_rcv+0x203/0x410 __sk_receive_skb+0x471/0x4a0 phonet_rcv+0x5b3/0x6c0 __netif_receive_skb+0xcc/0x1d0
Refetch the header with skb_header_pointer() after pskb_may_pull(), so the possibly stale pointer is no longer dereferenced. There are better ways to solve this, but, this is the less instrusive one.
--- net/phonet/pep.c | 2 ++ 1 file changed, 2 insertions(+)
net/phonet/pep.c +2 -0
@@ -55,6 +55,8 @@ static unsigned char *pep_get_sb(struct ph =skb_header_pointer (skb,0 ,2 , &h);if (ph ==NULL || ph->sb_len <2 || !pskb_may_pull (skb, ph->sb_len))return NULL ; +/* pskb_may_pull() may have reallocated the head; refetch ph. */ + ph =skb_header_pointer (skb,0 ,2 , &h); ph->sb_len -=2 ; *ptype = ph->sb_type; *plen = ph->sb_len;
Greg Kroah-Hartman
maintainerPATCH 170/389 vxlan: require CAP_NET_ADMIN in the device netns for changelink
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit 3a61bd9637f3d929aa846e4eb3d98b48c26fcb0e upstream.
A tunnel changelink() operates on at most two netns, dev_net(dev) and the sticky underlay netns vxlan->net. They differ once the device is created in or moved to a netns other than the one the request runs in. The rtnl changelink path checks CAP_NET_ADMIN only against dev_net(dev), so a caller privileged there but not in vxlan->net can rewrite a vxlan device whose underlay lives in vxlan->net.
vxlan_changelink() validates and applies the new configuration against vxlan->net (vxlan_config_validate(vxlan->net, ...)) and can reopen the underlay socket in that netns, so the same reasoning as the tunnel changelink series applies here.
Gate vxlan_changelink() with rtnl_dev_link_net_capable(), at the top of the op before any attribute is parsed, matching ipgre_changelink() and the rest of the "require CAP_NET_ADMIN in the device netns for changelink" series.
Found by 0sec automated security-research tooling (https://0sec.ai).
--- drivers/net/vxlan/vxlan_core.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/vxlan/vxlan_core.c +3 -0
@@ -4255,6 +4255,9 @@ static int vxlan_changelink(struct net_dstruct vxlan_rdst *dst;int err; +if (!rtnl_dev_link_net_capable (dev, vxlan->net)) +return -EPERM ; + dst = &vxlan->default_dst; err =vxlan_nl2conf (tb, data, dev, &conf, true, extack);if (err)
Greg Kroah-Hartman
maintainerPATCH 171/389 net: slip: serialize receive against buffer reallocation
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sungmin Kang <[email protected]>
commit ee7f9bb9320add61f7b367d7e6cd55e3a3a4d65d upstream.
sl_realloc_bufs() replaces rbuff and updates buffsize while holding sl->lock. slip_receive_buf() reads those fields and writes through rbuff without holding the lock.
An MTU change can therefore race with receive processing. An MTU shrink can expose the new smaller rbuff with the old larger bound, causing an out-of-bounds write. A receive callback which already loaded the old rbuff can instead continue writing after that buffer has been freed.
Serialize receive processing with sl_realloc_bufs() by holding sl->lock while consuming each receive batch.
--- drivers/net/slip/slip.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/slip/slip.c +4 -0
@@ -692,6 +692,8 @@ static void slip_receive_buf(struct tty_if (!sl || sl->magic !=SLIP_MAGIC || !netif_running (sl->dev))return ; +spin_lock_bh (&sl->lock); +/* Read the characters out of the buffer */ while (count--) {if (fp && *fp++) {
@@ -707,6 +709,8 @@ static void slip_receive_buf(struct tty_#endif slip_unesc (sl, *cp++); } + +spin_unlock_bh (&sl->lock); }/************************************
Greg Kroah-Hartman
maintainerPATCH 172/389 geneve: require CAP_NET_ADMIN in the device netns for changelink
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit 8efb8f8bbb353b8f2fdf4f37534c6d96c9f69e01 upstream.
A tunnel changelink() operates on at most two netns, dev_net(dev) and the sticky underlay netns geneve->net. They differ once the device is created in or moved to a netns other than the one the request runs in. The rtnl changelink path checks CAP_NET_ADMIN only against dev_net(dev), so a caller privileged there but not in geneve->net can rewrite a geneve device whose underlay lives in geneve->net.
geneve_changelink() applies the new configuration against geneve->net:geneve_link_config() and the geneve_quiesce()/geneve_unquiesce() pair reopen the underlay sockets in that netns (geneve_sock_add() uses geneve->net), so the same reasoning as the tunnel changelink series applies here.
Gate geneve_changelink() with rtnl_dev_link_net_capable(), at the top of the op before any attribute is parsed, matching ipgre_changelink() and the rest of the "require CAP_NET_ADMIN in the device netns for changelink" series.
Found by 0sec automated security-research tooling (https://0sec.ai).
--- drivers/net/geneve.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/geneve.c +3 -0
@@ -1751,6 +1751,9 @@ static int geneve_changelink(struct net_struct geneve_config cfg;int err; +if (!rtnl_dev_link_net_capable (dev, geneve->net)) +return -EPERM ; +/* If the geneve device is configured for metadata (or externally * controlled, for example, OVS), then nothing can be changed. */
Greg Kroah-Hartman
maintainerPATCH 173/389 net/af_iucv: fix NULL deref in afiucv_hs_callback_syn()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <[email protected]>
commit 47a5116e56a6b6fe1e909f244e39cd0fc26ceee4 upstream.
afiucv_hs_callback_syn() allocates the child socket with GFP_ATOMIC. If the allocation fails, nsk is NULL.
The connection-refused path is entered when the listen state check fails, the accept backlog is full, or nsk is NULL. The code unconditionally calls iucv_sock_kill(nsk) in that path.
iucv_sock_kill() does not accept a NULL socket pointer and immediately dereferences sk via sock_flag(sk, SOCK_ZAPPED). When nsk is NULL, calling iucv_sock_kill(nsk) results in a NULL pointer dereference.
Only call iucv_sock_kill() when a child socket was successfully allocated.
--- net/iucv/af_iucv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/iucv/af_iucv.c +2 -1
@@ -1868,7 +1868,8 @@ static int afiucv_hs_callback_syn(structafiucv_swap_src_dest (skb); trans_hdr->flags =AF_IUCV_FLAG_SYN |AF_IUCV_FLAG_FIN ; err =dev_queue_xmit (skb); -iucv_sock_kill (nsk); +if (nsk) +iucv_sock_kill (nsk);bh_unlock_sock (sk); goto out; }
Greg Kroah-Hartman
maintainerPATCH 174/389 net/iucv: fix use-after-free of a severed iucv_path
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit be7cc4656eb1f54029610e82d1f0fdd3f9b5ec0a upstream.
af_iucv queues not-yet-received message notifications on iucv->message_q, each holding a raw pointer to the connection's iucv_path. When the peer severs the connection, iucv_sever_path() frees that path with iucv_path_free() but leaves the notifications queued. A later recvmsg() drains message_q via iucv_process_message_q() and hands the stale path to message_receive() -- a use-after-free of the freed iucv_path.
Drop the queued notifications when the path is severed; once the path is gone they can no longer be received. This also frees the notifications leaked when a socket is closed with messages still queued.
--- net/iucv/af_iucv.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
net/iucv/af_iucv.c +14 -0
@@ -358,6 +358,7 @@ static void iucv_sever_path(struct sockunsigned char user_data[16 ];struct iucv_sock *iucv =iucv_sk (sk);struct iucv_path *path = iucv->path; +struct sock_msg_q *p, *n;/* Whoever resets the path pointer, must sever and free it. */ if (xchg (&iucv->path,NULL )) {
@@ -369,6 +370,19 @@ static void iucv_sever_path(struct sock }else pr_iucv->path_sever (path,NULL );iucv_path_free (path); + +/* +* Message notifications queued on message_q still reference +* the now freed path; drop them, otherwise a later recvmsg() +* would pass the freed iucv_path to message_receive() via +* iucv_process_message_q(). +*/ +spin_lock_bh (&iucv->message_q.lock); +list_for_each_entry_safe (p, n, &iucv->message_q.list, list) { +list_del (&p->list); +kfree (p); + } +spin_unlock_bh (&iucv->message_q.lock); } }
Greg Kroah-Hartman
maintainerPATCH 175/389 net/x25: fix use-after-free in x25_kill_by_neigh()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <[email protected]>
commit 5499e0602d2faafd42c580d25f615903c3fbe11b upstream.
x25_kill_by_neigh() walks the global X.25 socket list looking for sockets attached to a terminating neighbour. x25_list_lock protects list membership while the lookup is in progress, but it does not pin a socket's lifetime after the lock is dropped.
The function currently drops x25_list_lock before calling lock_sock(s). A concurrent close can run x25_release(), remove the same socket from x25_list, and drop the last socket reference in that window. The neighbour teardown path can then lock or inspect a freed struct sock/struct x25_sock.
Take sock_hold(s) while x25_list_lock still proves that the list entry is live, then drop the temporary reference after the socket has been locked, rechecked, and released. Recheck x25_sk(s)->neighbour after lock_sock(), because another path may have disconnected the socket before this path acquired the socket lock. Restart the list walk after each disconnect because the list lock was dropped and the previous iterator state may no longer be valid.
A QEMU/KASAN run against origin/master reproduced a slab-use-after-free in x25_kill_by_neigh().
--- net/x25/af_x25.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/x25/af_x25.c +6 -2
@@ -1779,15 +1779,19 @@ void x25_kill_by_neigh(struct x25_neigh {struct sock *s; +again:write_lock_bh (&x25_list_lock);sk_for_each (s, &x25_list) {if (x25_sk (s)->neighbour == nb) { +sock_hold (s);write_unlock_bh (&x25_list_lock);lock_sock (s); -x25_disconnect (s,ENETUNREACH ,0 ,0 ); +if (x25_sk (s)->neighbour == nb) +x25_disconnect (s,ENETUNREACH ,0 ,0 );release_sock (s); -write_lock_bh (&x25_list_lock); +sock_put (s); + goto again; } }write_unlock_bh (&x25_list_lock);
Greg Kroah-Hartman
maintainerPATCH 176/389 net: hip04: fix RX buffer leak on build_skb failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 14fa65d10f5696b063a7d8d26e8291ea84a2c6ed upstream.
When build_skb() fails in hip04_rx_poll(), the driver jumps to the refill path without releasing the current RX buffer and its DMA mapping. Installing a replacement buffer then overwrites the slot references and leaks both resources.
Keep the current slot intact and return budget so NAPI retries the same buffer. Also free a newly allocated RX fragment when dma_map_single() fails.
This issue was found by an in-house static analysis tool.
--- drivers/net/ethernet/hisilicon/hip04_eth.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/ethernet/hisilicon/hip04_eth.c +8 -3
@@ -594,7 +594,11 @@ static int hip04_rx_poll(struct napi_str skb =build_skb (buf, priv->rx_buf_size);if (unlikely (!skb)) {net_dbg_ratelimited ("build_skb failed\n" ); - goto refill; +/* Retain the slot; return budget so NAPI retries this +* buffer. Refill would overwrite rx_buf[]/rx_phys[] +* and leak them. +*/ +return budget; } dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head],
@@ -622,14 +626,15 @@ static int hip04_rx_poll(struct napi_str rx++; } -refill: buf =netdev_alloc_frag (priv->rx_buf_size);if (!buf) goto done; phys =dma_map_single (priv->dev, buf,RX_BUF_SIZE ,DMA_FROM_DEVICE ); -if (dma_mapping_error (priv->dev, phys)) +if (dma_mapping_error (priv->dev, phys)) { +skb_free_frag (buf); goto done; + } priv->rx_buf[priv->rx_head] = buf; priv->rx_phys[priv->rx_head] = phys;hip04_set_recv_desc (priv, phys);
Greg Kroah-Hartman
maintainerPATCH 177/389 proc: Fix broken error paths for namespace links
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
commit 425224c2d700391729be7fe6929a88ef4e2d7a4e upstream.
Don't return the return value of down_read_killable() (0) when a ptrace access check fails, return -EACCES as intended.
--- fs/proc/namespaces.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/proc/namespaces.c +3 -1
@@ -46,7 +46,7 @@ static const char *proc_ns_get_link(struconst struct proc_ns_operations *ns_ops =PROC_I (inode)->ns_ops;struct task_struct *task;struct path ns_path; -int error = -EACCES ; +int error;if (!dentry)return ERR_PTR (-ECHILD );
@@ -59,6 +59,7 @@ static const char *proc_ns_get_link(struif (error) goto out_put_task; + error = -EACCES ;if (!ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) goto out;
@@ -90,6 +91,7 @@ static int proc_ns_readlink(struct dentrif (res) goto out_put_task; + res = -EACCES ;if (ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) { res =ns_get_name (name,sizeof (name), task, ns_ops);if (res >=0 )
Greg Kroah-Hartman
maintainerPATCH 178/389 rbd: Reset positive result codes to zero in object map update path
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit a6c4250b81bd30beae94e1b7a4b26fa1193ad2e4 upstream.
In a reply message to an RBD request, a positive result code indicates a data payload, which is not allowed for writes. While rbd_osd_req_callback() already resets a positive result code for writes to zero, rbd_object_map_callback() does not. This allows a corrupted reply to an object map update to trigger the rbd_assert(*result < 0) in __rbd_obj_handle_request(). This happens, because rbd_object_map_callback() calls rbd_obj_handle_request() -> __rbd_obj_handle_request() and passes this positive result code. From __rbd_obj_handle_request(), rbd_obj_advance_write() is called, which leaves the positive result code unchanged and returns true. Therefore, the if(done && *result) branch is executed in __rbd_obj_handle_request() and the assertion triggers.
This patch fixes the issue by adjusting the logic in the rbd_object_map_callback() path. A positive result code for an object map update is now reset to zero (similar to rbd_osd_req_callback()), and the message is subsequently handled the same way as if the result code was zero from the beginning. Additionally, a WARN_ON_ONCE() is added for this case.
--- drivers/block/rbd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/block/rbd.c +6 -1
@@ -2020,10 +2020,15 @@ static int rbd_object_map_update_finish(bool has_current_state;void *p; -if (osd_req->r_result) +if (osd_req->r_result <0 )return osd_req->r_result;/* +* Writes aren't allowed to return a data payload. +*/ +WARN_ON_ONCE (osd_req->r_result >0 ); + +/* * Nothing to do for a snapshot object map. */ if (osd_req->r_num_ops ==1 )
Greg Kroah-Hartman
maintainerPATCH 179/389 ila: reload IPv6 header after pskb_may_pull in checksum adjust
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 92d3817649df2b0b6a008a686c8275c88d7ef594 upstream.
ila_csum_adjust_transport() caches ip6h = ipv6_hdr(skb) before calling pskb_may_pull(). On a non-linear skb whose transport header sits in a page fragment, pskb_may_pull() can call __pskb_pull_tail() / pskb_expand_head() and free the old skb head, leaving ip6h dangling; the following get_csum_diff(ip6h, p) then reads freed memory. ila_update_ipv6_locator() uses ip6h (and the iaddr derived from it) again after the csum-adjust call and additionally writes the new locator through that pointer.
Impact: a remote IPv6 packet routed through a configured ILA csum-adjust-transport route or receive-side mapping triggers a slab-use-after-free in ila_update_ipv6_locator() (KASAN). The route or mapping requires CAP_NET_ADMIN to configure, but trigger packets are unauthenticated once it exists.
Reload ip6h after each pskb_may_pull() in ila_csum_adjust_transport() before the csum-diff read. In ila_update_ipv6_locator() only the ILA_CSUM_ADJUST_TRANSPORT case pulls the skb, so reload ip6h and iaddr in that case alone before the destination-address write; the neutral-map modes never pull and keep their cached pointers.
--- net/ipv6/ila/ila_common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
net/ipv6/ila/ila_common.c +12 -0
@@ -84,6 +84,7 @@ static void ila_csum_adjust_transport(ststruct tcphdr *th = (struct tcphdr *) (skb_network_header (skb) + nhoff); + ip6h =ipv6_hdr (skb); diff =get_csum_diff (ip6h, p);inet_proto_csum_replace_by_diff (&th->check, skb, diff, true, true);
@@ -95,6 +96,7 @@ static void ila_csum_adjust_transport(st (skb_network_header (skb) + nhoff);if (uh->check || skb->ip_summed ==CHECKSUM_PARTIAL ) { + ip6h =ipv6_hdr (skb); diff =get_csum_diff (ip6h, p);inet_proto_csum_replace_by_diff (&uh->check, skb, diff, true, true);
@@ -109,6 +111,7 @@ static void ila_csum_adjust_transport(ststruct icmp6hdr *ih = (struct icmp6hdr *) (skb_network_header (skb) + nhoff); + ip6h =ipv6_hdr (skb); diff =get_csum_diff (ip6h, p);inet_proto_csum_replace_by_diff (&ih->icmp6_cksum, skb, diff, true, true);
@@ -126,6 +129,15 @@ void ila_update_ipv6_locator(struct sk_bswitch (p->csum_mode) {case ILA_CSUM_ADJUST_TRANSPORT :ila_csum_adjust_transport (skb, p); +/* +* ila_csum_adjust_transport() calls pskb_may_pull(), which can +* reallocate the skb head and leave ip6h (and the iaddr derived +* from it) dangling; reload both before the write below. The +* other csum modes do not pull, so their cached pointers stay +* valid. +*/ + ip6h =ipv6_hdr (skb); + iaddr =ila_a2i (&ip6h->daddr);break ;case ILA_CSUM_NEUTRAL_MAP :if (sir2ila) {
Greg Kroah-Hartman
maintainerPATCH 180/389 mac802154: llsec: reject frames shorter than the authentication tag
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit fd3a3f28ed60c6af4b2a39933b151d6b27842c3b upstream.
llsec_do_decrypt_auth() computes the associated-data length for the AEAD request as
assoclen += datalen - authlen;
where datalen is the number of bytes after the MAC header and authlen (4, 8 or 16) is the length of the authentication tag. Nothing verifies that the frame actually carries at least authlen payload bytes. A secured frame whose payload is shorter than the tag makes datalen - authlen negative; assoclen is then passed to aead_request_set_ad() as an unsigned value close to 4 GiB, so crypto_aead_decrypt() walks far off the end of the scatterlist that only spans the real frame.
The frame is fully attacker-controlled and reaches this path from any IEEE 802.15.4 peer in radio range. Reject frames whose payload is shorter than the authentication tag before the subtraction.
Dynamically reproduced on a KASAN kernel as a general-protection-fault in the AEAD scatterwalk, and the fix confirmed.
--- net/mac802154/llsec.c | 5 +++++ 1 file changed, 5 insertions(+)
net/mac802154/llsec.c +5 -0
@@ -888,6 +888,11 @@ llsec_do_decrypt_auth(struct sk_buff *sk data =skb_mac_header (skb) + skb->mac_len; datalen =skb_tail_pointer (skb) - data; +if (datalen < authlen) { +kfree_sensitive (req); +return -EBADMSG ; + } +sg_init_one (&sg,skb_mac_header (skb), assoclen + datalen);if (!(hdr->sec.level &IEEE802154_SCF_SECLEVEL_ENC )) {
Greg Kroah-Hartman
maintainerPATCH 181/389 pppoe: reload header pointer after dev_hard_header()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asim Viladi Oglu Manizada <[email protected]>
commit e9c238f6fe42fb1b4dba3a578277de32cb487937 upstream.
pppoe_sendmsg() saves a pointer to the PPPoE header before calling dev_hard_header(). Device header callbacks are allowed to reallocate the skb head, invalidating pointers into it.
This can happen when a send is blocked in copy_from_user() while the first non-Ethernet port is added to an empty team device. The team's delegated GRE header callback then expands the skb head. PPPoE subsequently writes six bytes through the stale pointer into the freed head.
Reload the PPPoE header through the skb's network-header offset after device header creation. pskb_expand_head() updates that offset when it relocates the head.
--- drivers/net/ppp/pppoe.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ppp/pppoe.c +1 -0
@@ -899,6 +899,7 @@ static int pppoe_sendmsg(struct socket *dev_hard_header (skb, dev,ETH_P_PPP_SES , po->pppoe_pa.remote,NULL , total_len); + ph =pppoe_hdr (skb);memcpy (ph, &hdr,sizeof (struct pppoe_hdr )); ph->length =htons (total_len);
Greg Kroah-Hartman
maintainerPATCH 182/389 tipc: clear sock->sk on the failed-insert path in tipc_sk_create()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit ba0533fc163f905fe817cfabdf8ed4058da44800 upstream.
When tipc_sk_create() fails to insert the new socket (tipc_sk_insert() returns non-zero), its error path frees the sk with sk_free() but leaves sock->sk pointing at the freed object:
if (tipc_sk_insert(tsk)) {
sk_free(sk);
pr_warn("Socket create failed; port number exhausted\n");
return -EINVAL;
}This is harmless for plain socket(): the syscall layer clears sock->ops before releasing, so tipc_release() is never called. It is not harmless on the accept() path. tipc_accept() creates the pre-allocated child socket with tipc_sk_create(net, new_sock, 0, kern); on failure it leaves new_sock->sk dangling and new_sock->ops non-NULL, and do_accept() then fput()s the new file, so __sock_release() -> tipc_release() runs lock_sock(new_sock->sk) on the freed sk -- a use-after-free write of the sk_lock spinlock.
tipc_release() already guards this exact "failed accept() releases a pre-allocated child" case with "if (sk == NULL) return 0;", but the guard is bypassed because tipc_sk_create() left sock->sk non-NULL (dangling) rather than NULL.
Clear sock->sk on the failed-insert path so the existing tipc_release() NULL check fires and the use-after-free is avoided.
The tipc_sk_insert() failure is reached when the per-netns socket rhashtable hits its max_size (tsk_rht_params.max_size = 1048576, ~2M elements) -- i.e. once a netns holds ~2M TIPC sockets every insert returns -E2BIG.
BUG: KASAN: slab-use-after-free in lock_sock_nested (net/core/sock.c:3839) Write of size 8 at addr ffff8880047cdc38 by task init/1 lock_sock_nested (net/core/sock.c:3839) tipc_release (net/tipc/socket.c:638) __sock_release (net/socket.c:710) sock_close (net/socket.c:1501) __fput (fs/file_table.c:512) Allocated by task 1: sk_alloc (net/core/sock.c:2308) tipc_sk_create (net/tipc/socket.c:487) tipc_accept (net/tipc/socket.c:2744) do_accept (net/socket.c:2034) Freed by task 1: __sk_destruct (net/core/sock.c:2391) tipc_sk_create (net/tipc/socket.c:504) tipc_accept (net/tipc/socket.c:2744) do_accept (net/socket.c:2034)
--- net/tipc/socket.c | 1 + 1 file changed, 1 insertion(+)
net/tipc/socket.c +1 -0
@@ -490,6 +490,7 @@ static int tipc_sk_create(struct net *netipc_set_sk_state (sk,TIPC_OPEN );if (tipc_sk_insert (tsk)) {sk_free (sk); + sock->sk =NULL ;pr_warn ("Socket create failed; port number exhausted\n" );return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 183/389 drm/amdgpu/gfx10: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit d06c4173a7c38c7a39e98859f839ce714c7af2c9 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +5 -8
@@ -3437,7 +3437,7 @@ static void gfx_v10_0_wait_reg_mem(struc WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -7811,7 +7811,7 @@ static void gfx_v10_0_ring_emit_ib_gfx(s }amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -7846,7 +7846,7 @@ static void gfx_v10_0_ring_emit_ib_compu }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -7879,9 +7879,9 @@ static void gfx_v10_0_ring_emit_fence(st* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -7917,9 +7917,6 @@ static void gfx_v10_0_ring_emit_fence_ki {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 184/389 drm/amdgpu/gfx8: drop unecessary BUG_ON()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 84a1a8a952ab4b8c23c5dd1f2eea4049cb4914f5 upstream.
There's no need to crash the kernel for this case.
--- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 3 --- 1 file changed, 3 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +0 -3
@@ -6292,9 +6292,6 @@ static void gfx_v8_0_ring_emit_fence_comstatic void gfx_v8_0_ring_emit_fence_kiq (struct amdgpu_ring *ring,u64 addr,u64 seq,unsigned int flags) { -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 185/389 drm/amdgpu/gfx9: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 6302be10b521f5106ce01eb5a724b9e7945a5061 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +5 -5
@@ -1028,7 +1028,7 @@ static void gfx_v9_0_wait_reg_mem(struct WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -5295,7 +5295,7 @@ static void gfx_v9_0_ring_emit_ib_gfx(st }amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -5330,7 +5330,7 @@ static void gfx_v9_0_ring_emit_ib_comput }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -5364,9 +5364,9 @@ static void gfx_v9_0_ring_emit_fence(str* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 186/389 drm/amdgpu: fix division by zero with invalid uvd dimensions
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit 0c01c811be47e6b146552dd59bfedbea8f09b8f4 upstream.
When width or height is less than 16, width_in_mb or height_in_mb becomes 0, leading to fs_in_mb being 0. This causes a division by zero when calculating num_dpb_buffer in H264 and H264 Perf decode paths.
Add validation to reject frames with width < 16 or height < 16 before performing any calculations that depend on these values.
V2: Format change - move up all vaiable definitions.
V3: Use warn_once to avoid spam.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +8 -0
@@ -567,6 +567,14 @@ static int amdgpu_uvd_cs_msg_decode(struunsigned image_size, tmp, min_dpb_size, num_dpb_buffer;unsigned min_ctx_size = ~0 ; +/* Reject invalid dimensions to prevent division by zero */ +if (width <16 || height <16 ) { +dev_WARN_ONCE (adev->dev,1 , +"Invalid UVD decoding dimensions (%dx%d)!\n" , + width, height); +return -EINVAL ; + } + image_size = width * height; image_size += image_size /2 ; image_size =ALIGN (image_size,1024 );
Greg Kroah-Hartman
maintainerPATCH 187/389 drm/amdgpu: invoke pm_genpd_remove() before freeing genpd
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ce Sun <[email protected]>
commit 28c9b3c5dc35cc790d11e26ca3fc6e068be63998 upstream.
Call pm_genpd_remove() to unregister from global list prior to releasing acp_genpd memory, and clear the pointer after free.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +2 -0
@@ -466,7 +466,9 @@ static int acp_hw_fini(void *handle)mfd_remove_devices (adev->acp.parent);kfree (adev->acp.acp_res); +pm_genpd_remove (&adev->acp.acp_genpd->gpd);kfree (adev->acp.acp_genpd); + adev->acp.acp_genpd =NULL ;kfree (adev->acp.acp_cell);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 188/389 tipc: fix use-after-free of the discoverer in tipc_disc_rcv()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit 1579342d71133da7f00daa02c75cebec7372097b upstream.
bearer_disable() frees b->disc with tipc_disc_delete()'s plain kfree(), but tipc_disc_rcv() still dereferences b->disc in RX softirq under rcu_read_lock() (tipc_udp_recv -> tipc_rcv -> tipc_disc_rcv).
L2 bearers are safe thanks to the synchronize_net() in tipc_disable_l2_media(), but the UDP bearer defers that call to the cleanup_bearer() workqueue, so the discoverer is freed with no grace period:
BUG: KASAN: slab-use-after-free in tipc_disc_rcv (net/tipc/discover.c:149) Read of size 8 at addr ffff88802348b728 by task poc_tipc/184 <IRQ> tipc_disc_rcv (net/tipc/discover.c:149) tipc_rcv (net/tipc/node.c:2126) tipc_udp_recv (net/tipc/udp_media.c:391) udp_rcv (net/ipv4/udp.c:2643) ip_local_deliver_finish (net/ipv4/ip_input.c:241) </IRQ> Freed by task 181: kfree (mm/slub.c:6565) bearer_disable (net/tipc/bearer.c:418) tipc_nl_bearer_disable (net/tipc/bearer.c:1001)
The bearer is freed with kfree_rcu(); free the discoverer the same way. Add an rcu_head to struct tipc_discoverer and free it and its skb from an RCU callback.
Because the RCU callback (tipc_disc_free_rcu) lives in module text, a call_rcu() that is still pending when the tipc module is unloaded would invoke a freed function. Add an rcu_barrier() to tipc_exit() after the bearer subsystem has been torn down, so all pending discoverer callbacks have run before the module text goes away.
Reachable from an unprivileged user namespace: the TIPCv2 genl family is netnsok and its bearer commands have no GENL_ADMIN_PERM. Needs CONFIG_TIPC and CONFIG_TIPC_MEDIA_UDP.
--- net/tipc/core.c | 5 +++++ net/tipc/discover.c | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-)
net/tipc/core.c +5 -0
@@ -220,6 +220,11 @@ static void __exit tipc_exit(void)unregister_pernet_device (&tipc_net_ops);tipc_unregister_sysctl (); +/* TODO: Wait for all timers that called call_rcu() to finish before +* calling rcu_barrier(). +*/ +rcu_barrier (); +pr_info ("Deactivated\n" ); }
net/tipc/discover.c +12 -2
@@ -58,6 +58,7 @@* @skb: request message to be (repeatedly) sent * @timer: timer governing period between requests * @timer_intv: current interval between requests (in ms) +* @rcu: RCU head for deferred freeing */ struct tipc_discoverer {u32 bearer_id;
@@ -69,6 +70,7 @@ struct tipc_discoverer {struct sk_buff *skb;struct timer_list timer;unsigned long timer_intv; +struct rcu_head rcu; };/**
@@ -381,6 +383,15 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,return 0 ; } +static void tipc_disc_free_rcu (struct rcu_head *rp) +{ + struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer, + rcu); + +kfree_skb (d->skb); +kfree (d); +} +/** * tipc_disc_delete - destroy object sending periodic link setup requests * @d: ptr to link duest structure
@@ -388,8 +399,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,void tipc_disc_delete (struct tipc_discoverer *d) {del_timer_sync (&d->timer); -kfree_skb (d->skb); -kfree (d); +call_rcu (&d->rcu, tipc_disc_free_rcu); }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 189/389 wifi: mt76: mt7615: drop TXRX_NOTIFY on non-mmio buses
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Devin Wittmayer <[email protected]>
commit 39afc46c0243d10b7795e6e6cf4ae91f41732120 upstream.
PKT_TYPE_TXRX_NOTIFY is an mmio-only event, but mt7615_rx_check() and mt7615_queue_rx_skb() dispatch it to mt7615_mac_tx_free() on every bus. mt7615_mac_tx_free() cleans the DMA tx queues with mt76_queue_tx_cleanup(), which calls queue_ops->tx_cleanup(). Only the mmio queue ops implement that callback; on the mt7663 USB and SDIO buses it is NULL, so a TXRX_NOTIFY there calls a NULL pointer in the RX worker. Same defect as the mt7921 and mt7925 patches in this series.
Drop the event on non-mmio buses via mt76_is_mmio(), as in commit 5683e1488aa9 ("wifi: mt76: connac: do not check WED status for non-mmio devices").
[ No mt7615_rx_check() on this tree, so only the mt7615_queue_rx_skb()
hunk applies, and mt7615_mac_tx_free() takes the skb rather than (data, len), so the guard frees it here. ]
--- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7615/mac.c +4 -0
@@ -1492,6 +1492,10 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,dev_kfree_skb (skb);break ;case PKT_TYPE_TXRX_NOTIFY : +if (!mt76_is_mmio (mdev)) { +dev_kfree_skb (skb); +break ; + }mt7615_mac_tx_free (dev, skb);break ;case PKT_TYPE_RX_EVENT :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 190/389 openvswitch: fix GSO userspace truncation underflow
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
[ Upstream commit 4032f8ed10fcb84d41c508dfb04be96589f78dfe ]
OVS_ACTION_ATTR_TRUNC currently stores a delta from the original skb length in OVS_CB(skb)->cutlen. When a later userspace action segments a GSO skb, queue_gso_packets() reuses that delta for each smaller segment. A segment can then reach queue_userspace_packet() with cutlen greater than skb->len, underflowing the length passed to skb_zerocopy().
Store the maximum preserved length instead and bound each consumer against the current skb length. Use U32_MAX as the no-truncation sentinel so the value remains valid if skb geometry changes before a consumer handles it.
--- net/openvswitch/actions.c | 15 +++++---------- net/openvswitch/datapath.c | 25 ++++++++++++++----------- net/openvswitch/datapath.h | 2 +- net/openvswitch/vport.c | 2 +- 4 files changed, 21 insertions(+), 23 deletions(-)
net/openvswitch/actions.c +5 -10
@@ -855,12 +855,8 @@ static void do_output(struct datapath *du16 mru =OVS_CB (skb)->mru;u32 cutlen =OVS_CB (skb)->cutlen; -if (unlikely (cutlen >0 )) { -if (skb->len - cutlen >ovs_mac_header_len (key)) -pskb_trim (skb, skb->len - cutlen); -else -pskb_trim (skb,ovs_mac_header_len (key)); - } +if (unlikely (cutlen < skb->len)) +pskb_trim (skb,max (cutlen,ovs_mac_header_len (key)));if (likely (!mru || (skb->len <= mru + vport->dev->hard_header_len))) {
@@ -1232,22 +1228,21 @@ static int do_execute_actions(struct dat clone =skb_clone (skb,GFP_ATOMIC );if (clone)do_output (dp, clone, port, key); -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;break ; }case OVS_ACTION_ATTR_TRUNC : {struct ovs_action_trunc *trunc =nla_data (a); -if (skb->len > trunc->max_len) -OVS_CB (skb)->cutlen = skb->len - trunc->max_len; +OVS_CB (skb)->cutlen = trunc->max_len;break ; }case OVS_ACTION_ATTR_USERSPACE :output_userspace (dp, skb, key, a, attr, len,OVS_CB (skb)->cutlen); -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;break ;case OVS_ACTION_ATTR_HASH :
net/openvswitch/datapath.c +14 -11
@@ -240,7 +240,7 @@ void ovs_dp_process_packet(struct sk_buf upcall.cmd =OVS_PACKET_CMD_MISS ; upcall.portid =ovs_vport_find_upcall_portid (p, skb); upcall.mru =OVS_CB (skb)->mru; - error =ovs_dp_upcall (dp, skb, key, &upcall,0 ); + error =ovs_dp_upcall (dp, skb, key, &upcall,U32_MAX );switch (error) {case 0 :case -EAGAIN :
@@ -400,7 +400,8 @@ static int queue_userspace_packet(structstruct sk_buff *nskb =NULL ;struct sk_buff *user_skb =NULL ;/* to be queued to userspace */ struct nlattr *nla; -size_t len; +size_t msg_size; +size_t skb_len;unsigned int hlen;int err, dp_ifindex;u64 hash;
@@ -421,7 +422,8 @@ static int queue_userspace_packet(struct skb = nskb; } -if (nla_attr_size (skb->len) >USHRT_MAX ) { + skb_len =min (skb->len, cutlen); +if (nla_attr_size (skb_len) >USHRT_MAX ) { err = -EFBIG ; goto out; }
@@ -436,13 +438,13 @@ static int queue_userspace_packet(struct* padding logic. Only perform zerocopy if padding is not required. */ if (dp->user_features &OVS_DP_F_UNALIGNED ) - hlen =skb_zerocopy_headlen (skb); + hlen =min (skb_zerocopy_headlen (skb), cutlen);else - hlen = skb->len; + hlen = skb_len; - len =upcall_msg_size (upcall_info, hlen - cutlen, -OVS_CB (skb)->acts_origlen); - user_skb =genlmsg_new (len,GFP_ATOMIC ); + msg_size =upcall_msg_size (upcall_info, hlen, +OVS_CB (skb)->acts_origlen); + user_skb =genlmsg_new (msg_size,GFP_ATOMIC );if (!user_skb) { err = -ENOMEM ; goto out;
@@ -503,7 +505,7 @@ static int queue_userspace_packet(struct }/* Add OVS_PACKET_ATTR_LEN when packet is truncated */ -if (cutlen >0 && +if (skb_len < skb->len &&nla_put_u32 (user_skb,OVS_PACKET_ATTR_LEN , skb->len)) { err = -ENOBUFS ; goto out;
@@ -528,9 +530,9 @@ static int queue_userspace_packet(struct err = -ENOBUFS ; goto out; } - nla->nla_len =nla_attr_size (skb->len - cutlen); + nla->nla_len =nla_attr_size (skb_len); - err =skb_zerocopy (user_skb, skb, skb->len - cutlen, hlen); + err =skb_zerocopy (user_skb, skb, skb_len, hlen);if (err) goto out;
@@ -587,6 +589,7 @@ static int ovs_packet_cmd_execute(struct packet->ignore_df =1 ; }OVS_CB (packet)->mru = mru; +OVS_CB (packet)->cutlen =U32_MAX ;if (a[OVS_PACKET_ATTR_HASH ]) { hash =nla_get_u64 (a[OVS_PACKET_ATTR_HASH ]);
net/openvswitch/datapath.h +1 -1
@@ -96,7 +96,7 @@ struct datapath {* @mru: The maximum received fragement size; 0 if the packet is not * fragmented. * @acts_origlen: The netlink size of the flow actions applied to this skb. -* @cutlen: The number of bytes from the packet end to be removed. +* @cutlen: The number of bytes in the packet to preserve on output. */ struct ovs_skb_cb {struct vport *input_vport;
net/openvswitch/vport.c +1 -1
@@ -436,7 +436,7 @@ int ovs_vport_receive(struct vport *vporOVS_CB (skb)->input_vport = vport;OVS_CB (skb)->mru =0 ; -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;if (unlikely (dev_net (skb->dev) !=ovs_dp_get_net (vport->dp))) {u32 mark;
Greg Kroah-Hartman
maintainerPATCH 191/389 raw: remove unused variables from raw6_icmp_error()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit c4fceb46add65481ef0dfb79cad24c3c269b4cad upstream.
saddr and daddr are set but not used.
--- net/ipv6/raw.c | 3 --- 1 file changed, 3 deletions(-)
net/ipv6/raw.c +0 -3
@@ -335,7 +335,6 @@ static void rawv6_err(struct sock *sk, svoid raw6_icmp_error (struct sk_buff *skb,int nexthdr,u8 type,u8 code,int inner_offset,__be32 info) { -const struct in6_addr *saddr, *daddr;struct net *net =dev_net (skb->dev);struct hlist_head *head;struct sock *sk;
@@ -347,8 +346,6 @@ void raw6_icmp_error(struct sk_buff *skbsk_for_each (sk, head) {/* Note: ipv6_hdr(skb) != skb->data */ const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data; - saddr = &ip6h->saddr; - daddr = &ip6h->daddr;if (!raw_v6_match (net, sk, nexthdr, &ip6h->saddr, &ip6h->daddr,inet6_iif (skb),inet6_sdif (skb)))
Greg Kroah-Hartman
maintainerPATCH 192/389 raw: fix a typo in raw_icmp_error()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 97a4d46b1516250d640c1ae0c9e7129d160d6a1c upstream.
I accidentally broke IPv4 traceroute, by swapping iph->saddr and iph->daddr.
Probably because raw_icmp_error() and raw_v4_input() use different order for iph->saddr and iph->daddr.
--- net/ipv4/raw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv4/raw.c +1 -1
@@ -279,7 +279,7 @@ void raw_icmp_error(struct sk_buff *skb,sk_for_each (sk, head) { iph = (const struct iphdr *)skb->data;if (!raw_v4_match (net, sk, iph->protocol, - iph->saddr, iph->daddr, dif, sdif)) + iph->daddr, iph->saddr, dif, sdif))continue ;raw_err (sk, skb, info); }
Greg Kroah-Hartman
maintainerPATCH 193/389 net: bridge: vlan: fix global vlan option range dumping
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikolay Aleksandrov <[email protected]>
commit 6c4110d9f499e2170fbb36723b0a5f50a8116304 upstream.
When global vlan options are equal sequentially we compress them in a range to save space and reduce processing time. In order to have the proper range end id we need to update range_end if the options are equal otherwise we get ranges with the same end vlan id as the start.
--- net/bridge/br_vlan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/bridge/br_vlan.c +2 -1
@@ -1839,7 +1839,7 @@ static int br_vlan_dump_dev(const structif (dump_global) {if (br_vlan_global_opts_can_enter_range (v, range_end)) -continue ; + goto update_end;if (!br_vlan_global_opts_fill (skb, range_start->vid, range_end->vid, range_start)) {
@@ -1865,6 +1865,7 @@ static int br_vlan_dump_dev(const struct range_start = v; } +update_end: range_end = v; }
Greg Kroah-Hartman
maintainerPATCH 194/389 net: mpls: initialize rtm_tos in mpls_getroute()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
[ Upstream commit 295dd295e2137e10e9a5b1891d97e0f08de76f03 ]
mpls_getroute() builds the RTM_NEWROUTE reply to an RTM_GETROUTE request by filling a struct rtmsg allocated from an skb whose data area is not zeroed (alloc_skb(NLMSG_GOODSIZE, ...)). It sets every field of the header except rtm_tos:
r = nlmsg_data(nlh); r->rtm_family = AF_MPLS; r->rtm_dst_len = 20; r->rtm_src_len = 0; r->rtm_table = RT_TABLE_MAIN; r->rtm_type = RTN_UNICAST; r->rtm_scope = RT_SCOPE_UNIVERSE; r->rtm_protocol = rt->rt_protocol; r->rtm_flags = 0;
struct rtmsg has no padding, so the one uninitialised byte rtm_tos (offset 3) is copied straight to user space on recvmsg(), leaking a byte of uninitialised heap memory. This is in contrast to mpls_dump_route(), which fills the very same header and does set rtm_tos = 0.
Initialize rtm_tos to 0, matching mpls_dump_route().
Reproduced with KMSAN by adding an MPLS route and issuing a non-RTM_F_FIB_MATCH RTM_GETROUTE for its label:
BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x36c/0x33f0 _copy_to_iter+0x36c/0x33f0 __skb_datagram_iter+0x196/0x12c0 skb_copy_datagram_iter+0x5b/0x210 netlink_recvmsg+0x37b/0xef0 ... Uninit was created at: __alloc_skb+0x8ca/0x10e0 mpls_getroute+0x1280/0x3a40 rtnetlink_rcv_msg+0x1138/0x15a0 ... Byte 19 of 64 is uninitialized
(byte 19 = nlmsghdr(16) + rtmsg offset 3 = rtm_tos)
--- net/mpls/af_mpls.c | 1 + 1 file changed, 1 insertion(+)
net/mpls/af_mpls.c +1 -0
@@ -2492,6 +2492,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, r->rtm_family =AF_MPLS ; r->rtm_dst_len =20 ; r->rtm_src_len =0 ; + r->rtm_tos =0 ; r->rtm_table =RT_TABLE_MAIN ; r->rtm_type =RTN_UNICAST ; r->rtm_scope =RT_SCOPE_UNIVERSE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 195/389 media: uvcvideo: Implement dual stream quirk to fix loss of usb packets
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Isaac Scott <[email protected]>
commit c2eda35e675b6ea4a0a21a4b1167b121571a9036 upstream.
Some cameras, such as the Sonix Technology Co. 292A, exhibit issues when running two parallel streams, causing USB packets to be dropped when an H.264 stream posts a keyframe while an MJPEG stream is running simultaneously. This occasionally causes the driver to erroneously output two consecutive JPEG images as a single frame.
To fix this, we inspect the buffer, and trigger a new frame when we find an SOI.
--- drivers/media/usb/uvc/uvc_video.c | 28 +++++++++++++++++++++++++++- drivers/media/usb/uvc/uvcvideo.h | 4 ++++ 2 files changed, 31 insertions(+), 1 deletion(-)
drivers/media/usb/uvc/uvc_video.c +27 -1
@@ -21,6 +21,8 @@#include "uvcvideo.h" +#define JPEG_MARKER_SOI 0xd8 +/* ------------------------------------------------------------------------ * UVC Controls */
@@ -1075,6 +1077,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,struct uvc_buffer *meta_buf, const u8 *data, int len) { + u8 header_len;u8 fid;/* Sanity checks:
@@ -1087,6 +1090,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,return -EINVAL ; } + header_len = data[0 ]; fid = data[1 ] &UVC_STREAM_FID ;/* Increase the sequence number regardless of any buffer states, so
@@ -1175,9 +1179,31 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,return -EAGAIN ; } +/* +* Some cameras, when running two parallel streams (one MJPEG alongside +* another non-MJPEG stream), are known to lose the EOF packet for a frame. +* We can detect the end of a frame by checking for a new SOI marker, as +* the SOI always lies on the packet boundary between two frames for +* these devices. +*/ +if (stream->dev->quirks &UVC_QUIRK_MJPEG_NO_EOF && + (stream->cur_format->fcc ==V4L2_PIX_FMT_MJPEG || + stream->cur_format->fcc ==V4L2_PIX_FMT_JPEG )) { +const u8 *packet = data + header_len; + +if (len >= header_len +2 && + packet[0 ] ==0xff && packet[1 ] ==JPEG_MARKER_SOI && + buf->bytesused !=0 ) { + buf->state =UVC_BUF_STATE_READY ; + buf->error =1 ; + stream->last_fid ^=UVC_STREAM_FID ; +return -EAGAIN ; + } + } + stream->last_fid = fid; -return data[0 ]; +return header_len; }/*
drivers/media/usb/uvc/uvcvideo.h +4 -0
@@ -204,6 +204,10 @@#define UVC_QUIRK_FORCE_Y8 0x00000800#define UVC_QUIRK_FORCE_BPP 0x00001000#define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000 +#define UVC_QUIRK_NO_RESET_RESUME 0x00004000 +#define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000 +#define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000 +#define UVC_QUIRK_MJPEG_NO_EOF 0x00020000/* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 196/389 media: uvcvideo: Fix sequence number when no EOF
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Ribalda <[email protected]>
commit f078966ca1fb1b3865d8e6bbe2705cfd277fc637 upstream.
If the driver could not detect the EOF, the sequence number is increased twice:
1) When we enter uvc_video_decode_start() with the old buffer and FID has flipped => We return -EAGAIN and last_fid is not flipped
2) When we enter uvc_video_decode_start() with the new buffer.
Fix this issue by moving the new frame detection logic earlier in uvc_video_decode_start().
This also has some nice side affects:
- The error status from the new packet will no longer get propagated to the previous frame-buffer.
- uvc_video_clock_decode() will no longer update the previous frame buf->stf with info from the new packet.
- uvc_video_clock_decode() and uvc_video_stats_decode() will no longer get called twice for the same packet.
--- drivers/media/usb/uvc/uvc_video.c | 94 ++++++++++++++++--------------- 1 file changed, 49 insertions(+), 45 deletions(-)
drivers/media/usb/uvc/uvc_video.c +49 -45
@@ -1093,7 +1093,55 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, header_len = data[0 ]; fid = data[1 ] &UVC_STREAM_FID ; -/* Increase the sequence number regardless of any buffer states, so +/* +* Mark the buffer as done if we're at the beginning of a new frame. +* End of frame detection is better implemented by checking the EOF +* bit (FID bit toggling is delayed by one frame compared to the EOF +* bit), but some devices don't set the bit at end of frame (and the +* last payload can be lost anyway). We thus must check if the FID has +* been toggled. +* +* stream->last_fid is initialized to -1, and buf->bytesused to 0, +* so the first isochronous frame will never trigger an end of frame +* detection. +* +* Empty buffers (bytesused == 0) don't trigger end of frame detection +* as it doesn't make sense to return an empty buffer. This also +* avoids detecting end of frame conditions at FID toggling if the +* previous payload had the EOF bit set. +*/ +if (fid != stream->last_fid && buf && buf->bytesused !=0 ) { +uvc_trace (UVC_TRACE_FRAME , +"Frame complete (FID bit toggled)\n" ); + buf->state =UVC_BUF_STATE_READY ; + +return -EAGAIN ; + } + +/* +* Some cameras, when running two parallel streams (one MJPEG alongside +* another non-MJPEG stream), are known to lose the EOF packet for a frame. +* We can detect the end of a frame by checking for a new SOI marker, as +* the SOI always lies on the packet boundary between two frames for +* these devices. +*/ +if (stream->dev->quirks &UVC_QUIRK_MJPEG_NO_EOF && + (stream->cur_format->fcc ==V4L2_PIX_FMT_MJPEG || + stream->cur_format->fcc ==V4L2_PIX_FMT_JPEG ) && + buf && buf->bytesused !=0 ) { +const u8 *packet = data + header_len; + +if (len >= header_len +2 && + packet[0 ] ==0xff && packet[1 ] ==JPEG_MARKER_SOI ) { + buf->state =UVC_BUF_STATE_READY ; + buf->error =1 ; + stream->last_fid ^=UVC_STREAM_FID ; +return -EAGAIN ; + } + } + +/* +* Increase the sequence number regardless of any buffer states, so * that discontinuous sequence numbers always indicate lost frames. */ if (stream->last_fid != fid) {
@@ -1157,50 +1205,6 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, meta_buf->state =UVC_BUF_STATE_ACTIVE ; } -/* Mark the buffer as done if we're at the beginning of a new frame. -* End of frame detection is better implemented by checking the EOF -* bit (FID bit toggling is delayed by one frame compared to the EOF -* bit), but some devices don't set the bit at end of frame (and the -* last payload can be lost anyway). We thus must check if the FID has -* been toggled. -* -* stream->last_fid is initialized to -1, so the first isochronous -* frame will never trigger an end of frame detection. -* -* Empty buffers (bytesused == 0) don't trigger end of frame detection -* as it doesn't make sense to return an empty buffer. This also -* avoids detecting end of frame conditions at FID toggling if the -* previous payload had the EOF bit set. -*/ -if (fid != stream->last_fid && buf->bytesused !=0 ) { -uvc_trace (UVC_TRACE_FRAME ,"Frame complete (FID bit " -"toggled).\n" ); - buf->state =UVC_BUF_STATE_READY ; -return -EAGAIN ; - } - -/* -* Some cameras, when running two parallel streams (one MJPEG alongside -* another non-MJPEG stream), are known to lose the EOF packet for a frame. -* We can detect the end of a frame by checking for a new SOI marker, as -* the SOI always lies on the packet boundary between two frames for -* these devices. -*/ -if (stream->dev->quirks &UVC_QUIRK_MJPEG_NO_EOF && - (stream->cur_format->fcc ==V4L2_PIX_FMT_MJPEG || - stream->cur_format->fcc ==V4L2_PIX_FMT_JPEG )) { -const u8 *packet = data + header_len; - -if (len >= header_len +2 && - packet[0 ] ==0xff && packet[1 ] ==JPEG_MARKER_SOI && - buf->bytesused !=0 ) { - buf->state =UVC_BUF_STATE_READY ; - buf->error =1 ; - stream->last_fid ^=UVC_STREAM_FID ; -return -EAGAIN ; - } - } - stream->last_fid = fid;return header_len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 197/389 HID: logitech-dj: Standardise hid_report_enum variable nomenclature
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <[email protected]>
[ Upstream commit a940aee176437046598dfc786b719bd96db3c74c ]
Since we will need to differentiate between the two report_enum types soon, let's unify the naming conventions now to save confusion and/or unnecessary/unrelated changes in upcoming commits.
{input,output}_report_enum is used in other places to let's conform.
--- drivers/hid/hid-logitech-dj.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/hid/hid-logitech-dj.c +6 -6
@@ -1668,7 +1668,7 @@ static int logi_dj_raw_event(struct hid_device *hdev,static int logi_dj_probe (struct hid_device *hdev,const struct hid_device_id *id) { -struct hid_report_enum *rep_enum; +struct hid_report_enum *input_report_enum;struct hid_report *rep;struct dj_receiver_dev *djrcv_dev;struct usb_interface *intf;
@@ -1711,10 +1711,10 @@ static int logi_dj_probe(struct hid_device *hdev, } } - rep_enum = &hdev->report_enum[HID_INPUT_REPORT ]; + input_report_enum = &hdev->report_enum[HID_INPUT_REPORT ];/* no input reports, bail out */ -if (list_empty (&rep_enum->report_list)) +if (list_empty (&input_report_enum->report_list))return -ENODEV ;/*
@@ -1722,7 +1722,7 @@ static int logi_dj_probe(struct hid_device *hdev,* Note: we should theoretically check for HID++ and DJ * collections, but this will do. */ -list_for_each_entry (rep, &rep_enum->report_list, list) { +list_for_each_entry (rep, &input_report_enum->report_list, list) {if (rep->application ==0xff000001 ) has_hidpp = true; }
@@ -1735,7 +1735,7 @@ static int logi_dj_probe(struct hid_device *hdev,return -ENODEV ;/* get the current application attached to the node */ - rep = list_first_entry(&rep_enum->report_list, struct hid_report, list); + rep = list_first_entry(&input_report_enum->report_list, struct hid_report, list); djrcv_dev =dj_get_receiver_dev (hdev, id->driver_data, rep->application, has_hidpp);if (!djrcv_dev) {
@@ -1743,7 +1743,7 @@ static int logi_dj_probe(struct hid_device *hdev,return -ENOMEM ; } -if (!rep_enum->numbered) +if (!input_report_enum->numbered) djrcv_dev->unnumbered_application = rep->application;/* Starts the usb device and connects to upper interfaces hiddev and
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 198/389 HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <[email protected]>
[ Upstream commit b6a57912854e7ea36f3b270032661140cc4209cd ]
logi_dj_recv_send_report() assumes that all incoming REPORT_ID_DJ_SHORT reports are 14 Bytes (DJREPORT_SHORT_LENGTH - 1) long. It uses that assumption to load the associated field's 'value' array with 14 Bytes of data. However, if a malicious user only sends say 1 Byte of data, 'report_count' will be 1 and only 1 Byte of memory will be allocated to the 'value' Byte array. When we come to populate 'value[1-13]' we will experience an OOB write.
--- drivers/hid/hid-logitech-dj.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/hid/hid-logitech-dj.c +10 -0
@@ -1669,6 +1669,7 @@ static int logi_dj_probe(struct hid_device *hdev, const struct hid_device_id *id) {struct hid_report_enum *input_report_enum; +struct hid_report_enum *output_report_enum;struct hid_report *rep;struct dj_receiver_dev *djrcv_dev;struct usb_interface *intf;
@@ -1711,6 +1712,15 @@ static int logi_dj_probe(struct hid_device *hdev, } } + output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT ]; + rep = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT ]; + +if (rep->maxfield <1 || 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 ; + } + input_report_enum = &hdev->report_enum[HID_INPUT_REPORT ];/* no input reports, bail out */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 199/389 HID: logitech-dj: fix wrong detection of bad DJ_SHORT output report
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Tissoires <[email protected]>
[ Upstream commit 8b9a097eb2fc37b486afd81388c693bf3ab44466 ]
commit b6a57912854e ("HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write") assumed that all HID devices attached to the logitech-dj driver was having an output report of DJ_SHORT.
However, on the receiver itself, we have 2 other HID device we attach
here: the mouse emulation and the keyboard emulation. For those devices the value of rep is NULL and we are triggered a segfault here.
This is doubly required because logitech-dj also handles non DJ devices that might not have the DJ collection.
--- drivers/hid/hid-logitech-dj.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/hid/hid-logitech-dj.c +2 -1
@@ -1715,7 +1715,8 @@ static int logi_dj_probe(struct hid_device *hdev, output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT ]; rep = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT ]; -if (rep->maxfield <1 || rep->field[0 ]->report_count !=DJREPORT_SHORT_LENGTH -1 ) { +if (rep && (rep->maxfield <1 || + 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 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 200/389 net: qrtr: ns: Limit the maximum server registration per node
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit d5ee2ff98322337951c56398e79d51815acbf955 ]
Current code does no bound checking on the number of servers added per node. A malicious client can flood NEW_SERVER messages and exhaust memory.
Fix this issue by limiting the maximum number of server registrations to 256 per node. If the NEW_SERVER message is received for an old port, then don't restrict it as it will get replaced. While at it, also rate limit the error messages in the failure path of qrtr_ns_worker().
Note that the limit of 256 is chosen based on the current platform requirements. If requirement changes in the future, this limit can be increased.
--- net/qrtr/ns.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
net/qrtr/ns.c +16 -10
@@ -68,13 +68,9 @@ struct qrtr_server {struct qrtr_node {unsigned int id;struct xarray servers; +u32 server_count; }; -/* Max lookup limit is chosen based on the current platform requirements. If the -* requirement changes in the future, this value can be increased. -*/ -#define QRTR_NS_MAX_LOOKUPS 64 -/* Max nodes, server, lookup limits are chosen based on the current platform * requirements. If the requirement changes in the future, these values can be * increased.
@@ -249,6 +245,17 @@ static struct qrtr_server *server_add(unsigned int service,if (!service || !port)return NULL ; + node =node_get (node_id); +if (!node) +return NULL ; + +/* Make sure the new servers per port are capped at the maximum value */ + old =xa_load (&node->servers, port); +if (!old && node->server_count >=QRTR_NS_MAX_SERVERS ) { +pr_err_ratelimited ("QRTR client node %u exceeds max server limit!\n" , node_id); +return NULL ; + } + srv =kzalloc (sizeof (*srv),GFP_KERNEL );if (!srv)return NULL ;
@@ -258,10 +265,6 @@ static struct qrtr_server *server_add(unsigned int service, srv->node = node_id; srv->port = port; - node =node_get (node_id); -if (!node) - goto err; -/* Delete the old server on the same port */ old =xa_store (&node->servers, port, srv,GFP_KERNEL );if (old) {
@@ -272,6 +275,8 @@ static struct qrtr_server *server_add(unsigned int service, }else {kfree (old); } + }else { + node->server_count++; } trace_qrtr_ns_server_add(srv->service, srv->instance,
@@ -312,6 +317,7 @@ static int server_del(struct qrtr_node *node, unsigned int port, bool bcast) }kfree (srv); + node->server_count--;return 0 ; }
@@ -716,7 +722,7 @@ static void qrtr_ns_worker(struct work_struct *work) }if (ret <0 ) -pr_err ("failed while handling packet from %d:%d" , +pr_err_ratelimited ("failed while handling packet from %d:%d" , sq.sq_node, sq.sq_port); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 201/389 net: qrtr: ns: Raise node count limit to 512
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Youssef Samir <[email protected]>
[ Upstream commit ff194cffd586cbd4cc49eccb002c65f2a902a277 ]
The current node limit of 64 breaks the functionality for a number of AI200 deployments that have up to 384 nodes. Raise the limit to 512.
Also, the backport of commit 27d5e84e810b ("net: qrtr: ns: Limit the total number of nodes") to 5.10, 5.15 and 6.1 dropped the node_count-- hunk in ctrl_cmd_bye(). Add it back.
--- net/qrtr/ns.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/qrtr/ns.c +3 -2
@@ -75,11 +75,11 @@ struct qrtr_node {* requirements. If the requirement changes in the future, these values can be * increased. */ -#define QRTR_NS_MAX_NODES 64 +#define QRTR_NS_MAX_NODES 512#define QRTR_NS_MAX_SERVERS 256#define QRTR_NS_MAX_LOOKUPS 64 -static u8 node_count; +static u16 node_count;static struct qrtr_node *node_get (unsigned int node_id) {
@@ -412,6 +412,7 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from) delete_node:xa_erase (&nodes, from->sq_node);kfree (node); + node_count--;return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 202/389 tls: separate no-async decryption request handling from async
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <[email protected]>
commit 41532b785e9d79636b3815a64ddf6a096647d011 upstream.
If we're not doing async, the handling is much simpler. There's no reference counting, we just need to wait for the completion to wake us up and return its result.
We should preferably also use a separate crypto_wait. I'm not seeing a UAF as I did in the past, I think aec7961916f3 ("tls: fix race between async notify and socket close") took care of it.
This will make the next fix easier.
--- net/tls/tls_sw.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
net/tls/tls_sw.c +10 -7
@@ -257,18 +257,21 @@ static int tls_do_decryption(struct sock *sk, tls_decrypt_done, skb);atomic_inc (&ctx->decrypt_pending); }else { +DECLARE_CRYPTO_WAIT (wait); +aead_request_set_callback (aead_req,CRYPTO_TFM_REQ_MAY_BACKLOG , - crypto_req_done, &ctx->async_wait); + crypto_req_done, &wait); + + ret =crypto_aead_decrypt (aead_req); +if (ret == -EINPROGRESS || ret == -EBUSY ) + ret =crypto_wait_req (ret, &wait); +return ret; } ret =crypto_aead_decrypt (aead_req); -if (ret == -EINPROGRESS ) { -if (async) -return ret; - - ret =crypto_wait_req (ret, &ctx->async_wait); - } +if (ret == -EINPROGRESS ) +return ret;if (async)atomic_dec (&ctx->decrypt_pending);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 203/389 dmaengine: sun6i-dma: Fix reclaim descriptors while terminating DMA
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongling Zeng <[email protected]>
[ Upstream commit ab1150115e68a46b687eb38c1ab92782018c9f2c ]
When terminating DMA transfers, active descriptors are not properly reclaimed. Only cyclic descriptors were handled, leaving non-cyclic descriptors and their LLI chains to be permanently leaked.
Fix by using vchan_terminate_vdesc() which handles both cyclic and non-cyclic descriptors by adding them to desc_terminated queue for proper cleanup.
Add pchan->desc != pchan->done check to prevent double-adding completed descriptors, which would corrupt the list.
--- drivers/dma/sun6i-dma.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/dma/sun6i-dma.c +4 -7
@@ -895,16 +895,13 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)spin_lock_irqsave (&vchan->vc.lock, flags); -if (vchan->cyclic) { - vchan->cyclic = false; -if (pchan && pchan->desc) { -struct virt_dma_desc *vd = &pchan->desc->vd; -struct virt_dma_chan *vc = &vchan->vc; +if (pchan && pchan->desc && pchan->desc != pchan->done) { +struct virt_dma_desc *vd = &pchan->desc->vd; -list_add_tail (&vd->node, &vc->desc_completed); - } +vchan_terminate_vdesc (vd); } + vchan->cyclic = false;vchan_get_all_descriptors (&vchan->vc, &head);if (pchan) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 204/389 ASoC: max98095: fix missing IS_ERR() before PTR_ERR() on mclk lookup
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uday Khare <[email protected]>
[ Upstream commit 317e21532e6ffa1de026bdbce5ba98e1b70ca5c6 ]
In max98095_probe(), the -EPROBE_DEFER check after devm_clk_get() is broken due to a missing IS_ERR() guard.
The code intends to return -EPROBE_DEFER only when the clock lookup fails with that specific error. However, without IS_ERR() the check:
if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER)
is called unconditionally, including when devm_clk_get() succeeds and returns a valid pointer. Calling PTR_ERR() on a valid pointer reinterprets its address as a signed long; the result is arbitrary and is almost never equal to -EPROBE_DEFER, so the check silently does nothing in the success case. When devm_clk_get() fails with any error other than -EPROBE_DEFER the check is also skipped, leaving max98095->mclk holding an error pointer with no indication to the caller.
This means a deferred probe will never actually be triggered for this device, and any non-EPROBE_DEFER clock error is silently swallowed with the error pointer left in the mclk field.
Fix this by adding the missing IS_ERR() guard around the PTR_ERR() call, matching the pattern already used in the sibling max98088 and wm8960 drivers.
--- sound/soc/codecs/max98095.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
sound/soc/codecs/max98095.c +3 -2
@@ -1990,8 +1990,9 @@ static int max98095_probe(struct snd_soc_component *component)int ret =0 ; max98095->mclk =devm_clk_get (component->dev,"mclk" ); -if (PTR_ERR (max98095->mclk) == -EPROBE_DEFER ) -return -EPROBE_DEFER ; +if (IS_ERR (max98095->mclk)) +if (PTR_ERR (max98095->mclk) == -EPROBE_DEFER ) +return -EPROBE_DEFER ;/* reset the codec, the DSP core, and disable all interrupts */ max98095_reset (component);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 205/389 ASoC: max98090: fix missing IS_ERR() before PTR_ERR() on mclk lookup
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uday Khare <[email protected]>
[ Upstream commit a792ce0fad61a70793ec565743f11d6ca534de59 ]
In max98090_probe(), the -EPROBE_DEFER check after devm_clk_get() is broken due to a missing IS_ERR() guard.
The code intends to return -EPROBE_DEFER only when the clock lookup fails with that specific error. However, without IS_ERR() the check:
if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
is called unconditionally, including when devm_clk_get() succeeds and returns a valid pointer. Calling PTR_ERR() on a valid pointer reinterprets its address as a signed long; the result is arbitrary and is almost never equal to -EPROBE_DEFER, so the check silently does nothing in the success case. When devm_clk_get() fails with any error other than -EPROBE_DEFER the check is also skipped, leaving max98090->mclk holding an error pointer with no indication to the caller.
This means a deferred probe will never actually be triggered for this device, and any non-EPROBE_DEFER clock error is silently swallowed with the error pointer left in the mclk field.
Fix this by adding the missing IS_ERR() guard around the PTR_ERR() call, matching the pattern already used in the sibling max98088 and wm8960 drivers.
--- sound/soc/codecs/max98090.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
sound/soc/codecs/max98090.c +3 -2
@@ -2393,8 +2393,9 @@ static int max98090_probe(struct snd_soc_component *component)dev_dbg (component->dev,"max98090_probe\n" ); max98090->mclk =devm_clk_get (component->dev,"mclk" ); -if (PTR_ERR (max98090->mclk) == -EPROBE_DEFER ) -return -EPROBE_DEFER ; +if (IS_ERR (max98090->mclk)) +if (PTR_ERR (max98090->mclk) == -EPROBE_DEFER ) +return -EPROBE_DEFER ; max98090->component = component;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 206/389 netfilter: nf_conntrack_sip: widen NAT rewrite delta to s32 in sip_help_tcp()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit db3d0e0e5d4bc5ab4fe445b9f413d1b486508ca5 ]
sip_help_tcp() stores the size change of each NAT-rewritten SIP message in s16 diff and accumulates it in s16 tdiff, but a single message can grow by more than S16_MAX while the packet stays under the 65535 enlarge_skb() limit: nf_nat_sip() rewrites every matching URI, and a long Contact list expands the message by tens of kilobytes. diff then wraps, and "datalen = datalen + diff - msglen" yields a huge unsigned datalen, so the next iteration's ct_sip_get_header() reads past the linearized skb tail.
Widen diff, tdiff and the seq_adjust hook to s32. Both are bounded by the 65535 byte packet limit, and the seqadj core is already s32 (nf_ct_seqadj_set() takes s32), so no previously accepted input is rejected.
BUG: KASAN: use-after-free in ct_sip_get_header (net/netfilter/nf_conntrack_sip.c:464) Read of size 1 at addr ffff888010800000 by task ksoftirqd/1/25 ct_sip_get_header (net/netfilter/nf_conntrack_sip.c:464) sip_help_tcp (net/netfilter/nf_conntrack_sip.c:1694) nf_confirm (net/netfilter/nf_conntrack_proto.c:183) nf_hook_slow (net/netfilter/core.c:619) ip6_output (net/ipv6/ip6_output.c:246) ip6_forward (net/ipv6/ip6_output.c:690) ipv6_rcv (net/ipv6/ip6_input.c:351) __netif_receive_skb_one_core (net/core/dev.c:6212) process_backlog (net/core/dev.c:6676) __napi_poll (net/core/dev.c:7735) net_rx_action (net/core/dev.c:7955) handle_softirqs (kernel/softirq.c:622) run_ksoftirqd (kernel/softirq.c:1076) ...
--- include/linux/netfilter/nf_conntrack_sip.h | 2 +- net/netfilter/nf_conntrack_sip.c | 2 +- net/netfilter/nf_nat_sip.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
include/linux/netfilter/nf_conntrack_sip.h +1 -1
@@ -115,7 +115,7 @@ struct nf_nat_sip_hooks { unsigned int *datalen);void (*seq_adjust)(struct sk_buff *skb, -unsigned int protoff,s16 off); +unsigned int protoff,s32 off); unsigned int (*expect)(struct sk_buff *skb, unsigned int protoff,
net/netfilter/nf_conntrack_sip.c +1 -1
@@ -1622,7 +1622,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,unsigned int matchoff, matchlen;unsigned int msglen, origlen;const char *dptr, *end; -s16 diff, tdiff =0 ; +s32 diff, tdiff =0 ;int ret =NF_ACCEPT ;unsigned long clen;bool term;
net/netfilter/nf_nat_sip.c +1 -1
@@ -313,7 +313,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, }static void nf_nat_sip_seq_adjust (struct sk_buff *skb,unsigned int protoff, -s16 off) +s32 off) {enum ip_conntrack_info ctinfo;struct nf_conn *ct =nf_ct_get (skb, &ctinfo);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 207/389 keys: fix out-of-bounds read in keyring_get_key_chunk()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 63918731f9ae25b5deb022f118e941e6dddfcef4 ]
For description-level chunks keyring_get_key_chunk() advances the read pointer by level * sizeof(long) past the inline prefix but only bounds-checks the prefix, so a long enough key description is read past its kmemdup(desc, desc_len + 1) allocation. Compute the full byte offset and bounds-check the description against it before reading.
The walk only reaches a description-level chunk when two keys collide through the hash, x, type and domain_tag chunks, so this is reached from an unprivileged add_key(2) with a crafted pair of same-type keys whose index hashes collide; KASAN reports a slab-out-of-bounds read.
--- security/keys/keyring.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
security/keys/keyring.c +5 -4
@@ -271,6 +271,7 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)unsigned long chunk =0 ;const u8 *d;int desc_len = index_key->desc_len, n =sizeof (chunk); +unsigned int offset; level /=ASSOC_ARRAY_KEY_CHUNK_SIZE ;switch (level) {
@@ -284,12 +285,12 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)return (unsigned long )index_key->domain_tag;default : level -=4 ; -if (desc_len <=sizeof (index_key->desc)) + offset =sizeof (index_key->desc) + level *sizeof (long ); +if (desc_len <= offset)return 0 ; - d = index_key->description +sizeof (index_key->desc); - d += level *sizeof (long ); - desc_len -=sizeof (index_key->desc); + d = index_key->description + offset; + desc_len -= offset;if (desc_len > n) desc_len = n; do {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 208/389 keys: make keyring key-chunk byte order agree with keyring_diff_objects()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 58565eef0f8d861aae92abfb7658458d661cee17 ]
keyring_get_key_chunk() loads description bytes into the index chunk low address first, while keyring_diff_objects() numbers the first differing bit from the low end and folds the absolute byte index into the level without removing the inline-prefix offset the level already carries. The two disagree on byte order and bit position, so the array can be told two keys first differ at a bit that does not differ in the chunk the walker uses, letting crafted descriptions collide into one node.
Load the chunk in the order keyring_diff_objects() assumes and drop the inline-prefix length when folding the byte index into the level. This only changes the in-memory ordering used to place keys within a keyring; add, search and read of non-colliding keys are unaffected.
--- security/keys/keyring.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
security/keys/keyring.c +3 -2
@@ -293,9 +293,10 @@ static unsigned long keyring_get_key_chunk(const void *data, int level) desc_len -= offset;if (desc_len > n) desc_len = n; + d += desc_len;do { chunk <<=8 ; - chunk |= *d++; + chunk |= *--d; }while (--desc_len >0 );return chunk; }
@@ -376,7 +377,7 @@ static int keyring_diff_objects(const void *object, const void *data)return -1 ; differ_plus_i: - level += i; + level += i - (int )sizeof (a->desc); differ: i = level *8 +__ffs (seg_a ^ seg_b);return i;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 209/389 assoc_array: trim the final shortcut word using the current chunk end
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit a82c8a05e86f3f84e09698f65b4515b5d04633f6 ]
assoc_array_walk() masks off the bits past shortcut->skip_to_level in the word that contains skip_to_level, gated onround_up(sc_level, ASSOC_ARRAY_KEY_CHUNK_SIZE) > skip_to_level.
That guard is wrong in two opposite ways:
- When sc_level is word-aligned (every word after the first) round_up() is a no-op, so the guard is sc_level > skip_to_level and never fires for the word that holds skip_to_level. A shortcut that spans more than one word and ends in the middle of its last word leaves that word untrimmed, and its stale high bits leak into the dissimilarity word and can steer the walk down the wrong descendant.
- When sc_level is unaligned (the first word) and skip_to_level sits on the next chunk boundary, sc_level + CHUNK would exceed skip_to_level and fire the trim with shift = skip_to_level & CHUNK_MASK == 0, which clears the whole dissimilarity word and makes a differing shortcut compare equal.
Use the end of the chunk that contains sc_level instead:
skip_to_level < round_down(sc_level, CHUNK) + CHUNK
For an aligned sc_level whose word holds skip_to_level this now fires (the first bug); for an unaligned sc_level with skip_to_level on the following boundary it does not, so shift is never 0 when the branch runs and the trim never clears the whole word.
--- lib/assoc_array.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
lib/assoc_array.c +2 -1
@@ -255,7 +255,8 @@ assoc_array_walk(const struct assoc_array *array, sc_segments = shortcut->index_key[sc_level >>ASSOC_ARRAY_KEY_CHUNK_SHIFT ]; dissimilarity = segments ^ sc_segments; -if (round_up (sc_level,ASSOC_ARRAY_KEY_CHUNK_SIZE ) > shortcut->skip_to_level) { +if (shortcut->skip_to_level <round_down (sc_level, +ASSOC_ARRAY_KEY_CHUNK_SIZE ) +ASSOC_ARRAY_KEY_CHUNK_SIZE ) {/* Trim segments that are beyond the shortcut */ int shift = shortcut->skip_to_level &ASSOC_ARRAY_KEY_CHUNK_MASK ; dissimilarity &= ~(ULONG_MAX << shift);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 210/389 netfilter: xt_hashlimit: validate hashtable supports XT_HASHLIMIT_RATE_MATCH
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 305b63e1402267459fdabb183af4527f6799eebf ]
The XT_HASHLIMIT_RATE_MATCH flag mode changes the semantics of the dsthash_ent structure which represents an entry in the hashtable. There is a union area which uses a different layout to express the rate match mode.
Update .checkentry path to validate the XT_HASHLIMIT_RATE_MATCH mode flag is requested by two or more different rules that refer to the same hashtable. Otherwise, uninitialized access to the burst field in the union is possible.
Reject the use of the XT_HASHLIMIT_RATE_MATCH mode flag if set on by revision less than 3 too.
--- net/netfilter/xt_hashlimit.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
net/netfilter/xt_hashlimit.c +15 -1
@@ -118,6 +118,7 @@ struct xt_hashlimit_htable {refcount_t use;u_int8_t family;bool rnd_initialized; +bool ratematch;struct hashlimit_cfg3 cfg;/* config */
@@ -325,6 +326,7 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg,vfree (hinfo);return -ENOMEM ; } + hinfo->ratematch = !!(cfg->mode &XT_HASHLIMIT_RATE_MATCH );spin_lock_init (&hinfo->lock);switch (revision) {
@@ -868,7 +870,10 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par, }/* Check for overflow. */ -if (revision >=3 && cfg->mode &XT_HASHLIMIT_RATE_MATCH ) { +if (cfg->mode &XT_HASHLIMIT_RATE_MATCH ) { +if (revision <3 ) +return -EINVAL ; +if (cfg->avg ==0 || cfg->avg >U32_MAX ) {pr_info_ratelimited ("invalid rate\n" );return -ERANGE ;
@@ -901,6 +906,15 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par,mutex_unlock (&hashlimit_mutex);return ret; } + }else { +if ((cfg->mode &XT_HASHLIMIT_RATE_MATCH && + !(*hinfo)->ratematch) || + (!(cfg->mode &XT_HASHLIMIT_RATE_MATCH ) && + (*hinfo)->ratematch)) { +mutex_unlock (&hashlimit_mutex); +htable_put (*hinfo); +return -EINVAL ; + } }mutex_unlock (&hashlimit_mutex);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 211/389 netfilter: nft_payload: fix mask build for partial field offload
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei (Microsoft) <[email protected]>
[ Upstream commit 39e88f28fb32bf02bd4b525c24c842c9cff5663d ]
nft_payload_offload_mask() builds the offload match mask for a payload expression that covers only part of a header field. For a partial IPv6 address match (field_len = 16, priv_len = 1) that shift is 1 << 120, which is undefined on the 32-bit int operand. It also trims only one word, so the remaining words stay 0xffffffff (and when priv_len is a multiple of 4 the trim is skipped entirely), leaving the mask covering more bytes than the rule matches.
UBSAN: shift-out-of-bounds in net/netfilter/nft_payload.c:278:20 shift exponent 120 is too large for 32-bit type 'int' ...
The match is byte-granular and struct nft_data is zero-initialised, so the correct mask is simply the first priv_len bytes set to 0xff. Set those bytes directly and drop the word/shift trimming; this removes the undefined shift and no longer over-masks the trailing bytes.
--- net/netfilter/nft_payload.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-)
net/netfilter/nft_payload.c +1 -11
@@ -159,9 +159,7 @@ static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)static bool nft_payload_offload_mask (struct nft_offload_reg *reg,u32 priv_len,u32 field_len) { -unsigned int remainder, delta, k;struct nft_data mask = {}; -__be32 remainder_mask;if (priv_len == field_len) {memset (®->mask,0xff , priv_len);
@@ -170,15 +168,7 @@ static bool nft_payload_offload_mask(struct nft_offload_reg *reg,return false; } -memset (&mask,0xff , field_len); - remainder = priv_len %sizeof (u32); -if (remainder) { - k = priv_len /sizeof (u32); - delta = field_len - priv_len; - remainder_mask =htonl (~((1 << (delta *BITS_PER_BYTE )) -1 )); - mask.data[k] = (__force u32 )remainder_mask; - } - +memset (&mask,0xff , priv_len);memcpy (®->mask, &mask, field_len);return true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 212/389 rds: Fix inet6_addr_lst NULL dereference when IPv6 is disabled
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilia Gavrilov <[email protected]>
[ Upstream commit 9c805e592a29be9e4e61ff1bd567da04aa8fd6f9 ]
When booting with the 'ipv6.disable=1' parameter, inet6_addr_lst is never initialized because inet6_init() exits before addrconf_init() is called to initialize it. An attempt to bind an RDS socket to an ipv6 address results in a crash in __ipv6_chk_addr_and_flags()
KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] RIP: 0010:__ipv6_chk_addr_and_flags+0x1df/0x7e0 Call Trace: <TASK> ipv6_chk_addr+0x3b/0x50 rds_tcp_laddr_check+0x155/0x3b0 [rds_tcp] rds_trans_get_preferred+0x15d/0x2d0 [rds] ? trace_hardirqs_on+0x2d/0x110 rds_bind+0x1433/0x1d60 [rds] ? rds_remove_bound+0xd50/0xd50 [rds] ? aa_af_perm+0x250/0x250 ? __might_fault+0xde/0x190 ? __sys_bind+0x1dc/0x210 __sys_bind+0x1dc/0x210 ? __ia32_sys_socketpair+0x100/0x100 ? restore_fpregs_from_fpstate+0x53/0x100 __x64_sys_bind+0x73/0xb0 ? syscall_enter_from_user_mode+0x1c/0x50 do_syscall_64+0x34/0x80 entry_SYSCALL_64_after_hwframe+0x6e/0xd8 RIP: 0033:0x7f47f8269ea9 </TASK>
The following code reproduces the issue:
struct sockaddr_in6 addr;
s = socket(PF_RDS, SOCK_SEQPACKET, 0);
memset(&addr, 0, sizeof(addr));inet_pton(AF_INET6, ADDRESS, &addr.sin6_addr);
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(PORT);
bind(s, &addr, sizeof(addr));
Found by InfoTeCS on behalf of Linux Verification Center (linuxtesting.org) with Syzkaller.
Stable-dep-of: 78f75d632f74 ("rds: tcp: hold the RCU lock across ipv6_chk_addr() in rds_tcp_laddr_check()")
--- net/rds/ib.c | 4 ++++ net/rds/ib_cm.c | 4 ++++ net/rds/tcp.c | 8 +++++--- 3 files changed, 13 insertions(+), 3 deletions(-)
net/rds/ib.c +4 -0
@@ -431,6 +431,10 @@ static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr, sa = (struct sockaddr *)&sin; }else {#if IS_ENABLED (CONFIG_IPV6 ) +if (!ipv6_mod_enabled ()) { + ret = -EADDRNOTAVAIL ; + goto out; + }memset (&sin6,0 ,sizeof (sin6)); sin6.sin6_family =AF_INET6 ; sin6.sin6_addr = *addr;
net/rds/ib_cm.c +4 -0
@@ -844,6 +844,10 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id, dp = event->param.conn.private_data;if (isv6) {#if IS_ENABLED (CONFIG_IPV6 ) +if (!ipv6_mod_enabled ()) { + err = -EOPNOTSUPP ; + goto out; + } dp_cmn = &dp->ricp_v6.dp_cmn; saddr6 = &dp->ricp_v6.dp_saddr; daddr6 = &dp->ricp_v6.dp_daddr;
net/rds/tcp.c +5 -3
@@ -341,9 +341,11 @@ int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,rcu_read_unlock (); }#if IS_ENABLED (CONFIG_IPV6 ) - ret =ipv6_chk_addr (net, addr, dev,0 ); -if (ret) -return 0 ; +if (ipv6_mod_enabled ()) { + ret =ipv6_chk_addr (net, addr, dev,0 ); +if (ret) +return 0 ; + }#endif return -EADDRNOTAVAIL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 213/389 rds: tcp: hold the RCU lock across ipv6_chk_addr() in rds_tcp_laddr_check()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 78f75d632f74b8de0f081a128588f7c37d0d1164 ]
rds_tcp_laddr_check() looks up a scoped IPv6 interface with dev_get_by_index_rcu(), drops the RCU read-side lock, and only then passes the bare struct net_device * into ipv6_chk_addr().
dev_get_by_index_rcu() only keeps the device alive within the same RCU read-side section. After rcu_read_unlock(), a concurrent RTM_DELLINK can free the net_device; ipv6_chk_addr() then dereferences the stale pointer in __ipv6_chk_addr_and_flags() (e.g. l3mdev_master_dev_rcu(dev)), reading freed memory.
Keep the RCU read-side lock held across the ipv6_chk_addr() call instead of dropping it right after the lookup, so the device cannot be freed while it is in use.
BUG: KASAN: slab-use-after-free in __ipv6_chk_addr_and_flags (... net/ipv6/addrconf.c:1998) Read of size 8 at addr ffff8880106ec000 by task exploit/153 Call Trace: ... kasan_report (mm/kasan/report.c:595) __ipv6_chk_addr_and_flags (... net/ipv6/addrconf.c:1998) ipv6_chk_addr (net/ipv6/addrconf.c:2031 net/ipv6/addrconf.c:1972) rds_tcp_laddr_check (net/rds/tcp.c:370) rds_bind (net/rds/bind.c:248) __sys_bind (net/socket.c:1920) __x64_sys_bind (net/socket.c:1956) do_syscall_64 (arch/x86/entry/syscall_64.c:63) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
--- net/rds/tcp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
net/rds/tcp.c +5 -3
@@ -330,23 +330,25 @@ int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,/* If the scope_id is specified, check only those addresses * hosted on the specified interface. */ +rcu_read_lock ();if (scope_id !=0 ) { -rcu_read_lock (); dev =dev_get_by_index_rcu (net, scope_id);/* scope_id is not valid... */ if (!dev) {rcu_read_unlock ();return -EADDRNOTAVAIL ; } -rcu_read_unlock (); }#if IS_ENABLED (CONFIG_IPV6 )if (ipv6_mod_enabled ()) { ret =ipv6_chk_addr (net, addr, dev,0 ); -if (ret) +if (ret) { +rcu_read_unlock ();return 0 ; + } }#endif +rcu_read_unlock ();return -EADDRNOTAVAIL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 214/389 scsi: libiscsi: Fix stale-data leak into the SCSI sense buffer
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 98b87885de4b7f605533a2860685f5689fce8e82 ]
iscsi_scsi_cmd_rsp() copies the sense data of a SCSI Response from the target-supplied data segment. The segment carries a 2-byte sense length followed by the sense bytes, so it must hold 2 + senselen bytes, but the bounds check only requires datalen >= senselen:
senselen = get_unaligned_be16(data); if (datalen < senselen) goto invalid_datalen; memcpy(sc->sense_buffer, data + 2, min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
A target that returns a SCSI Response whose datalen equals senselen (with senselen <= SCSI_SENSE_BUFFERSIZE) makes the memcpy() from data + 2 read up to two bytes past the received data. Those bytes are stale conn->data contents and end up in the command's sense buffer, which is returned to userspace.
Account for the 2-byte sense length prefix in the check.
--- drivers/scsi/libiscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/libiscsi.c +1 -1
@@ -840,7 +840,7 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } senselen =get_unaligned_be16 (data); -if (datalen < senselen) +if (datalen < senselen +2 ) goto invalid_datalen; memcpy(sc->sense_buffer, data + 2,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 215/389 scsi: libiscsi_tcp: Bound SCSI Response data segment to the connection buffer
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit c1dea15f819cded9b3faf58f8bec72323568b6e6 ]
iscsi_tcp_hdr_dissect() receives the data segment of several PDU types into the fixed-size conn->data buffer, which is allocated for ISCSI_DEF_MAX_RECV_SEG_LEN (8192) bytes. For the LOGIN_RSP, TEXT_RSP, REJECT and ASYNC_EVENT opcodes the dissect path already rejects a PDU whose DataSegmentLength exceeds that buffer.
The SCSI Command Response (ISCSI_OP_SCSI_CMD_RSP) path also copies its data segment (sense/response data) into conn->data via iscsi_tcp_data_recv_prep(), but it does so without the same check. The only upstream bound on in.datalen is conn->max_recv_dlength, the initiator's advertised MaxRecvDataSegmentLength, which is commonly negotiated well above 8192 (open-iscsi defaults to 262144). A target that returns a SCSI Response with a DataSegmentLength between 8193 and max_recv_dlength therefore overflows the 8192-byte conn->data buffer.
Once the same bound applies, ISCSI_OP_SCSI_CMD_RSP is handled exactly like those responses: bound the data segment, receive it into conn->data when present, and otherwise complete the PDU with no data. Fold the opcode into that case group rather than duplicating the check.
--- drivers/scsi/libiscsi_tcp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
drivers/scsi/libiscsi_tcp.c +1 -7
@@ -722,13 +722,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) rc =__iscsi_complete_pdu (conn, hdr,NULL ,0 );spin_unlock (&conn->session->back_lock);break ; -case ISCSI_OP_SCSI_CMD_RSP : -if (tcp_conn->in.datalen) { -iscsi_tcp_data_recv_prep (tcp_conn); -return 0 ; - } - rc =iscsi_complete_pdu (conn, hdr,NULL ,0 ); -break ;case ISCSI_OP_R2T :spin_lock (&conn->session->back_lock); task =iscsi_itt_to_ctask (conn, hdr->itt);
@@ -745,6 +738,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) }else rc =ISCSI_ERR_PROTO ;break ; +case ISCSI_OP_SCSI_CMD_RSP :case ISCSI_OP_LOGIN_RSP :case ISCSI_OP_TEXT_RSP :case ISCSI_OP_REJECT :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 216/389 smb: client: fix buffer leaks in SMB1 read and write
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
[ Upstream commit 6a3e16d60e81a4aa3056ab15617036cfbea2e07d ]
CIFSSMBRead(), CIFSSMBWrite() and CIFSSMBWrite2() allocate a request buffer before checking whether tcon->ses->server is NULL. If that defensive check ever fails, the helper returns -ECONNABORTED without releasing the request buffer.
Fix these leaks by releasing the allocated request buffer before returning from these error paths. Use cifs_small_buf_release() for the buffers allocated by small_smb_init() and cifs_buf_release() for the buffer allocated by smb_init().
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.1.
An x86_64 allyesconfig build showed no new warnings.
Runtime validation used a temporary fault-injection hook to force tcon->ses->server to NULL after request-buffer initialization. On the unfixed kernel, the harness observed two leaked small request buffers and one leaked large request buffer, with directed kmemleak dumps confirming the CIFS buffer allocation stacks. After the fix, no CIFS request-buffer deltas remained.
--- fs/cifs/cifssmb.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
fs/cifs/cifssmb.c +9 -3
@@ -1774,8 +1774,10 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms, pSMB->hdr.PidHigh =cpu_to_le16 ((__u16)(pid >>16 ));/* tcon and ses pointer are checked in smb_init */ -if (tcon->ses->server ==NULL ) +if (!tcon->ses->server) { +cifs_small_buf_release (pSMB);return -ECONNABORTED ; + } pSMB->AndXCommand =0xFF ;/* none */ pSMB->Fid = netfid;
@@ -1887,8 +1889,10 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, pSMB->hdr.PidHigh =cpu_to_le16 ((__u16)(pid >>16 ));/* tcon and ses pointer are checked in smb_init */ -if (tcon->ses->server ==NULL ) +if (!tcon->ses->server) { +cifs_buf_release (pSMB);return -ECONNABORTED ; + } pSMB->AndXCommand =0xFF ;/* none */ pSMB->Fid = netfid;
@@ -2317,8 +2321,10 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, pSMB->hdr.PidHigh =cpu_to_le16 ((__u16)(pid >>16 ));/* tcon and ses pointer are checked in smb_init */ -if (tcon->ses->server ==NULL ) +if (!tcon->ses->server) { +cifs_small_buf_release (pSMB);return -ECONNABORTED ; + } pSMB->AndXCommand =0xFF ;/* none */ pSMB->Fid = netfid;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 217/389 hwmon: (nct6775-core) Prevent access to unsupported weight registers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit d0b704e569ac3b8416d8e02270cdc9bf830ed395 ]
Sashiko reports:
During initialization of the nct6116 chip, the driver sets data->pwm_num to 5. However, it assigns several NCT6106 register arrays (such as NCT6106_REG_WEIGHT_DUTY_STEP, NCT6106_REG_WEIGHT_TEMP_SEL, and NCT6106_REG_WEIGHT_TEMP_*) to data->REG_PWM and data->REG_WEIGHT_TEMP. These arrays only contain 3 elements.
In nct6775_update_pwm(), the driver iterates up to data->pwm_num. If data->has_pwm has bits 3 or 4 set (which is structurally possible for nct6116), the loop attempts to read elements at index 3 and 4 from these 3-element arrays. This results in a global out-of-bounds read, which can be caught by KASAN.
Furthermore, the driver uses these garbage out-of-bounds values as hardware register addresses for subsequent read and write operations. This leads to invalid hardware register access, potentially causing hardware misconfiguration or system crashes.
The underlying problem is that the chip does support up to five fan control channels, but only the first three support weight control. Fix the problem by extending the affected weight register arrays with zeroed fields. The driver uses zeroed register addresses to determine if a register is supported or not, and skips accesses for unsupported registers.
--- drivers/hwmon/nct6775.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/hwmon/nct6775.c +6 -6
@@ -851,12 +851,12 @@ static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };static const u16 NCT6106_REG_TARGET [] = {0x111 ,0x121 ,0x131 }; -static const u16 NCT6106_REG_WEIGHT_TEMP_SEL [] = {0x168 ,0x178 ,0x188 }; -static const u16 NCT6106_REG_WEIGHT_TEMP_STEP [] = {0x169 ,0x179 ,0x189 }; -static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL [] = {0x16a ,0x17a ,0x18a }; -static const u16 NCT6106_REG_WEIGHT_DUTY_STEP [] = {0x16b ,0x17b ,0x18b }; -static const u16 NCT6106_REG_WEIGHT_TEMP_BASE [] = {0x16c ,0x17c ,0x18c }; -static const u16 NCT6106_REG_WEIGHT_DUTY_BASE [] = {0x16d ,0x17d ,0x18d }; +static const u16 NCT6106_REG_WEIGHT_TEMP_SEL [] = {0x168 ,0x178 ,0x188 ,0 ,0 }; +static const u16 NCT6106_REG_WEIGHT_TEMP_STEP [] = {0x169 ,0x179 ,0x189 ,0 ,0 }; +static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL [] = {0x16a ,0x17a ,0x18a ,0 ,0 }; +static const u16 NCT6106_REG_WEIGHT_DUTY_STEP [] = {0x16b ,0x17b ,0x18b ,0 ,0 }; +static const u16 NCT6106_REG_WEIGHT_TEMP_BASE [] = {0x16c ,0x17c ,0x18c ,0 ,0 }; +static const u16 NCT6106_REG_WEIGHT_DUTY_BASE [] = {0x16d ,0x17d ,0x18d ,0 ,0 };static const u16 NCT6106_REG_AUTO_TEMP [] = {0x160 ,0x170 ,0x180 };static const u16 NCT6106_REG_AUTO_PWM [] = {0x164 ,0x174 ,0x184 };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 218/389 forcedeth: fix UAF of txrx_stats in nv_remove
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
[ Upstream commit 22666ba1420164753d7b0f5a841986b25ace5435 ]
nv_remove() frees the per-CPU txrx_stats before unregister_netdev(). Until unregister completes, ndo_get_stats64, the NAPI/xmit data path, and nv_close()/drain may still access txrx_stats, leading to a use-after-free.
Free the stats only after unregister_netdev().
--- drivers/net/ethernet/nvidia/forcedeth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/nvidia/forcedeth.c +2 -2
@@ -6199,10 +6199,10 @@ static void nv_remove(struct pci_dev *pci_dev)struct net_device *dev =pci_get_drvdata (pci_dev);struct fe_priv *np =netdev_priv (dev); -free_percpu (np->txrx_stats); -unregister_netdev (dev); +free_percpu (np->txrx_stats); +nv_restore_mac_addr (pci_dev);/* restore any phy related changes */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 219/389 hwmon: (adt7470) Fix busy-loop and I2C flooding in update thread
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Angelo Daros de Luca <[email protected]>
[ Upstream commit cb0b7f9c43b0abbd422a7e4c2c85e91db429207c ]
When userspace configures 'auto_update_interval' to 0 via sysfs, the background kthread executes schedule_timeout_interruptible(0), which returns immediately.
If 'num_temp_sensors' is concurrently or previously set to 0, the msleep_interruptible() delay inside adt7470_read_temperatures() also becomes 0. This combination forces the background thread into a tight, unbounded busy-loop, hogging the CPU and flooding the I2C bus with a continuous stream of transactions.
Fix this vulnerability by raising the lower limit of the clamp_val in auto_update_interval_store() from 0 to 500 milliseconds. This guarantees a reasonable minimum sleep window between sensor updates, protecting the system from intentional or accidental I2C bus denial of service.
--- drivers/hwmon/adt7470.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/adt7470.c +1 -1
@@ -408,7 +408,7 @@ static ssize_t auto_update_interval_store(struct device *dev,if (kstrtol (buf,10 , &temp))return -EINVAL ; - temp =clamp_val (temp,0 ,60000 ); + temp =clamp_val (temp,500 ,60000 );mutex_lock (&data->lock); data->auto_update_interval = temp;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 220/389 hwmon: (adt7470) Fix swapped PWM3 and PWM4 auto mode masks
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Angelo Daros de Luca <[email protected]>
[ Upstream commit a3850231521b06bbbb18c8ebea100320c14a08be ]
The ADT7470_PWM3_AUTO_MASK and ADT7470_PWM4_AUTO_MASK macros are currently defined with swapped bit values.
According to Table 22 of the ADT7470 datasheet, the Fan Control Mode Configuration for register 0x69 follows the exact same bit position layout as register 0x68:
- 0x68 Bit[7] corresponds to BHVR1 (PWM1) -> 0x80
- 0x68 Bit[6] corresponds to BHVR2 (PWM2) -> 0x40
- 0x69 Bit[7] corresponds to BHVR3 (PWM3) -> 0x80
- 0x69 Bit[6] corresponds to BHVR4 (PWM4) -> 0x40
Consequently, PWM3 should use mask 0x80 and PWM4 should use 0x40.
This typo did not cause any functional bugs because these specific macros are never referenced in the driver code. Instead, the driver correctly applies the configuration by relying on the modulo parity of the channel index (e.g., channel % 2) to selectively apply either ADT7470_PWM1_AUTO_MASK (0x80) or ADT7470_PWM2_AUTO_MASK (0x40). Since the bit layout is identical between the two configuration registers, the hardware is currently configured correctly.
Fix the macro definitions to reflect the datasheet accurately and prevent future bugs or confusion during code review and refactoring. As this is a purely cosmetic fix with no functional impact, a backport to stable kernels is not necessary.
--- drivers/hwmon/adt7470.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwmon/adt7470.c +2 -2
@@ -66,8 +66,8 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };#define ADT7470_PWM1_AUTO_MASK 0x80#define ADT7470_PWM_AUTO_MASK 0xC0#define ADT7470_REG_PWM34_CFG 0x69 -#define ADT7470_PWM3_AUTO_MASK 0x40 -#define ADT7470_PWM4_AUTO_MASK 0x80 +#define ADT7470_PWM4_AUTO_MASK 0x40 +#define ADT7470_PWM3_AUTO_MASK 0x80#define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A#define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 221/389 hwmon: (adt7470) Create functions for updating readings and limits
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Packham <[email protected]>
[ Upstream commit ad00a02e34b481396938c5fa62ee642bff7fbb08 ]
Split the body of adt7470_update_device() into two helper functions adt7470_update_sensors() and adt7470_update_limits(). Although neither of the new helpers returns an error yet lay the groundwork for propagating failures through to the sysfs readers.
Stable-dep-of: 92413f439d1e ("hwmon: (adt7470) Fix PWM auto temp state array and bounds check")
--- drivers/hwmon/adt7470.c | 154 ++++++++++++++++++++++++++++++---------- 1 file changed, 118 insertions(+), 36 deletions(-)
drivers/hwmon/adt7470.c +118 -36
@@ -270,37 +270,11 @@ static int adt7470_update_thread(void *p)return 0 ; } -static struct adt7470_data *adt7470_update_device (struct device *dev) +static int adt7470_update_sensors (struct adt7470_data *data) { -struct adt7470_data *data =dev_get_drvdata (dev);struct i2c_client *client = data->client; -unsigned long local_jiffies = jiffies;u8 cfg;int i; -int need_sensors =1 ; -int need_limits =1 ; - -/* -* Figure out if we need to update the shadow registers. -* Lockless means that we may occasionally report out of -* date data. -*/ -if (time_before (local_jiffies, data->sensors_last_updated + -SENSOR_REFRESH_INTERVAL ) && - data->sensors_valid) - need_sensors =0 ; - -if (time_before (local_jiffies, data->limits_last_updated + -LIMIT_REFRESH_INTERVAL ) && - data->limits_valid) - need_limits =0 ; - -if (!need_sensors && !need_limits) -return data; - -mutex_lock (&data->lock); -if (!need_sensors) - goto no_sensor_update;if (!data->temperatures_probed)adt7470_read_temperatures (client, data);
@@ -352,12 +326,13 @@ static struct adt7470_data *adt7470_update_device(struct device *dev) data->alarms_mask =adt7470_read_word_data (client,ADT7470_REG_ALARM1_MASK ); - data->sensors_last_updated = local_jiffies; - data->sensors_valid =1 ; +return 0 ; +} -no_sensor_update: -if (!need_limits) - goto out; +static int adt7470_update_limits (struct adt7470_data *data) +{ +struct i2c_client *client = data->client; +int i;for (i =0 ; i <ADT7470_TEMP_COUNT ; i++) { data->temp_min[i] = i2c_smbus_read_byte_data(client,
@@ -382,12 +357,55 @@ static struct adt7470_data *adt7470_update_device(struct device *dev) ADT7470_REG_PWM_TMIN(i)); } - data->limits_last_updated = local_jiffies; - data->limits_valid =1 ; +return 0 ; +} +static struct adt7470_data *adt7470_update_device (struct device *dev) +{ +struct adt7470_data *data =dev_get_drvdata (dev); +unsigned long local_jiffies = jiffies; +int need_sensors =1 ; +int need_limits =1 ; +int err; + +/* +* Figure out if we need to update the shadow registers. +* Lockless means that we may occasionally report out of +* date data. +*/ +if (time_before (local_jiffies, data->sensors_last_updated + +SENSOR_REFRESH_INTERVAL ) && + data->sensors_valid) + need_sensors =0 ; + +if (time_before (local_jiffies, data->limits_last_updated + +LIMIT_REFRESH_INTERVAL ) && + data->limits_valid) + need_limits =0 ; + +if (!need_sensors && !need_limits) +return data; + +mutex_lock (&data->lock); +if (need_sensors) { + err =adt7470_update_sensors (data); +if (err <0 ) + goto out; + data->sensors_last_updated = local_jiffies; + data->sensors_valid =1 ; + } + +if (need_limits) { + err =adt7470_update_limits (data); +if (err <0 ) + goto out; + data->limits_last_updated = local_jiffies; + data->limits_valid =1 ; + } out:mutex_unlock (&data->lock); -return data; + +return err <0 ?ERR_PTR (err) : data; } static ssize_t auto_update_interval_show(struct device *dev,
@@ -395,6 +413,10 @@ static ssize_t auto_update_interval_show(struct device *dev, char *buf) {struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" , data->auto_update_interval); }
@@ -422,6 +444,10 @@ static ssize_t num_temp_sensors_show(struct device *dev, char *buf) {struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" , data->num_temp_sensors); }
@@ -451,6 +477,10 @@ static ssize_t temp_min_show(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" ,1000 * data->temp_min[attr->index]); }
@@ -483,6 +513,10 @@ static ssize_t temp_max_show(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" ,1000 * data->temp_max[attr->index]); }
@@ -515,6 +549,10 @@ static ssize_t temp_show(struct device *dev, struct device_attribute *devattr, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" ,1000 * data->temp[attr->index]); }
@@ -524,6 +562,9 @@ static ssize_t alarm_mask_show(struct device *dev, {struct adt7470_data *data =adt7470_update_device (dev); +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%x\n" , data->alarms_mask); }
@@ -554,6 +595,9 @@ static ssize_t fan_max_show(struct device *dev,struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); +if (IS_ERR (data)) +return PTR_ERR (data); +if (FAN_DATA_VALID (data->fan_max[attr->index]))return sprintf (buf,"%d\n" ,FAN_PERIOD_TO_RPM (data->fan_max[attr->index]));
@@ -590,6 +634,9 @@ static ssize_t fan_min_show(struct device *dev,struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); +if (IS_ERR (data)) +return PTR_ERR (data); +if (FAN_DATA_VALID (data->fan_min[attr->index]))return sprintf (buf,"%d\n" ,FAN_PERIOD_TO_RPM (data->fan_min[attr->index]));
@@ -626,6 +673,9 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); +if (IS_ERR (data)) +return PTR_ERR (data); +if (FAN_DATA_VALID (data->fan[attr->index]))return sprintf (buf,"%d\n" ,FAN_PERIOD_TO_RPM (data->fan[attr->index]));
@@ -637,6 +687,10 @@ static ssize_t force_pwm_max_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct adt7470_data *data = adt7470_update_device(dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" , data->force_pwm_max); }
@@ -670,6 +724,10 @@ static ssize_t pwm_show(struct device *dev, struct device_attribute *devattr, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" , data->pwm[attr->index]); }
@@ -763,6 +821,10 @@ static ssize_t pwm_max_show(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" , data->pwm_max[attr->index]); }
@@ -794,6 +856,10 @@ static ssize_t pwm_min_show(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" , data->pwm_min[attr->index]); }
@@ -825,6 +891,10 @@ static ssize_t pwm_tmax_show(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +/* the datasheet says that tmax = tmin + 20C */ return sprintf (buf,"%d\n" ,1000 * (20 + data->pwm_tmin[attr->index])); }
@@ -834,6 +904,10 @@ static ssize_t pwm_tmin_show(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" ,1000 * data->pwm_tmin[attr->index]); }
@@ -866,6 +940,10 @@ static ssize_t pwm_auto_show(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); + +if (IS_ERR (data)) +return PTR_ERR (data); +return sprintf (buf,"%d\n" ,1 + data->pwm_automatic[attr->index]); }
@@ -911,8 +989,12 @@ static ssize_t pwm_auto_temp_show(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); -u8 ctrl = data->pwm_auto_temp[attr->index]; +u8 ctrl; + +if (IS_ERR (data)) +return PTR_ERR (data); + ctrl = data->pwm_auto_temp[attr->index];if (ctrl)return sprintf (buf,"%d\n" ,1 << (ctrl -1 ));else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 222/389 hwmon: (adt7470) Fix some style issues
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Packham <[email protected]>
[ Upstream commit 23bd022aa6182367e1add7b4d05777cdba283756 ]
In preparation for the changes that follow fix up some existing style issues.
Specifically:
- add blank line between variable declaration and code
- use strscpy instead of strlcpy
- remove unnecessary braces
Stable-dep-of: 92413f439d1e ("hwmon: (adt7470) Fix PWM auto temp state array and bounds check")
--- drivers/hwmon/adt7470.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/hwmon/adt7470.c +3 -3
@@ -175,6 +175,7 @@ struct adt7470_data {static inline int adt7470_read_word_data (struct i2c_client *client,u8 reg) {u16 foo; + foo =i2c_smbus_read_byte_data (client, reg); foo |= ((u16 )i2c_smbus_read_byte_data (client, reg +1 ) <<8 );return foo;
@@ -1282,7 +1283,7 @@ static int adt7470_detect(struct i2c_client *client,if (revision !=ADT7470_REVISION )return -ENODEV ; -strlcpy (info->type,"adt7470" ,I2C_NAME_SIZE ); +strscpy (info->type,"adt7470" ,I2C_NAME_SIZE );return 0 ; }
@@ -1331,9 +1332,8 @@ static int adt7470_probe(struct i2c_client *client) data->auto_update =kthread_run (adt7470_update_thread, client,"%s" ,dev_name (hwmon_dev)); -if (IS_ERR (data->auto_update)) { +if (IS_ERR (data->auto_update))return PTR_ERR (data->auto_update); - }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 223/389 hwmon: (adt7470) Convert to use regmap
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Packham <[email protected]>
[ Upstream commit ef67959c42539bfece4d7c4335c07656703bb027 ]
Convert the adt7470 to using regmap which allows better error handling.
Stable-dep-of: 92413f439d1e ("hwmon: (adt7470) Fix PWM auto temp state array and bounds check")
--- drivers/hwmon/adt7470.c | 414 +++++++++++++++++++++++----------------- 1 file changed, 241 insertions(+), 173 deletions(-)
drivers/hwmon/adt7470.c +241 -173
@@ -18,6 +18,7 @@#include <linux/delay.h> #include <linux/log2.h> #include <linux/kthread.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <linux/util_macros.h> #include <linux/sched.h>
@@ -36,7 +37,10 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };#define ADT7470_REG_PWM_MAX_BASE_ADDR 0x38#define ADT7470_REG_PWM_MAX_MAX_ADDR 0x3B#define ADT7470_REG_CFG 0x40 +#define ADT7470_STRT_MASK 0x01 +#define ADT7470_TEST_MASK 0x02#define ADT7470_FSPD_MASK 0x04 +#define ADT7470_T05_STB_MASK 0x80#define ADT7470_REG_ALARM1 0x41#define ADT7470_R1T_ALARM 0x01#define ADT7470_R2T_ALARM 0x02
@@ -138,7 +142,7 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };#define ADT7470_FREQ_SHIFT 4struct adt7470_data { -struct i2c_client *client; +struct regmap *regmap;struct mutex lock;char sensors_valid;char limits_valid;
@@ -172,52 +176,76 @@ struct adt7470_data {* 16-bit registers on the ADT7470 are low-byte first. The data sheet says * that the low byte must be read before the high byte. */ -static inline int adt7470_read_word_data (struct i2c_client *client,u8 reg) +static inline int adt7470_read_word_data (struct adt7470_data *data,unsigned int reg, +unsigned int *val) { -u16 foo; +u8 regval[2 ]; +int err; + + err =regmap_bulk_read (data->regmap, reg, ®val,2 ); +if (err <0 ) +return err; + + *val = regval[0 ] | (regval[1 ] <<8 ); - foo =i2c_smbus_read_byte_data (client, reg); - foo |= ((u16 )i2c_smbus_read_byte_data (client, reg +1 ) <<8 ); -return foo; +return 0 ; } -static inline int adt7470_write_word_data (struct i2c_client *client,u8 reg, -u16 value) +static inline int adt7470_write_word_data (struct adt7470_data *data,unsigned int reg, +unsigned int val) { -return i2c_smbus_write_byte_data (client, reg, value &0xFF ) - ||i2c_smbus_write_byte_data (client, reg +1 , value >>8 ); +u8 regval[2 ]; + + regval[0 ] = val &0xFF ; + regval[1 ] = val >>8 ; + +return regmap_bulk_write (data->regmap, reg, ®val,2 ); }/* Probe for temperature sensors. Assumes lock is held */ -static int adt7470_read_temperatures (struct i2c_client *client, -struct adt7470_data *data) +static int adt7470_read_temperatures (struct adt7470_data *data) {unsigned long res; +unsigned int pwm_cfg[2 ]; +int err;int i; -u8 cfg, pwm[4 ], pwm_cfg[2 ]; +u8 pwm[ADT7470_FAN_COUNT ];/* save pwm[1-4] config register */ - pwm_cfg[0 ] =i2c_smbus_read_byte_data (client,ADT7470_REG_PWM_CFG (0 )); - pwm_cfg[1 ] =i2c_smbus_read_byte_data (client,ADT7470_REG_PWM_CFG (2 )); + err =regmap_read (data->regmap,ADT7470_REG_PWM_CFG (0 ), &pwm_cfg[0 ]); +if (err <0 ) +return err; + err =regmap_read (data->regmap,ADT7470_REG_PWM_CFG (2 ), &pwm_cfg[1 ]); +if (err <0 ) +return err;/* set manual pwm to whatever it is set to now */ -for (i =0 ; i <ADT7470_FAN_COUNT ; i++) - pwm[i] =i2c_smbus_read_byte_data (client,ADT7470_REG_PWM (i)); + err =regmap_bulk_read (data->regmap,ADT7470_REG_PWM (0 ), &pwm[0 ], +ADT7470_PWM_COUNT ); +if (err <0 ) +return err;/* put pwm in manual mode */ -i2c_smbus_write_byte_data (client,ADT7470_REG_PWM_CFG (0 ), - pwm_cfg[0 ] & ~(ADT7470_PWM_AUTO_MASK )); -i2c_smbus_write_byte_data (client,ADT7470_REG_PWM_CFG (2 ), - pwm_cfg[1 ] & ~(ADT7470_PWM_AUTO_MASK )); + err =regmap_update_bits (data->regmap,ADT7470_REG_PWM_CFG (0 ), +ADT7470_PWM_AUTO_MASK ,0 ); +if (err <0 ) +return err; + err =regmap_update_bits (data->regmap,ADT7470_REG_PWM_CFG (2 ), +ADT7470_PWM_AUTO_MASK ,0 ); +if (err <0 ) +return err;/* write pwm control to whatever it was */ -for (i =0 ; i <ADT7470_FAN_COUNT ; i++) -i2c_smbus_write_byte_data (client,ADT7470_REG_PWM (i), pwm[i]); + err =regmap_bulk_write (data->regmap,ADT7470_REG_PWM (0 ), &pwm[0 ], +ADT7470_PWM_COUNT ); +if (err <0 ) +return err;/* start reading temperature sensors */ - cfg =i2c_smbus_read_byte_data (client,ADT7470_REG_CFG ); - cfg |=0x80 ; -i2c_smbus_write_byte_data (client,ADT7470_REG_CFG , cfg); + err =regmap_update_bits (data->regmap,ADT7470_REG_CFG , +ADT7470_T05_STB_MASK ,ADT7470_T05_STB_MASK ); +if (err <0 ) +return err;/* Delay is 200ms * number of temp sensors. */ res = msleep_interruptible((data->num_temp_sensors >= 0 ?
@@ -225,26 +253,31 @@ static int adt7470_read_temperatures(struct i2c_client *client, TEMP_COLLECTION_TIME));/* done reading temperature sensors */ - cfg =i2c_smbus_read_byte_data (client,ADT7470_REG_CFG ); - cfg &= ~0x80 ; -i2c_smbus_write_byte_data (client,ADT7470_REG_CFG , cfg); + err =regmap_update_bits (data->regmap,ADT7470_REG_CFG , +ADT7470_T05_STB_MASK ,0 ); +if (err <0 ) +return err;/* restore pwm[1-4] config registers */ -i2c_smbus_write_byte_data (client,ADT7470_REG_PWM_CFG (0 ), pwm_cfg[0 ]); -i2c_smbus_write_byte_data (client,ADT7470_REG_PWM_CFG (2 ), pwm_cfg[1 ]); - -if (res) { -pr_err ("ha ha, interrupted\n" ); + err =regmap_write (data->regmap,ADT7470_REG_PWM_CFG (0 ), pwm_cfg[0 ]); +if (err <0 ) +return err; + err =regmap_write (data->regmap,ADT7470_REG_PWM_CFG (2 ), pwm_cfg[1 ]); +if (err <0 ) +return err; + +if (res)return -EAGAIN ; - }/* Only count fans if we have to */ if (data->num_temp_sensors >=0 )return 0 ; + err =regmap_bulk_read (data->regmap,ADT7470_TEMP_REG (0 ), &data->temp[0 ], +ADT7470_TEMP_COUNT ); +if (err <0 ) +return err;for (i =0 ; i <ADT7470_TEMP_COUNT ; i++) { - data->temp[i] =i2c_smbus_read_byte_data (client, -ADT7470_TEMP_REG (i));if (data->temp[i]) data->num_temp_sensors = i +1 ; }
@@ -259,7 +292,7 @@ static int adt7470_update_thread(void *p)while (!kthread_should_stop ()) {mutex_lock (&data->lock); -adt7470_read_temperatures (client, data); +adt7470_read_temperatures (data);mutex_unlock (&data->lock);if (kthread_should_stop ())
@@ -273,89 +306,116 @@ static int adt7470_update_thread(void *p)static int adt7470_update_sensors (struct adt7470_data *data) { -struct i2c_client *client = data->client; -u8 cfg; +unsigned int val; +int err;int i;if (!data->temperatures_probed) -adt7470_read_temperatures (client, data); + err =adt7470_read_temperatures (data);else -for (i =0 ; i <ADT7470_TEMP_COUNT ; i++) - data->temp[i] =i2c_smbus_read_byte_data (client, -ADT7470_TEMP_REG (i)); + err =regmap_bulk_read (data->regmap,ADT7470_TEMP_REG (0 ), &data->temp[0 ], +ADT7470_TEMP_COUNT ); +if (err <0 ) +return err; -for (i =0 ; i <ADT7470_FAN_COUNT ; i++) - data->fan[i] =adt7470_read_word_data (client, -ADT7470_REG_FAN (i)); +for (i =0 ; i <ADT7470_FAN_COUNT ; i++) { + err =adt7470_read_word_data (data,ADT7470_REG_FAN (i), &val); +if (err <0 ) +return err; + data->fan[i] = val; + } -for (i =0 ; i <ADT7470_PWM_COUNT ; i++) { -int reg; -int reg_mask; + err =regmap_bulk_read (data->regmap,ADT7470_REG_PWM (0 ), &data->pwm[0 ],ADT7470_PWM_COUNT ); +if (err <0 ) +return err; - data->pwm[i] =i2c_smbus_read_byte_data (client, -ADT7470_REG_PWM (i)); +for (i =0 ; i <ADT7470_PWM_COUNT ; i++) { +unsigned int mask;if (i %2 ) - reg_mask =ADT7470_PWM2_AUTO_MASK ; + mask =ADT7470_PWM2_AUTO_MASK ;else - reg_mask =ADT7470_PWM1_AUTO_MASK ; + mask =ADT7470_PWM1_AUTO_MASK ; - reg =ADT7470_REG_PWM_CFG (i); -if (i2c_smbus_read_byte_data (client, reg) & reg_mask) - data->pwm_automatic[i] =1 ; -else - data->pwm_automatic[i] =0 ; + err =regmap_read (data->regmap,ADT7470_REG_PWM_CFG (i), &val); +if (err <0 ) +return err; + data->pwm_automatic[i] = !!(val & mask); - reg =ADT7470_REG_PWM_AUTO_TEMP (i); - cfg =i2c_smbus_read_byte_data (client, reg); + err =regmap_read (data->regmap,ADT7470_REG_PWM_AUTO_TEMP (i), &val); +if (err <0 ) +return err;if (!(i %2 )) - data->pwm_auto_temp[i] = cfg >>4 ; + data->pwm_auto_temp[i] = val >>4 ;else - data->pwm_auto_temp[i] = cfg &0xF ; + data->pwm_auto_temp[i] = val &0xF ; } -if (i2c_smbus_read_byte_data (client,ADT7470_REG_CFG ) & -ADT7470_FSPD_MASK ) - data->force_pwm_max =1 ; -else - data->force_pwm_max =0 ; + err =regmap_read (data->regmap,ADT7470_REG_CFG , &val); +if (err <0 ) +return err; + data->force_pwm_max = !!(val &ADT7470_FSPD_MASK ); + + err =regmap_read (data->regmap,ADT7470_REG_ALARM1 , &val); +if (err <0 ) +return err; + data->alarm = val; +if (data->alarm &ADT7470_OOL_ALARM ) { + err =regmap_read (data->regmap,ADT7470_REG_ALARM2 , &val); +if (err <0 ) +return err; + data->alarm |=ALARM2 (val); + } - data->alarm =i2c_smbus_read_byte_data (client,ADT7470_REG_ALARM1 ); -if (data->alarm &ADT7470_OOL_ALARM ) - data->alarm |=ALARM2 (i2c_smbus_read_byte_data (client, -ADT7470_REG_ALARM2 )); - data->alarms_mask =adt7470_read_word_data (client, -ADT7470_REG_ALARM1_MASK ); + err =adt7470_read_word_data (data,ADT7470_REG_ALARM1_MASK , &val); +if (err <0 ) +return err; + data->alarms_mask = val;return 0 ; }static int adt7470_update_limits (struct adt7470_data *data) { -struct i2c_client *client = data->client; +unsigned int val; +int err;int i;for (i =0 ; i <ADT7470_TEMP_COUNT ; i++) { - data->temp_min[i] =i2c_smbus_read_byte_data (client, -ADT7470_TEMP_MIN_REG (i)); - data->temp_max[i] =i2c_smbus_read_byte_data (client, -ADT7470_TEMP_MAX_REG (i)); + err =regmap_read (data->regmap,ADT7470_TEMP_MIN_REG (i), &val); +if (err <0 ) +return err; + data->temp_min[i] = (s8 )val; + err =regmap_read (data->regmap,ADT7470_TEMP_MAX_REG (i), &val); +if (err <0 ) +return err; + data->temp_max[i] = (s8 )val; }for (i =0 ; i <ADT7470_FAN_COUNT ; i++) { - data->fan_min[i] =adt7470_read_word_data (client, -ADT7470_REG_FAN_MIN (i)); - data->fan_max[i] =adt7470_read_word_data (client, -ADT7470_REG_FAN_MAX (i)); + err =adt7470_read_word_data (data,ADT7470_REG_FAN_MIN (i), &val); +if (err <0 ) +return err; + data->fan_min[i] = val; + err =adt7470_read_word_data (data,ADT7470_REG_FAN_MAX (i), &val); +if (err <0 ) +return err; + data->fan_max[i] = val; }for (i =0 ; i <ADT7470_PWM_COUNT ; i++) { - data->pwm_max[i] =i2c_smbus_read_byte_data (client, -ADT7470_REG_PWM_MAX (i)); - data->pwm_min[i] =i2c_smbus_read_byte_data (client, -ADT7470_REG_PWM_MIN (i)); - data->pwm_tmin[i] =i2c_smbus_read_byte_data (client, -ADT7470_REG_PWM_TMIN (i)); + err =regmap_read (data->regmap,ADT7470_REG_PWM_MAX (i), &val); +if (err <0 ) +return err; + data->pwm_max[i] = val; + err =regmap_read (data->regmap,ADT7470_REG_PWM_MIN (i), &val); +if (err <0 ) +return err; + data->pwm_min[i] = val; + err =regmap_read (data->regmap,ADT7470_REG_PWM_TMIN (i), &val); +if (err <0 ) +return err; + data->pwm_tmin[i] = (s8 )val; }return 0 ;
@@ -491,8 +551,8 @@ static ssize_t temp_min_store(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long temp; +int err;if (kstrtol (buf,10 , &temp))return -EINVAL ;
@@ -502,11 +562,11 @@ static ssize_t temp_min_store(struct device *dev,mutex_lock (&data->lock); data->temp_min[attr->index] = temp; -i2c_smbus_write_byte_data (client,ADT7470_TEMP_MIN_REG (attr->index), + err =regmap_write (data->regmap,ADT7470_TEMP_MIN_REG (attr->index), temp);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t temp_max_show(struct device *dev,
@@ -527,8 +587,8 @@ static ssize_t temp_max_store(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long temp; +int err;if (kstrtol (buf,10 , &temp))return -EINVAL ;
@@ -538,11 +598,10 @@ static ssize_t temp_max_store(struct device *dev,mutex_lock (&data->lock); data->temp_max[attr->index] = temp; -i2c_smbus_write_byte_data (client,ADT7470_TEMP_MAX_REG (attr->index), - temp); + err =regmap_write (data->regmap,ADT7470_TEMP_MAX_REG (attr->index), temp);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
@@ -575,6 +634,7 @@ static ssize_t alarm_mask_store(struct device *dev, {struct adt7470_data *data =dev_get_drvdata (dev);long mask; +int err;if (kstrtoul (buf,0 , &mask))return -EINVAL ;
@@ -584,10 +644,10 @@ static ssize_t alarm_mask_store(struct device *dev,mutex_lock (&data->lock); data->alarms_mask = mask; -adt7470_write_word_data (data->client,ADT7470_REG_ALARM1_MASK , mask); + err =adt7470_write_word_data (data,ADT7470_REG_ALARM1_MASK , mask);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t fan_max_show(struct device *dev,
@@ -612,8 +672,8 @@ static ssize_t fan_max_store(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long temp; +int err;if (kstrtol (buf,10 , &temp) || !temp)return -EINVAL ;
@@ -623,10 +683,10 @@ static ssize_t fan_max_store(struct device *dev,mutex_lock (&data->lock); data->fan_max[attr->index] = temp; -adt7470_write_word_data (client,ADT7470_REG_FAN_MAX (attr->index), temp); + err =adt7470_write_word_data (data,ADT7470_REG_FAN_MAX (attr->index), temp);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t fan_min_show(struct device *dev,
@@ -651,8 +711,8 @@ static ssize_t fan_min_store(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long temp; +int err;if (kstrtol (buf,10 , &temp) || !temp)return -EINVAL ;
@@ -662,10 +722,10 @@ static ssize_t fan_min_store(struct device *dev,mutex_lock (&data->lock); data->fan_min[attr->index] = temp; -adt7470_write_word_data (client,ADT7470_REG_FAN_MIN (attr->index), temp); + err =adt7470_write_word_data (data,ADT7470_REG_FAN_MIN (attr->index), temp);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
@@ -700,24 +760,20 @@ static ssize_t force_pwm_max_store(struct device *dev, const char *buf, size_t count) {struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long temp; -u8 reg; +int err;if (kstrtol (buf,10 , &temp))return -EINVAL ;mutex_lock (&data->lock); data->force_pwm_max = temp; - reg =i2c_smbus_read_byte_data (client,ADT7470_REG_CFG ); -if (temp) - reg |=ADT7470_FSPD_MASK ; -else - reg &= ~ADT7470_FSPD_MASK ; -i2c_smbus_write_byte_data (client,ADT7470_REG_CFG , reg); + err =regmap_update_bits (data->regmap,ADT7470_REG_CFG , +ADT7470_FSPD_MASK , + temp ?ADT7470_FSPD_MASK :0 );mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t pwm_show(struct device *dev, struct device_attribute *devattr,
@@ -737,8 +793,8 @@ static ssize_t pwm_store(struct device *dev, struct device_attribute *devattr, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long temp; +int err;if (kstrtol (buf,10 , &temp))return -EINVAL ;
@@ -747,10 +803,10 @@ static ssize_t pwm_store(struct device *dev, struct device_attribute *devattr,mutex_lock (&data->lock); data->pwm[attr->index] = temp; -i2c_smbus_write_byte_data (client,ADT7470_REG_PWM (attr->index), temp); + err =regmap_write (data->regmap,ADT7470_REG_PWM (attr->index), temp);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; }/* These are the valid PWM frequencies to the nearest Hz */
@@ -762,13 +818,20 @@ static ssize_t pwm1_freq_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct adt7470_data *data = adt7470_update_device(dev); -unsigned char cfg_reg_1; -unsigned char cfg_reg_2; +unsigned int cfg_reg_1, cfg_reg_2;int index; +int err; + +if (IS_ERR (data)) +return PTR_ERR (data);mutex_lock (&data->lock); - cfg_reg_1 =i2c_smbus_read_byte_data (data->client,ADT7470_REG_CFG ); - cfg_reg_2 =i2c_smbus_read_byte_data (data->client,ADT7470_REG_CFG_2 ); + err =regmap_read (data->regmap,ADT7470_REG_CFG , &cfg_reg_1); +if (err <0 ) + goto out; + err =regmap_read (data->regmap,ADT7470_REG_CFG_2 , &cfg_reg_2); +if (err <0 ) + goto out;mutex_unlock (&data->lock); index = (cfg_reg_2 &ADT7470_FREQ_MASK ) >>ADT7470_FREQ_SHIFT ;
@@ -778,6 +841,10 @@ static ssize_t pwm1_freq_show(struct device *dev, index =ARRAY_SIZE (adt7470_freq_map) -1 ;return scnprintf (buf,PAGE_SIZE ,"%d\n" , adt7470_freq_map[index]); + +out: +mutex_unlock (&data->lock); +return err; } static ssize_t pwm1_freq_store(struct device *dev,
@@ -785,11 +852,10 @@ static ssize_t pwm1_freq_store(struct device *dev, const char *buf, size_t count) {struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long freq;int index;int low_freq =ADT7470_CFG_LF ; -unsigned char val; +int err;if (kstrtol (buf,10 , &freq))return -EINVAL ;
@@ -805,16 +871,19 @@ static ssize_t pwm1_freq_store(struct device *dev,mutex_lock (&data->lock);/* Configuration Register 1 */ - val =i2c_smbus_read_byte_data (client,ADT7470_REG_CFG ); -i2c_smbus_write_byte_data (client,ADT7470_REG_CFG , - (val & ~ADT7470_CFG_LF ) | low_freq); + err =regmap_update_bits (data->regmap,ADT7470_REG_CFG , +ADT7470_CFG_LF , low_freq); +if (err <0 ) + goto out; +/* Configuration Register 2 */ - val =i2c_smbus_read_byte_data (client,ADT7470_REG_CFG_2 ); -i2c_smbus_write_byte_data (client,ADT7470_REG_CFG_2 , - (val & ~ADT7470_FREQ_MASK ) | (index <<ADT7470_FREQ_SHIFT )); + err =regmap_update_bits (data->regmap,ADT7470_REG_CFG_2 , +ADT7470_FREQ_MASK , + index <<ADT7470_FREQ_SHIFT ); +out:mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t pwm_max_show(struct device *dev,
@@ -835,8 +904,8 @@ static ssize_t pwm_max_store(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long temp; +int err;if (kstrtol (buf,10 , &temp))return -EINVAL ;
@@ -845,11 +914,11 @@ static ssize_t pwm_max_store(struct device *dev,mutex_lock (&data->lock); data->pwm_max[attr->index] = temp; -i2c_smbus_write_byte_data (client,ADT7470_REG_PWM_MAX (attr->index), - temp); + err =regmap_write (data->regmap,ADT7470_REG_PWM_MAX (attr->index), + temp);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t pwm_min_show(struct device *dev,
@@ -870,8 +939,8 @@ static ssize_t pwm_min_store(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long temp; +int err;if (kstrtol (buf,10 , &temp))return -EINVAL ;
@@ -880,11 +949,11 @@ static ssize_t pwm_min_store(struct device *dev,mutex_lock (&data->lock); data->pwm_min[attr->index] = temp; -i2c_smbus_write_byte_data (client,ADT7470_REG_PWM_MIN (attr->index), - temp); + err =regmap_write (data->regmap,ADT7470_REG_PWM_MIN (attr->index), + temp);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t pwm_tmax_show(struct device *dev,
@@ -918,8 +987,8 @@ static ssize_t pwm_tmin_store(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;long temp; +int err;if (kstrtol (buf,10 , &temp))return -EINVAL ;
@@ -929,11 +998,11 @@ static ssize_t pwm_tmin_store(struct device *dev,mutex_lock (&data->lock); data->pwm_tmin[attr->index] = temp; -i2c_smbus_write_byte_data (client,ADT7470_REG_PWM_TMIN (attr->index), - temp); + err =regmap_write (data->regmap,ADT7470_REG_PWM_TMIN (attr->index), + temp);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t pwm_auto_show(struct device *dev,
@@ -954,11 +1023,9 @@ static ssize_t pwm_auto_store(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client; -int pwm_auto_reg =ADT7470_REG_PWM_CFG (attr->index);int pwm_auto_reg_mask;long temp; -u8 reg; +int err;if (kstrtol (buf,10 , &temp))return -EINVAL ;
@@ -974,15 +1041,12 @@ static ssize_t pwm_auto_store(struct device *dev,mutex_lock (&data->lock); data->pwm_automatic[attr->index] = temp; - reg =i2c_smbus_read_byte_data (client, pwm_auto_reg); -if (temp) - reg |= pwm_auto_reg_mask; -else - reg &= ~pwm_auto_reg_mask; -i2c_smbus_write_byte_data (client, pwm_auto_reg, reg); + err =regmap_update_bits (data->regmap,ADT7470_REG_PWM_CFG (attr->index), + pwm_auto_reg_mask, + temp ? pwm_auto_reg_mask :0 );mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t pwm_auto_temp_show(struct device *dev,
@@ -1017,10 +1081,10 @@ static ssize_t pwm_auto_temp_store(struct device *dev, {struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =dev_get_drvdata (dev); -struct i2c_client *client = data->client;int pwm_auto_reg =ADT7470_REG_PWM_AUTO_TEMP (attr->index); +unsigned int mask, val;long temp; -u8 reg; +int err;if (kstrtol (buf,10 , &temp))return -EINVAL ;
@@ -1031,20 +1095,19 @@ static ssize_t pwm_auto_temp_store(struct device *dev,mutex_lock (&data->lock); data->pwm_automatic[attr->index] = temp; - reg =i2c_smbus_read_byte_data (client, pwm_auto_reg);if (!(attr->index %2 )) { - reg &=0xF ; - reg |= (temp <<4 ) &0xF0 ; + mask =0xF0 ; + val = (temp <<4 ) &0xF0 ; }else { - reg &=0xF0 ; - reg |= temp &0xF ; + mask =0x0F ; + val = temp &0x0F ; } -i2c_smbus_write_byte_data (client, pwm_auto_reg, reg); + err =regmap_update_bits (data->regmap, pwm_auto_reg, mask, val);mutex_unlock (&data->lock); -return count; +return err <0 ? err : count; } static ssize_t alarm_show(struct device *dev,
@@ -1053,6 +1116,9 @@ static ssize_t alarm_show(struct device *dev,struct sensor_device_attribute *attr =to_sensor_dev_attr (devattr);struct adt7470_data *data =adt7470_update_device (dev); +if (IS_ERR (data)) +return PTR_ERR (data); +if (data->alarm & attr->index)return sprintf (buf,"1\n" );else
@@ -1288,23 +1354,19 @@ static int adt7470_detect(struct i2c_client *client,return 0 ; } -static void adt7470_init_client (struct i2c_client *client) -{ -int reg =i2c_smbus_read_byte_data (client,ADT7470_REG_CFG ); - -if (reg <0 ) { -dev_err (&client->dev,"cannot read configuration register\n" ); - }else { -/* start monitoring (and do a self-test) */ -i2c_smbus_write_byte_data (client,ADT7470_REG_CFG , reg |3 ); - } -} +static const struct regmap_config adt7470_regmap_config = { + .reg_bits =8 , + .val_bits =8 , + .use_single_read = true, + .use_single_write = true, +};static int adt7470_probe (struct i2c_client *client) {struct device *dev = &client->dev;struct adt7470_data *data;struct device *hwmon_dev; +int err; data =devm_kzalloc (dev,sizeof (struct adt7470_data ),GFP_KERNEL );if (!data)
@@ -1312,15 +1374,21 @@ static int adt7470_probe(struct i2c_client *client) data->num_temp_sensors =-1 ; data->auto_update_interval =AUTO_UPDATE_INTERVAL ; + data->regmap =devm_regmap_init_i2c (client, &adt7470_regmap_config); +if (IS_ERR (data->regmap)) +return PTR_ERR (data->regmap);i2c_set_clientdata (client, data); - data->client = client;mutex_init (&data->lock);dev_info (&client->dev,"%s chip found\n" , client->name);/* Initialize the ADT7470 chip */ -adt7470_init_client (client); + err =regmap_update_bits (data->regmap,ADT7470_REG_CFG , +ADT7470_STRT_MASK |ADT7470_TEST_MASK , +ADT7470_STRT_MASK |ADT7470_TEST_MASK ); +if (err <0 ) +return err;/* Register sysfs hooks */ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 224/389 hwmon: (adt7470) Fix PWM auto temp state array and bounds check
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Angelo Daros de Luca <[email protected]>
[ Upstream commit 92413f439d1ec5e55b73ede8d66a7b971cbd1ced ]
In pwm_auto_temp_store(), the parsed user input was missing bounds checks, allowing values > 0xF to overflow into the adjacent channel's bits. Furthermore, the value was being incorrectly written to the pwm_automatic state array instead of pwm_auto_temp.
Fix this by rejecting values > 0xF with -EINVAL, and assigning the value to the correct array only after a successful I2C write.
--- drivers/hwmon/adt7470.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/hwmon/adt7470.c +6 -1
@@ -1093,8 +1093,10 @@ static ssize_t pwm_auto_temp_store(struct device *dev,if (temp <0 )return temp; +if (temp >0xF ) +return -EINVAL ; +mutex_lock (&data->lock); - data->pwm_automatic[attr->index] = temp;if (!(attr->index %2 )) { mask =0xF0 ;
@@ -1105,6 +1107,9 @@ static ssize_t pwm_auto_temp_store(struct device *dev, } err =regmap_update_bits (data->regmap, pwm_auto_reg, mask, val); +if (!err) + data->pwm_auto_temp[attr->index] = temp; +mutex_unlock (&data->lock);return err <0 ? err : count;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 225/389 powerpc/boot: Fix simpleboot CPU node lookup check
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit c824ab65685bb119c6c6a3a200b3428c72862d5a ]
fdt_node_offset_by_prop_value() returns a negative error code on failure - fix the check accordingly.
--- arch/powerpc/boot/simpleboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/boot/simpleboot.c +1 -1
@@ -68,7 +68,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,/* finally, setup the timebase */ node =fdt_node_offset_by_prop_value (_dtb_start,-1 ,"device_type" ,"cpu" ,sizeof ("cpu" )); -if (!node) +if (node <0 )fatal ("Cannot find cpu node\n" ); timebase =fdt_getprop (_dtb_start, node,"timebase-frequency" , &size);if (timebase && (size ==4 ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 226/389 powerpc/boot: Fix treeboot-currituck CPU node lookup check
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit 43863f6575d2211e8c5157fefb83ad0ad046aab4 ]
fdt_node_offset_by_prop_value() returns a negative error code on failure - fix the check accordingly.
--- arch/powerpc/boot/treeboot-currituck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/boot/treeboot-currituck.c +1 -1
@@ -102,7 +102,7 @@ void platform_init(void) node =fdt_node_offset_by_prop_value (_dtb_start,-1 ,"device_type" ,"cpu" ,sizeof ("cpu" )); -if (!node) +if (node <0 )fatal ("Cannot find cpu node\n" ); timebase =fdt_getprop (_dtb_start, node,"timebase-frequency" , &size);if (timebase && (size ==4 ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 227/389 powerpc/boot: Fix treeboot-akebono CPU node lookup check
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit b24fc8278b70a9d27ec801a427ab4de9b769d69a ]
fdt_node_offset_by_prop_value() returns a negative error code on failure - fix the check accordingly.
--- arch/powerpc/boot/treeboot-akebono.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/boot/treeboot-akebono.c +1 -1
@@ -146,7 +146,7 @@ void platform_init(char *userdata) node =fdt_node_offset_by_prop_value (_dtb_start,-1 ,"device_type" ,"cpu" ,sizeof ("cpu" )); -if (!node) +if (node <0 )fatal ("Cannot find cpu node\n" ); timebase =fdt_getprop (_dtb_start, node,"timebase-frequency" , &size);if (timebase && (size ==4 ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 228/389 hwmon: (pmbus) Fix return value from pmbus_update_byte_data()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit a19038a200f18d9e74ac30081797917d0886e16b ]
pmbus_update_byte_data() is supposed to return a negative error code or 0. However, if no change is made to the register, it actually returns the register value. This can result in problems if the calling code explicitly expects to see an error code or 0.
Fix it to return 0 on success or the error code as expected.
--- drivers/hwmon/pmbus/pmbus_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/pmbus/pmbus_core.c +1 -1
@@ -408,7 +408,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,if (tmp != rv) rv =_pmbus_write_byte_data (client, page, reg, tmp); -return rv; +return rv <0 ? rv :0 ; }EXPORT_SYMBOL_GPL (pmbus_update_byte_data);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 229/389 Bluetooth: L2CAP: fix UAF in l2cap_le_connect_rsp
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiale Yao <[email protected]>
[ Upstream commit c4740e7f23ff9a8210198d8b4703259e21b9f69d ]
l2cap_le_connect_rsp() obtains a channel via __l2cap_get_chan_by_ident() but neither holds a reference nor uses l2cap_chan_hold_unless_zero() before locking and operating on it. A concurrent l2cap_chan_del() triggered by a remote disconnect can free the channel between the lookup and l2cap_chan_lock(), causing a use-after-free.
The BR/EDR counterpart l2cap_connect_rsp() and the sibling handler l2cap_le_command_rej() already use l2cap_chan_hold_unless_zero() to safely hold a reference, but l2cap_le_connect_rsp() was left unprotected.
Fix by adding l2cap_chan_hold_unless_zero() after the ident lookup and l2cap_chan_put() on the exit path, consistent with other L2CAP response handlers.
--- net/bluetooth/l2cap_core.c | 5 +++++ 1 file changed, 5 insertions(+)
net/bluetooth/l2cap_core.c +5 -0
@@ -5744,6 +5744,10 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn, goto unlock; } + chan =l2cap_chan_hold_unless_zero (chan); +if (!chan) +return -EBADSLT ; + err =0 ;l2cap_chan_lock (chan);
@@ -5789,6 +5793,7 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn, }l2cap_chan_unlock (chan); +l2cap_chan_put (chan); unlock:mutex_unlock (&conn->chan_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 230/389 net: phylink: put link_gpio if phylink_create fails
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Marangi <[email protected]>
[ Upstream commit 0fe1e3e8f3380d7862296a73b528d164e96c76b8 ]
In phylink_create() if phylink_register_sfp() returns an error, link_gpio obtained by phylink_parse_fixedlink() is never released. While this is a very unlikely scenario, it's worth to fix/handle this.
This was present from the very first implementation of phylink but got relevant only with the introduction of ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network devices and sfp cages") where additional function were added after phylink_parse_fixedlink() making the release of link_gpio needed if such additional function errored out.
While at it, restructure the exit condition of phylink_create() with the goto pattern to reduce code duplication on handling error conditions.
--- drivers/net/phy/phylink.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
drivers/net/phy/phylink.c +15 -14
@@ -842,8 +842,8 @@ struct phylink *phylink_create(struct phylink_config *config, }else if (config->type ==PHYLINK_DEV ) { pl->dev = config->dev; }else { -kfree (pl); -return ERR_PTR (-EINVAL ); + ret = -EINVAL ; + goto free_pl; } pl->phy_state.interface = iface;
@@ -866,28 +866,29 @@ struct phylink *phylink_create(struct phylink_config *config,phylink_validate (pl, pl->supported, &pl->link_config); ret =phylink_parse_mode (pl, fwnode); -if (ret <0 ) { -kfree (pl); -return ERR_PTR (ret); - } +if (ret <0 ) + goto free_pl;if (pl->cfg_link_an_mode ==MLO_AN_FIXED ) { ret =phylink_parse_fixedlink (pl, fwnode); -if (ret <0 ) { -kfree (pl); -return ERR_PTR (ret); - } +if (ret <0 ) + goto release_link_gpio; } pl->cur_link_an_mode = pl->cfg_link_an_mode; ret =phylink_register_sfp (pl, fwnode); -if (ret <0 ) { -kfree (pl); -return ERR_PTR (ret); - } +if (ret <0 ) + goto release_link_gpio;return pl; + +release_link_gpio: +if (pl->link_gpio) +gpiod_put (pl->link_gpio); +free_pl: +kfree (pl); +return ERR_PTR (ret); }EXPORT_SYMBOL_GPL (phylink_create);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 231/389 scsi: zfcp: Fix memory leak during adapter release by destroying gid_pn_req
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Block <[email protected]>
[ Upstream commit b601fa590e667bd9643feed8c869b6b3e418480d ]
When releasing an adapter we don't free the mempool 'gid_pn_req' that is allocated during the enqueue. This leaks memory:
unreferenced object 0xd8d29297de700 (size 256):
comm "(udev-worker)", pid 2105, jiffies 4294945794
hex dump (first 32 bytes):
00 00 00 00 de ad 4e ad ff ff ff ff 00 00 00 00 ......N.........
ff ff ff ff ff ff ff ff 00 0d c4 5f 67 9d 99 e0 ..........._g...
backtrace (crc 4a5b5da2):
[<000dc45f64da418c>] kmemleak_alloc+0x6c/0xa0
[<000dc45f62b430aa>] __kmalloc_cache_node_noprof+0x36a/0x4d0
[<000dc45f629a535a>] mempool_create_node_noprof+0xaa/0x150
[<000dc45ee2c065e6>] zfcp_allocate_low_mem_buffers+0x96/0x370 [zfcp]
[<000dc45ee2c070f8>] zfcp_adapter_enqueue+0x598/0xd40 [zfcp]
[<000dc45ee2c08eb0>] zfcp_ccw_set_online+0x160/0x210 [zfcp]
[<000dc45f643d4762>] ccw_device_set_online+0x232/0xd80
[<000dc45f643d53d4>] online_store_recog_and_online+0x124/0x390
[<000dc45f643d8238>] online_store+0x298/0x5b0
[<000dc45f62eb0a04>] kernfs_fop_write_iter+0x2c4/0x480
[<000dc45f62c81150>] new_sync_write+0x370/0x4b0
[<000dc45f62c87abe>] vfs_write+0x43e/0x5b0
[<000dc45f62c87ff4>] ksys_write+0x114/0x1f0
[<000dc45f621c4a16>] do_syscall+0x2f6/0x430
[<000dc45f64d9d5d8>] __do_syscall+0xc8/0x1c0
[<000dc45f64dc2224>] system_call+0x74/0xa0Fix this by destroying the mempool during the adapter's release.
--- drivers/s390/scsi/zfcp_aux.c | 1 + 1 file changed, 1 insertion(+)
drivers/s390/scsi/zfcp_aux.c +1 -0
@@ -254,6 +254,7 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)static void zfcp_free_low_mem_buffers (struct zfcp_adapter *adapter) {mempool_destroy (adapter->pool.erp_req); +mempool_destroy (adapter->pool.gid_pn_req);mempool_destroy (adapter->pool.scsi_req);mempool_destroy (adapter->pool.scsi_abort);mempool_destroy (adapter->pool.qtcb_pool);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 232/389 net: sxgbe: free TX rings on RX allocation failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
[ Upstream commit c870f7e2890b9f78ac84515a9809cc5c183c975e ]
When RX descriptor ring allocation fails, init_dma_desc_rings() only frees the partially allocated RX rings and returns. The TX rings that were allocated earlier in the same function are leaked.
Rearrange error labels to clean up TX rings upon RX failures.
--- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +4 -5
@@ -599,14 +599,13 @@ static int init_dma_desc_rings(struct net_device *netd)return 0 ; -txalloc_err: -while (queue_num--) -free_tx_ring (priv->device, priv->txq[queue_num], tx_rsize); -return ret; - rxalloc_err:while (queue_num--)free_rx_ring (priv->device, priv->rxq[queue_num], rx_rsize); + queue_num =SXGBE_TX_QUEUES ; +txalloc_err: +while (queue_num--) +free_tx_ring (priv->device, priv->txq[queue_num], tx_rsize);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 233/389 net: sxgbe: check descriptor ring allocation failures
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
[ Upstream commit 51b093a7ba27476e1f639455f005e8d2e75390e4 ]
sxgbe_open() ignores the return value of init_dma_desc_rings() and continues to program DMA with invalid ring addresses when allocation fails. Check the return value and disconnect the PHY on failure.
--- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +4 -1
@@ -1077,7 +1077,9 @@ static int sxgbe_open(struct net_device *dev) priv->dma_buf_sz =SXGBE_ALIGN (DMA_BUFFER_SIZE ); priv->tx_tc =TC_DEFAULT ; priv->rx_tc =TC_DEFAULT ; -init_dma_desc_rings (dev); + ret =init_dma_desc_rings (dev); +if (ret) + goto init_phy_error;/* DMA initialization and SW reset */ ret =sxgbe_init_dma_engine (priv);
@@ -1186,6 +1188,7 @@ static int sxgbe_open(struct net_device *dev) init_error:free_dma_desc_resources (priv); +init_phy_error:if (dev->phydev)phy_disconnect (dev->phydev); phy_error:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 234/389 can: isotp: check register_netdevice_notifier() error in module init
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Minhong He <[email protected]>
[ Upstream commit ef09a13c5afac41a3c4b5f22b8572820d9e7518c ]
Register the netdevice notifier before can_proto_register() and check the return value. If protocol registration fails, unregister the notifier before returning the error.
Align isotp_module_init() with the reordering already done for raw.c (commit c28b3bffe49e ("can: raw: process optimization in raw_init()")) and bcm.c (commit edd1a7e42f1d ("can: bcm: registration process optimization in bcm_module_init()")).
--- net/can/isotp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
net/can/isotp.c +9 -4
@@ -1827,13 +1827,18 @@ static __init int isotp_module_init(void)pr_info ("can: isotp protocol\n" ); + err =register_netdevice_notifier (&canisotp_notifier); +if (err) +return err; + err =can_proto_register (&isotp_can_proto); -if (err <0 ) +if (err <0 ) {pr_err ("can: registration of isotp protocol failed %pe\n" ,ERR_PTR (err)); -else -register_netdevice_notifier (&canisotp_notifier); +unregister_netdevice_notifier (&canisotp_notifier); +return err; + } -return err; +return 0 ; } static __exit void isotp_module_exit(void)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 235/389 tracing/mmiotrace: Reset dropped_count in mmio_reset_data()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit c786d2bdf1f3964deee192ad942dee2a741c1e2c ]
mmio_reset_data() is called during tracer initialization, reset, and start. While it resets overrun_detected and prev_overruns, it neglects to reset dropped_count. Consequently, dropped event counts from prior tracing sessions persist in dropped_count and corrupt overrun reports in subsequent runs.
Fix this by explicitly calling atomic_set(&dropped_count, 0) in mmio_reset_data().
--- kernel/trace/trace_mmiotrace.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/trace_mmiotrace.c +1 -0
@@ -31,6 +31,7 @@ static void mmio_reset_data(struct trace_array *tr) { overrun_detected = false; prev_overruns =0 ; +atomic_set (&dropped_count,0 );tracing_reset_online_cpus (&tr->array_buffer); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 236/389 octeontx2-pf: Set correct sequence for carrier off and tx queue stop
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suman Ghosh <[email protected]>
[ Upstream commit 16809472409d998afcda402e32b8229b389337c4 ]
During link down event, we were doing netif_tx_stop_all_queues() first and then netif_carrier_off(). This can cause a potential race since carrier is still on during down event. This patch reverse the calling order to fix the issue.
--- drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +1 -1
@@ -840,8 +840,8 @@ static void otx2_handle_link_event(struct otx2_nic *pf)netif_carrier_on (netdev);netif_tx_start_all_queues (netdev); }else { -netif_tx_stop_all_queues (netdev);netif_carrier_off (netdev); +netif_tx_stop_all_queues (netdev); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 237/389 qede: sync udp_tunnel ports outside qede_lock in the recovery path
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Denis V. Lunev <[email protected]>
[ Upstream commit 451c9075d6c53f2438d110addbeeeea6fac18567 ]
A TX timeout on a qede NIC that has VXLAN/GENEVE tunnel ports configured wedges the rtnetlink control plane of the whole machine:
NETDEV WATCHDOG: ens6f1 (qede): transmit queue 2 timed out 10226 ms [qede_tx_timeout:586(ens6f1)]TX timeout on queue 2! [qede_recovery_handler:2665(ens6f0)]Starting a recovery process
The recovery path deadlocks on the driver's own mutex:
qede_sp_task
rtnl_lock()
mutex_lock(&edev->qede_lock) <- taken
qede_recovery_handler
qede_load
udp_tunnel_nic_reset_ntf
__udp_tunnel_nic_device_sync
info->sync_table == qede_udp_tunnel_sync
mutex_lock(&edev->qede_lock) <- same task: deadlockThe mutex is not recursive, so the kworker blocks on itself with rtnl_lock held, and neither lock is ever released. Every task that calls rtnl_lock() afterwards (ip, ovs-vswitchd, lldpad, IPv6 addrconf, sshd) blocks forever while the node still answers ping. In a vmcore from an affected production node rtnl_mutex.owner decodes to the very kworker blocked at the innermost mutex_lock() above.
Re-sync the tunnel ports from qede_sp_task() after the internal lock is dropped, still under rtnl_lock as the udp_tunnel API requires. This mirrors qede_open(), which calls udp_tunnel_nic_reset_ntf() under rtnl without the internal lock.
qede_recovery_handler() now returns whether it has successfully reloaded an open device, and the caller re-syncs the ports only in that case. This keeps the old gating exactly: a device that was down or a failed recovery returns false, as those paths never reached the udp_tunnel_nic_reset_ntf() call before either.
This was the only user of the qede_lock()/qede_unlock() helpers, so remove them.
--- drivers/net/ethernet/qlogic/qede/qede_main.c | 44 ++++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-)
drivers/net/ethernet/qlogic/qede/qede_main.c +22 -22
@@ -113,7 +113,7 @@ static void qede_remove(struct pci_dev *pdev);static void qede_shutdown (struct pci_dev *pdev);static void qede_link_update (void *dev,struct qed_link_output *link);static void qede_schedule_recovery_handler (void *dev); -static void qede_recovery_handler (struct qede_dev *edev); +static bool qede_recovery_handler (struct qede_dev *edev);static void qede_schedule_hw_err_handler (void *dev,enum qed_hw_err_type err_type);static void qede_get_eth_tlv_data (void *edev,void *data);
@@ -993,21 +993,6 @@ void __qede_unlock(struct qede_dev *edev)mutex_unlock (&edev->qede_lock); } -/* This version of the lock should be used when acquiring the RTNL lock is also -* needed in addition to the internal qede lock. -*/ -static void qede_lock (struct qede_dev *edev) -{ -rtnl_lock (); -__qede_lock (edev); -} - -static void qede_unlock (struct qede_dev *edev) -{ -__qede_unlock (edev); -rtnl_unlock (); -} -static void qede_periodic_task (struct work_struct *work) { struct qede_dev *edev = container_of(work, struct qede_dev,
@@ -1044,6 +1029,8 @@ static void qede_sp_task(struct work_struct *work)*/ if (test_and_clear_bit (QEDE_SP_RECOVERY , &edev->sp_flags)) { +bool reloaded; +cancel_delayed_work_sync (&edev->periodic_task);#ifdef CONFIG_QED_SRIOV /* SRIOV must be disabled outside the lock to avoid a deadlock.
@@ -1052,9 +1039,17 @@ static void qede_sp_task(struct work_struct *work)if (pci_num_vf (edev->pdev))qede_sriov_configure (edev->pdev,0 );#endif -qede_lock (edev); -qede_recovery_handler (edev); -qede_unlock (edev); +rtnl_lock (); +__qede_lock (edev); + reloaded =qede_recovery_handler (edev); +__qede_unlock (edev); + +/* The udp_tunnel core synchronously calls back into +* qede_udp_tunnel_sync(), which takes the qede lock. +*/ +if (reloaded) +udp_tunnel_nic_reset_ntf (edev->ndev); +rtnl_unlock (); }__qede_lock (edev);
@@ -2573,9 +2568,13 @@ static void qede_recovery_failed(struct qede_dev *edev) edev->ops->common->set_power_state (edev->cdev, PCI_D3hot); } -static void qede_recovery_handler (struct qede_dev *edev) +/* Returns true if an open device was successfully reloaded and its +* udp_tunnel ports need to be re-synced by the caller. +*/ +static bool qede_recovery_handler (struct qede_dev *edev) {u32 curr_state = edev->state; +bool reloaded = false;int rc;DP_NOTICE (edev,"Starting a recovery process\n" );
@@ -2605,17 +2604,18 @@ static void qede_recovery_handler(struct qede_dev *edev) goto err;qede_config_rx_mode (edev->ndev); -udp_tunnel_nic_reset_ntf (edev->ndev); + reloaded = true; } edev->state = curr_state;DP_NOTICE (edev,"Recovery handling is done\n" ); -return ; +return reloaded; err:qede_recovery_failed (edev); +return false; }static void qede_atomic_hw_err_handler (struct qede_dev *edev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 238/389 ipv6: fib6: fix NULL deref in fib6_walk_continue() on multi-batch dump
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengfei Zhang <[email protected]>
commit 9facb861dc6b9b9ea9793ef5032a9a826f7a4229 upstream.
inet6_dump_fib() saves its progress in cb->args[1] as a positional index within the current hash chain. Between batches, a concurrent fib6_new_table() can insert a new table at the chain head, shifting all existing entries. The saved index then lands on a different table, causing fib6_dump_table() to set w->root to the wrong table while w->node still points into the previous one. fib6_walk_continue() dereferences w->node->parent (NULL) and panics:
BUG: kernel NULL pointer dereference, address: 0000000000000008 RIP: 0010:fib6_walk_continue+0x6e/0x170 Call Trace: <TASK> fib6_dump_table.isra.0+0xc5/0x240 inet6_dump_fib+0xf6/0x420 rtnl_dumpit+0x30/0xa0 netlink_dump+0x15b/0x460 netlink_recvmsg+0x1d6/0x2a0 ____sys_recvmsg+0x17a/0x190
Fix by storing tb->tb6_id in cb->args[1] instead of a positional index. On resume, skip entries until the id matches; a concurrent head-insert can never match the saved id, so the walker always resumes on the correct table.
[Adapted to 5.10/6.1/6.6: inet6_dump_fib() there predates 22e36ea9f5d7
and 5fc68320c1fb, so the return variable is "res" not "err" and the RCU-protected hash walk exits via "out_unlock" instead of "unlock". Context-only change; the fix itself is identical.]
--- net/ipv6/ip6_fib.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
net/ipv6/ip6_fib.c +8 -9
@@ -620,11 +620,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)const struct nlmsghdr *nlh = cb->nlh;struct net *net =sock_net (skb->sk);unsigned int h, s_h; -unsigned int e =0 , s_e;struct fib6_walker *w;struct fib6_table *tb;struct hlist_head *head;int res =0 ; +u32 s_id;if (cb->strict_check) {int err;
@@ -682,25 +682,24 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) } s_h = cb->args[0 ]; - s_e = cb->args[1 ]; + s_id = cb->args[1 ];rcu_read_lock (); -for (h = s_h; h <FIB6_TABLE_HASHSZ ; h++, s_e =0 ) { - e =0 ; +for (h = s_h; h <FIB6_TABLE_HASHSZ ; h++, s_id =0 ) { head = &net->ipv6.fib_table_hash[h];hlist_for_each_entry_rcu (tb, head, tb6_hlist) { -if (e < s_e) - goto next; +if (s_id && tb->tb6_id != s_id) +continue ; + + s_id =0 ; + cb->args[1 ] = tb->tb6_id; res =fib6_dump_table (tb, skb, cb);if (res !=0 ) goto out_unlock; -next: - e++; } } out_unlock:rcu_read_unlock (); - cb->args[1 ] = e; cb->args[0 ] = h; out: res = res <0 ? res : skb->len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 239/389 rhashtable: clear stale iter->p on table restart
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft) <[email protected]>
[ Upstream commit 8173f7e2ce67e6ca1d4763f3da14e5b01ce77456 ]
rhashtable_walk_start_check() has two restart paths when resuming a walk. When iter->walker.tbl is valid, it re-validates iter->p against the table and sets iter->p = NULL if the object is gone. When iter->walker.tbl is NULL (table was freed during resize), it resets slot and skip but forgets to clear iter->p.
rhashtable_walk_next() then dereferences the stale iter->p, reading freed memory. This is a use-after-free.
Any caller that does multi-fragment rhashtable walks across walk_stop/walk_start boundaries is affected. Concrete cases include netlink_diag (__netlink_diag_dump in net/netlink/diag.c) and TIPC (tipc_nl_sk_walk in net/tipc/socket.c).
Crash stack (netlink_diag):
BUG: KASAN: slab-use-after-free in rhashtable_walk_next+0x365/0x3c0 Read of size 8 at addr ffff88801a9d2438 (freed kmalloc-2k, offset 1080) Call Trace: rhashtable_walk_next+0x365/0x3c0 (lib/rhashtable.c:1016) __netlink_diag_dump+0x160/0x760 (net/netlink/diag.c:122) netlink_diag_dump+0xc2/0x240 netlink_dump+0x5bc/0x1270 netlink_recvmsg+0x7a3/0x980 sock_recvmsg+0x1bc/0x200 __sys_recvfrom+0x1d4/0x2c0
--- lib/rhashtable.c | 1 + 1 file changed, 1 insertion(+)
lib/rhashtable.c +1 -0
@@ -730,6 +730,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter) iter->walker.tbl =rht_dereference_rcu (ht->tbl, ht); iter->slot =0 ; iter->skip =0 ; + iter->p =NULL ;return -EAGAIN ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 240/389 pinctrl: devicetree: dont free uninitialized dev_name on error path
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit 015b5bcbcb622b32317642be91a7f79aa5413649 upstream.
dt_remember_or_free_map() duplicates dev_name for each map entry. If kstrdup_const() fails, dt_free_map() frees dev_name in all num_maps entries, including entries that have not been initialized.
Some pinctrl drivers, including pinctrl-imx, allocate the map with kmalloc() and leave dev_name for the core to initialize. The untouched entries therefore contain uninitialized data which is passed to kfree_const().
Reproduced on qemu's mcimx6ul-evk (pinctrl-imx) with failslab injection while binding the pinctrl-consuming device, under KASAN:
BUG: KASAN: double-free in dt_free_map+0x34/0xa4 Free of addr c425a900 by task init/1 kfree from dt_free_map+0x34/0xa4 dt_free_map from dt_remember_or_free_map+0x184/0x198 dt_remember_or_free_map from pinctrl_dt_to_map+0x33c/0x4c8 pinctrl_dt_to_map from create_pinctrl+0x9c/0x5c0
Initialize all dev_name fields to NULL before duplicating the device name, making the full-map cleanup safe after a partial failure.
--- drivers/pinctrl/devicetree.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/pinctrl/devicetree.c +4 -0
@@ -69,6 +69,10 @@ static int dt_remember_or_free_map(strucint i;struct pinctrl_dt_map *dt_map; +/* Initialize dev_name before any allocation can fail */ +for (i =0 ; i < num_maps; i++) + map[i].dev_name =NULL ; +/* Initialize common mapping table entry fields */ for (i =0 ; i < num_maps; i++) {const char *devname;
Greg Kroah-Hartman
maintainerPATCH 241/389 pinctrl: bm1880: add missing select GENERIC_PINCONF
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Boortz <[email protected]>
commit dad6e107b3cd9d20514e7799b7ad8674f81e3f30 upstream.
drivers/pinctrl/pinctrl-bm1880.c initialises its pinconf_ops with .is_generic = true, but that field is only present when CONFIG_GENERIC_PINCONF is enabled (guarded by #ifdef in pinconf.h). The Kconfig entry for PINCTRL_BM1880 never selects GENERIC_PINCONF, so any config that enables CONFIG_PINCTRL_BM1880=y without CONFIG_GENERIC_PINCONF=y fails to compile:
drivers/pinctrl/pinctrl-bm1880.c:1288:10: error: 'const struct pinconf_ops' has no member named 'is_generic'
Found by randconfig testing on arm64; tinyconfig reproducer below. Add the missing select to fix the build.
--- drivers/pinctrl/Kconfig | 1 + 1 file changed, 1 insertion(+)
drivers/pinctrl/Kconfig +1 -0
@@ -115,6 +115,7 @@ config PINCTRL_BM1880 depends on OF && (ARCH_BITMAIN || COMPILE_TEST) default ARCH_BITMAIN select PINMUX + select GENERIC_PINCONF help Pinctrl driver for Bitmain BM1880 SoC.
Greg Kroah-Hartman
maintainerPATCH 242/389 mm/percpu-km: fix bitmap overflow and accounting in pcpu_create_chunk()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zi Yan <[email protected]>
commit 89b1b79c308818a715e75f28744b70d8940a07c9 upstream.
In pcpu_create_chunk(), nr_pages is the total contiguous backing allocation, i.e., nr_units * pcpu_unit_pages, but pcpu_chunk_populated() uses it to set chunk->populated, whose size is pcpu_unit_pages, bitmap. Since bit N in chunk->populated means page offset N inside every unit is backed. When nr_units > 1, the function writes beyond chunk->populated. Fix it by using chunk->nr_pages.
It also fixes the global pcpu_nr_empty_pop_pages accounting, since pcpu_balance_free() only iterates up to chunk->nr_pages.
Commit a63d4ac4ab609 ("percpu: make percpu-km set chunk->populated bitmap properly") introduced the bitmap overflow issue. Later, commit b539b87fed37f ("percpu: implmeent pcpu_nr_empty_pop_pages and chunk->nr_populated") added pcpu_nr_empty_pop_pages and caused the accounting issue.
--- mm/percpu-km.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/percpu-km.c +1 -1
@@ -70,7 +70,7 @@ static struct pcpu_chunk *pcpu_create_ch chunk->base_addr =page_address (pages);spin_lock_irqsave (&pcpu_lock, flags); -pcpu_chunk_populated (chunk,0 , nr_pages); +pcpu_chunk_populated (chunk,0 , chunk->nr_pages);spin_unlock_irqrestore (&pcpu_lock, flags);pcpu_stats_chunk_alloc ();
Greg Kroah-Hartman
maintainerPATCH 243/389 mm/hugetlb: fix list corruption in allocate_file_region_entries()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiangfeng Cai <[email protected]>
commit dd9623f58ec702a07b2d67179d6fcea79c52231a upstream.
allocate_file_region_entries() tops up resv->region_cache with freshly allocated file_region descriptors. The allocation uses GFP_KERNEL, so resv->lock is dropped around it: the new entries are gathered on a stack-local list head, allocated_regions, and spliced into resv->region_cache once the lock is re-acquired.
The splice used list_splice(), which moves the entries but does not re-initialize the source head, so allocated_regions is left pointing at an entry that now lives on resv->region_cache. The top-up runs in a while loop that re-checks the cache deficit after re-acquiring the lock. For a shared mapping the resv_map is shared by every mapper of the hugetlbfs inode, so a concurrent region_chg()/region_add()/region_del() on the same resv_map can consume cache entries during the unlocked window and force a second iteration. That iteration calls list_add() on the stale head and corrupts the list; with CONFIG_DEBUG_LIST the __list_add_valid() check trips:
list_add corruption. next->prev should be prev (ffffc900011ff7f8), but was ffff88814c281460. (next=ffff88814c545640). kernel BUG at lib/list_debug.c:31!
allocate_file_region_entries+0x191/0x420 region_chg+0x267/0x300 hugetlb_reserve_pages+0x387/0xc80 hugetlbfs_file_mmap+0x2ce/0x3f0 mmap_region+0x1348/0x1a80 do_mmap+0x85e/0xb90 vm_mmap_pgoff+0x18c/0x330 ksys_mmap_pgoff+0x2a1/0x3e0 do_syscall_64+0xd7/0x420
Without CONFIG_DEBUG_LIST the bad list_add() silently links a kernel-stack address into resv->region_cache, leading to later use-after-free.
This was observed as a real host panic on a dense KVM host where a QEMU guest-RAM hugetlbfs file was mapped MAP_SHARED by both QEMU and a separate SPDK/DPDK vhost-user target, generating concurrent region_* traffic on one shared resv_map.
Use list_splice_init() so the source head is re-initialized empty after each splice, making the retry loop safe.
--- mm/hugetlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/hugetlb.c +1 -1
@@ -482,7 +482,7 @@ static int allocate_file_region_entries(spin_lock (&resv->lock); -list_splice (&allocated_regions, &resv->region_cache); +list_splice_init (&allocated_regions, &resv->region_cache); resv->region_cache_count += to_allocate; }
Greg Kroah-Hartman
maintainerPATCH 244/389 sctp: validate Adaptation Indication parameter length
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Charles Vosburgh <[email protected]>
commit 74b21f52c5c5a71a05c0ff70e513f4f04ff28b17 upstream.
The Adaptation Layer Indication parameter contains a fixed 32-bit Adaptation Code Point after its parameter header. However, sctp_verify_param() accepts a header-only parameter because the generic parameter walker only requires the header to be present.
sctp_process_param() then reads adaptation_ind beyond the declared parameter. When the malformed parameter is last in an INIT, the read starts at the receive skb tail, and the value is copied into the state cookie returned in the INIT ACK. This may disclose four receive-buffer tail bytes.
Require the declared parameter length to match the fixed structure size and abort the association through the existing invalid parameter length path otherwise.
--- net/sctp/sm_make_chunk.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/sctp/sm_make_chunk.c +6 -0
@@ -2142,7 +2142,13 @@ static enum sctp_ierror sctp_verify_paracase SCTP_PARAM_HEARTBEAT_INFO :case SCTP_PARAM_UNRECOGNIZED_PARAMETERS :case SCTP_PARAM_ECN_CAPABLE : +break ;case SCTP_PARAM_ADAPTATION_LAYER_IND : +if (ntohs (param.p->length) !=sizeof (*param.aind)) { +sctp_process_inv_paramlength (asoc, param.p, + chunk, err_chunk); + retval =SCTP_IERROR_ABORT ; + }break ;case SCTP_PARAM_SUPPORTED_EXT :
Greg Kroah-Hartman
maintainerPATCH 245/389 audit: fix potential integer overflow in audit_log_n_string()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit f865c143629d4094866a811dba5f329250bad486 upstream.
audit_log_n_string() computes new_len as "slen + 3" (enclosing quotes plus the NUL terminator) and stores it into an int, while slen is a size_t. For a sufficiently large slen the addition can overflow and/or the result be truncated when assigned to the int new_len, so the "new_len > avail" check can be bypassed and the subsequent memcpy(ptr, string, slen) can write past the skb tail.
This is the same class of bug that was fixed for the hex sibling in commit 65dfde57d1e2 ("audit: fix potential integer overflow in audit_log_n_hex()"); both helpers are reached through audit_log_n_untrustedstring() with the same length source.
Make new_len a size_t and use check_add_overflow() to catch the overflow, mirroring the audit_log_n_hex() fix. No functional change for the in-tree callers, which all pass bounded lengths.
--- kernel/audit.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
kernel/audit.c +9 -2
@@ -2074,7 +2074,8 @@ void audit_log_n_hex(struct audit_buffervoid audit_log_n_string (struct audit_buffer *ab,const char *string,size_t slen) { -int avail, new_len; +int avail; +size_t new_len;unsigned char *ptr;struct sk_buff *skb;
@@ -2084,7 +2085,13 @@ void audit_log_n_string(struct audit_bufBUG_ON (!ab->skb); skb = ab->skb; avail =skb_tailroom (skb); - new_len = slen +3 ;/* enclosing quotes + null terminator */ + +/* enclosing quotes + null terminator */ +if (check_add_overflow (slen,3 , &new_len)) { +audit_log_format (ab,"?" ); +return ; + } +if (new_len > avail) { avail =audit_expand (ab, new_len);if (!avail)
Greg Kroah-Hartman
maintainerPATCH 246/389 audit: fix potential use-after-free in audit_del_rule()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luxiao Xu <[email protected]>
commit 246df90b5f1a8a6e6abbd2f058b029558720adec upstream.
audit_del_rule() destroys e->rule.exe via audit_remove_mark_rule() before unlinking the rule from RCU-visible filter lists and waiting for a grace period. Concurrent readers in audit_filter() and audit_filter_rules() still dereference e->rule.exe, while the fsnotify mark can be freed on an independent lifetime path. This creates a use-after-free window during rule deletion.
Fix this by unlinking the rule from the RCU-visible lists and invoking synchronize_rcu() before calling audit_remove_mark_rule() (and other rule removal helpers). This ensures that all existing RCU readers have exited the critical section before any underlying resources are destroyed.
--- kernel/auditfilter.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/auditfilter.c +4 -2
@@ -1036,6 +1036,10 @@ int audit_del_rule(struct audit_entry *e goto out; } +list_del_rcu (&e->list); +list_del (&e->rule.list); +synchronize_rcu (); +if (e->rule.watch)audit_remove_watch_rule (&e->rule);
@@ -1053,8 +1057,6 @@ int audit_del_rule(struct audit_entry *e audit_signals--;#endif -list_del_rcu (&e->list); -list_del (&e->rule.list);call_rcu (&e->rcu, audit_free_rule_rcu); out:
Greg Kroah-Hartman
maintainerPATCH 247/389 Bluetooth: HIDP: validate numbered report payloads
In reply to Greg Kroah-Hartman5.10-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
@@ -533,9 +533,10 @@ static int hidp_process_data(struct hidp }if (test_bit (HIDP_WAITING_FOR_RETURN , &session->flags) && - param == session->waiting_report_type) { + param == session->waiting_report_type) {if (session->waiting_report_number <0 || - session->waiting_report_number == skb->data[0 ]) { + (skb->len && + session->waiting_report_number == skb->data[0 ])) {/* hidp_get_raw_report() is waiting on this report. */ session->report_return = skb; done_with_skb =0 ;
Greg Kroah-Hartman
maintainerPATCH 248/389 bpf: lwt: Fix dst reference leak on reroute failure
In reply to Greg Kroah-Hartman5.10-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
@@ -245,8 +245,10 @@ static int bpf_lwt_xmit_reroute(struct s* if there is enough header space in skb. */ err =skb_cow_head (skb,LL_RESERVED_SPACE (dst->dev)); -if (unlikely (err)) +if (unlikely (err)) { +dst_release (dst); goto err; + }skb_dst_drop (skb);skb_dst_set (skb, dst);
Greg Kroah-Hartman
maintainerPATCH 249/389 ALSA: 6fire: Fix UAF at error handling during probe
In reply to Greg Kroah-Hartman5.10-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
@@ -159,6 +159,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 250/389 ALSA: lx6464es: fix period byte count for 16-bit streams
In reply to Greg Kroah-Hartman5.10-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
@@ -412,11 +412,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
@@ -1019,10 +1019,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 251/389 ALSA: pcm: wake linked drain waiters on unlink
In reply to Greg Kroah-Hartman5.10-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
@@ -2335,6 +2335,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;
@@ -2350,6 +2351,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 252/389 ASoC: tas2562: fix DVC coefficient write order
In reply to Greg Kroah-Hartman5.10-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
@@ -508,20 +508,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 253/389 ASoC: tas2562: fix broken entries in the volume lookup table
In reply to Greg Kroah-Hartman5.10-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 254/389 ALSA: usb-audio: fix OOB write in snd_usbmidi_akai_output()
In reply to Greg Kroah-Hartman5.10-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
@@ -816,6 +816,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 255/389 ALSA: usb-audio: Fix DMA buffer out-of-bounds write when fill_max is set
In reply to Greg Kroah-Hartman5.10-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
@@ -871,10 +871,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 (ep->chip->dev) !=USB_SPEED_FULL ) { packs_per_ms =8 >> ep->datainterval;
Greg Kroah-Hartman
maintainerPATCH 256/389 ALSA: usb-audio: Clamp frame size in implicit-feedback mode
In reply to Greg Kroah-Hartman5.10-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
@@ -1352,11 +1352,13 @@ void snd_usb_handle_sync_urb(struct snd_ 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 ; + } } ep->next_packet_write_pos++;
Greg Kroah-Hartman
maintainerPATCH 257/389 dmaengine: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+
In reply to Greg Kroah-Hartman5.10-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 258/389 e1000: fix memory leak in e1000_probe()
In reply to Greg Kroah-Hartman5.10-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 259/389 igbvf: Fix leak in TX DMA error cleanup
In reply to Greg Kroah-Hartman5.10-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
@@ -2215,8 +2215,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 260/389 ipvs: do not propagate one-packet flag to synced conns
In reply to Greg Kroah-Hartman5.10-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 261/389 net/smc: fix socket use-after-free during link group termination
In reply to Greg Kroah-Hartman5.10-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
@@ -919,10 +919,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 262/389 netfilter: ipset: do not update comments from kernel-side hash adds
In reply to Greg Kroah-Hartman5.10-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
@@ -986,7 +986,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 263/389 tipc: avoid use-after-free in poll trace queue dumps
In reply to Greg Kroah-Hartman5.10-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
@@ -774,7 +774,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 264/389 wifi: mwifiex: use the subframe length when parsing A-MSDU TDLS frames
In reply to Greg Kroah-Hartman5.10-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
@@ -56,7 +56,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 265/389 binfmt_misc: reject a flag character as the field delimiter
In reply to Greg Kroah-Hartman5.10-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 266/389 mm/page_reporting: use system_freezable_wq to fix UAF during suspend
In reply to Greg Kroah-Hartman5.10-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
@@ -43,7 +43,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 */
@@ -306,7 +307,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 267/389 net: bridge: stop fast-leave after deleting a port group
In reply to Greg Kroah-Hartman5.10-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
@@ -2838,6 +2838,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 268/389 net: ipv6: clear suppressed fib6 rule result
In reply to Greg Kroah-Hartman5.10-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
@@ -300,6 +300,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 269/389 powerpc/ps3: Fix map failure path in dma_ioc0_map_pages()
In reply to Greg Kroah-Hartman5.10-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
@@ -614,6 +614,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 270/389 um: vector: fix use-after-free in vector_mmsg_rx()
In reply to Greg Kroah-Hartman5.10-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
@@ -1008,6 +1008,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 271/389 vxlan: re-fetch eth header after route_shortcircuit()
In reply to Greg Kroah-Hartman5.10-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
@@ -2940,6 +2940,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 272/389 vxlan: unclone skb head before modifying eth header in route_shortcircuit()
In reply to Greg Kroah-Hartman5.10-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
@@ -2291,6 +2291,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 273/389 vxlan: use neigh_ha_snapshot() in route_shortcircuit()
In reply to Greg Kroah-Hartman5.10-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
@@ -2287,9 +2287,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);
@@ -2297,7 +2299,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 274/389 vxlan: use pskb_network_may_pull() in route_shortcircuit()
In reply to Greg Kroah-Hartman5.10-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
@@ -2239,7 +2239,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);
@@ -2265,7 +2265,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 275/389 tracing: Check return value of __register_event() in trace_module_add_events()
In reply to Greg Kroah-Hartman5.10-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
@@ -2654,8 +2654,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 276/389 tracing/filters: Fix false positive match in regex_match_full()
In reply to Greg Kroah-Hartman5.10-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
@@ -836,6 +836,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 277/389 selftests/clone3: fix wild pointer access of getline due to missing init
In reply to Greg Kroah-Hartman5.10-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 278/389 sctp: reject stale cookies with mismatched verification tags
In reply to Greg Kroah-Hartman5.10-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
@@ -1776,9 +1776,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
@@ -1789,7 +1789,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 279/389 sctp: prevent peer transport count overflow
In reply to Greg Kroah-Hartman5.10-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
@@ -613,6 +613,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 280/389 i2c: amd-mp2: Unregister callback on adapter add failure
In reply to Greg Kroah-Hartman5.10-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
@@ -327,8 +327,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 281/389 cpufreq: powernow-k8: Fix possible memory leak in powernowk8_cpu_init()
In reply to Greg Kroah-Hartman5.10-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 282/389 s390/dasd: Fix potential NULL pointer dereference
In reply to Greg Kroah-Hartman5.10-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
@@ -333,7 +333,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 283/389 s390/zcrypt: Validate length for CCA AES cipher key requests
In reply to Greg Kroah-Hartman5.10-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
@@ -1229,6 +1229,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 284/389 s390/zcrypt: Validate length for CCA ECC private key requests
In reply to Greg Kroah-Hartman5.10-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
@@ -1398,6 +1398,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 285/389 phy: zynqmp: fix L0_TM_DISABLE_SCRAMBLE_ENCODER mask
In reply to Greg Kroah-Hartman5.10-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
@@ -52,7 +52,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 286/389 phy: zynqmp: use read-modify-write for SERDES scrambler bypass
In reply to Greg Kroah-Hartman5.10-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
@@ -413,8 +413,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 287/389 phy: zynqmp: keep SERDES scrambler and 8b/10b enabled for USB
In reply to Greg Kroah-Hartman5.10-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
@@ -410,15 +410,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. */
@@ -439,7 +454,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 ); }
@@ -455,7 +470,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. */
@@ -608,6 +623,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 ; } out:
Greg Kroah-Hartman
maintainerPATCH 288/389 net: openvswitch: fix potential UAF on meter attach failure
In reply to Greg Kroah-Hartman5.10-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
@@ -136,18 +136,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) {
@@ -155,16 +147,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 289/389 net: openvswitch: fix skb leak on flow key update failure during ct
In reply to Greg Kroah-Hartman5.10-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
@@ -1316,7 +1316,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 290/389 i2c: jz4780: Cache host clock rate at probe to prevent CCF prepare_lock deadlock
In reply to Greg Kroah-Hartman5.10-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 */
@@ -801,6 +802,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 291/389 can: j1939: transport: j1939_session_fresh_new(): initialize receive buffer
In reply to Greg Kroah-Hartman5.10-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
@@ -1546,7 +1546,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 292/389 can: kvaser_usb: kvaser_usb_hydra_get_busparams(): fix memory leak in kvaser_usb_hydra_get_busparams()
In reply to Greg Kroah-Hartman5.10-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
@@ -1582,6 +1582,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 293/389 can: kvaser_usb_leaf: kvaser_usb_leaf_wait_cmd(): validate received command extents
In reply to Greg Kroah-Hartman5.10-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
@@ -615,13 +615,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; }
@@ -1576,7 +1585,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 294/389 can: softing: fw_parse(): validate firmware record spans
In reply to Greg Kroah-Hartman5.10-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 ]);