7.1.6-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 493/744 media: marvell-cam: fix missing pci_disable_device() on remove
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 033ff0420e4c9c240ae5523fff39770298efa964 upstream.
During manual code audit, we found that cafe_pci_probe() enables the PCI device with pci_enable_device(), and its probe error path properly calls pci_disable_device() on failure.
However, cafe_pci_remove() tears down the controller and frees the driver data without disabling the PCI device, leaving the remove path inconsistent with probe cleanup.
Add the missing pci_disable_device() call to cafe_pci_remove().
--- drivers/media/platform/marvell/cafe-driver.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/platform/marvell/cafe-driver.c +1 -0
@@ -609,6 +609,7 @@ static void cafe_pci_remove(struct pci_dreturn ; }cafe_shutdown (cam); +pci_disable_device (pdev);kfree (cam); }
Greg Kroah-Hartman
maintainerPATCH 494/744 media: meson: vdec: Fix memory leak in error path of vdec_open
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anand Moon <[email protected]>
commit 940f161f734b25f175a95d2684c2021f6323693a upstream.
The vdec_open() function previously jumped directly to err_m2m_release when vdec_init_ctrls() failed, skipping release of the m2m context. This caused a resource leak.
Fix it by introducing a proper err_m2m_ctx_release label that calls v4l2_m2m_ctx_release(sess->m2m_ctx) before releasing the m2m device.
This was identified via kmemleak:
unreferenced object 0xffff0000205d6878 (size 8):
comm "v4l_id", pid 5289, jiffies 4294938580
hex dump (first 8 bytes):
40 d2 49 18 00 00 ff ff @.I.....
backtrace (crc d3204599):
kmemleak_alloc+0xc8/0xf0
__kvmalloc_node_noprof+0x60c/0x850
v4l2_ctrl_handler_init_class+0x1b4/0x2e8 [videodev]
vdec_open+0x1f4/0x788 [meson_vdec]
v4l2_open+0x144/0x460 [videodev]
chrdev_open+0x1ac/0x500
do_dentry_open+0x3f0/0xfe8
vfs_open+0x68/0x320
do_open+0x2d8/0x9a8
path_openat+0x1d0/0x4f0
do_filp_open+0x190/0x380
do_sys_openat2+0xf8/0x1b0
__arm64_sys_openat+0x13c/0x1e8
invoke_syscall+0xdc/0x268
el0_svc_common.constprop.0+0x178/0x258
do_el0_svc+0x4c/0x70--- drivers/staging/media/meson/vdec/vdec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/staging/media/meson/vdec/vdec.c +3 -1
@@ -889,7 +889,7 @@ static int vdec_open(struct file *file) ret =vdec_init_ctrls (sess);if (ret) - goto err_m2m_release; + goto err_m2m_ctx_release; sess->pixfmt_cap = formats[0 ].pixfmts_cap[0 ]; sess->fmt_out = &formats[0 ];
@@ -913,6 +913,8 @@ static int vdec_open(struct file *file)return 0 ; +err_m2m_ctx_release: +v4l2_m2m_ctx_release (sess->m2m_ctx); err_m2m_release:v4l2_m2m_release (sess->m2m_dev); err_free_sess:
Greg Kroah-Hartman
maintainerPATCH 495/744 media: msi2500: Return queued buffers on start_streaming() failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit 7201c17786a498497bca57752883b90914d405ac upstream.
The vb2 framework hands buffers to the driver via buf_queue() before calling start_streaming(). If start_streaming() returns an error without first returning those buffers via vb2_buffer_done(), vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued buffers leak.
msi2500_start_streaming() had five error paths that all hit this trap and were further tangled by ret-overwriting between calls:
- -ENODEV when the USB device was already disconnected
- -ERESTARTSYS when mutex_lock_interruptible() was interrupted
- msi2500_set_usb_adc() failure: ret was silently overwritten by the next call (msi2500_isoc_init), so the error was lost entirely
- msi2500_isoc_init() failure: cleanup_queued_bufs was called, but the function then fell through to msi2500_ctrl_msg() and again masked the original error by overwriting ret
- msi2500_ctrl_msg(CMD_START_STREAMING) failure: no cleanup at all, leaving isoc URBs submitted with no way for the driver to consume them
Consolidate the error paths into a small goto chain. Every failure now stops the function, drains the queued-buffer list, and returns the real error code. The ctrl_msg failure path also rolls back the preceding msi2500_isoc_init() via msi2500_isoc_cleanup() before unlocking and draining.
The cleanup helper takes a vb2_buffer_state argument so that the start_streaming error paths can pass VB2_BUF_STATE_QUEUED (as expected by userspace on start_streaming failure) while stop_streaming keeps its existing VB2_BUF_STATE_ERROR semantics.
This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo:
Return queued buffers on start_streaming() failure").
--- drivers/media/usb/msi2500/msi2500.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-)
drivers/media/usb/msi2500/msi2500.c +24 -8
@@ -541,7 +541,8 @@ static int msi2500_isoc_init(struct msi2 }/* Must be called with vb_queue_lock hold */ -static void msi2500_cleanup_queued_bufs (struct msi2500_dev *dev) +static void msi2500_cleanup_queued_bufs (struct msi2500_dev *dev, +enum vb2_buffer_state state) {unsigned long flags;
@@ -554,7 +555,7 @@ static void msi2500_cleanup_queued_bufs( buf =list_entry (dev->queued_bufs.next, struct msi2500_frame_buf, list);list_del (&buf->list); -vb2_buffer_done (&buf->vb.vb2_buf,VB2_BUF_STATE_ERROR ); +vb2_buffer_done (&buf->vb.vb2_buf, state); }spin_unlock_irqrestore (&dev->queued_bufs_lock, flags); }
@@ -830,25 +831,40 @@ static int msi2500_start_streaming(strucdev_dbg (dev->dev,"\n" ); -if (!dev->udev) -return -ENODEV ; +if (!dev->udev) { + ret = -ENODEV ; + goto err_cleanup; + } -if (mutex_lock_interruptible (&dev->v4l2_lock)) -return -ERESTARTSYS ; +if (mutex_lock_interruptible (&dev->v4l2_lock)) { + ret = -ERESTARTSYS ; + goto err_cleanup; + }/* wake-up tuner */ v4l2_subdev_call (dev->v4l2_subdev, core, s_power,1 ); ret =msi2500_set_usb_adc (dev); +if (ret) + goto err_unlock_cleanup; ret =msi2500_isoc_init (dev);if (ret) -msi2500_cleanup_queued_bufs (dev); + goto err_unlock_cleanup; ret =msi2500_ctrl_msg (dev,CMD_START_STREAMING ,0 ); +if (ret) + goto err_isoc_cleanup;mutex_unlock (&dev->v4l2_lock); +return 0 ; +err_isoc_cleanup: +msi2500_isoc_cleanup (dev); +err_unlock_cleanup: +mutex_unlock (&dev->v4l2_lock); +err_cleanup: +msi2500_cleanup_queued_bufs (dev,VB2_BUF_STATE_QUEUED );return ret; }
@@ -863,7 +879,7 @@ static void msi2500_stop_streaming(strucif (dev->udev)msi2500_isoc_cleanup (dev); -msi2500_cleanup_queued_bufs (dev); +msi2500_cleanup_queued_bufs (dev,VB2_BUF_STATE_ERROR );/* according to tests, at least 700us delay is required */ msleep (20 );
Greg Kroah-Hartman
maintainerPATCH 496/744 media: nuvoton: npcm-video: fix error handling in npcm_video_init()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
commit 60ca00792bce46ec170c7ed101f376186d4cf8a9 upstream.
npcm_video_init() has two error handling issues after of_reserved_mem_device_init() is called:
When dma_set_mask_and_coherent() fails, the function releases the reserved memory but does not return, allowing execution to fall through into npcm_video_ece_init() with a failed DMA configuration.
When npcm_video_ece_init() fails, the function returns an error without calling of_reserved_mem_device_release(), leaking the reserved memory association.
Fix both by adding the missing return after the DMA mask failure and adding the missing of_reserved_mem_device_release() call on the ECE init error path.
--- drivers/media/platform/nuvoton/npcm-video.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/media/platform/nuvoton/npcm-video.c +2 -0
@@ -1720,10 +1720,12 @@ static int npcm_video_init(struct npcm_vif (rc) {dev_err (dev,"Failed to set DMA mask\n" );of_reserved_mem_device_release (dev); +return rc; } rc =npcm_video_ece_init (video);if (rc) { +of_reserved_mem_device_release (dev);dev_err (dev,"Failed to initialize ECE\n" );return rc; }
Greg Kroah-Hartman
maintainerPATCH 497/744 media: nuvoton: npcm-video: fix memory leaks in probe and remove
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
commit 50cc0e547da50b887e63dfa1ad203cd5b735d01e upstream.
npcm_video_probe() allocates the npcm_video structure with kzalloc_obj() but never frees it on any probe error path or in npcm_video_remove(), leaking the allocation on every failed probe and every normal unbind.
Additionally, when npcm_video_setup_video() fails, the reserved memory association established by of_reserved_mem_device_init() in npcm_video_init() is not released, leaking the rmem_assigned_device entry on the global list.
Fix both by adding kfree(video) to all probe error paths and to npcm_video_remove(), and adding the missing of_reserved_mem_device_release() call when npcm_video_setup_video() fails.
--- drivers/media/platform/nuvoton/npcm-video.c | 32 ++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 9 deletions(-)
drivers/media/platform/nuvoton/npcm-video.c +23 -9
@@ -1750,42 +1750,55 @@ static int npcm_video_probe(struct platf regs =devm_platform_ioremap_resource (pdev,0 );if (IS_ERR (regs)) {dev_err (&pdev->dev,"Failed to parse VCD reg in DTS\n" ); -return PTR_ERR (regs); + rc =PTR_ERR (regs); + goto err_free; } video->vcd_regmap =devm_regmap_init_mmio (&pdev->dev, regs, &npcm_video_regmap_cfg);if (IS_ERR (video->vcd_regmap)) {dev_err (&pdev->dev,"Failed to initialize VCD regmap\n" ); -return PTR_ERR (video->vcd_regmap); + rc =PTR_ERR (video->vcd_regmap); + goto err_free; } video->reset =devm_reset_control_get (&pdev->dev,NULL );if (IS_ERR (video->reset)) {dev_err (&pdev->dev,"Failed to get VCD reset control in DTS\n" ); -return PTR_ERR (video->reset); + rc =PTR_ERR (video->reset); + goto err_free; } video->gcr_regmap =syscon_regmap_lookup_by_phandle (pdev->dev.of_node,"nuvoton,sysgcr" ); -if (IS_ERR (video->gcr_regmap)) -return PTR_ERR (video->gcr_regmap); +if (IS_ERR (video->gcr_regmap)) { + rc =PTR_ERR (video->gcr_regmap); + goto err_free; + } video->gfx_regmap =syscon_regmap_lookup_by_phandle (pdev->dev.of_node,"nuvoton,sysgfxi" ); -if (IS_ERR (video->gfx_regmap)) -return PTR_ERR (video->gfx_regmap); +if (IS_ERR (video->gfx_regmap)) { + rc =PTR_ERR (video->gfx_regmap); + goto err_free; + } rc =npcm_video_init (video);if (rc) -return rc; + goto err_free; rc =npcm_video_setup_video (video);if (rc) -return rc; + goto err_release_mem;dev_info (video->dev,"NPCM video driver probed\n" );return 0 ; + +err_release_mem: +of_reserved_mem_device_release (&pdev->dev); +err_free: +kfree (video); +return rc; }static void npcm_video_remove (struct platform_device *pdev)
@@ -1800,6 +1813,7 @@ static void npcm_video_remove(struct plav4l2_device_unregister (v4l2_dev);if (video->ece.enable)npcm_video_ece_stop (video); +kfree (video);of_reserved_mem_device_release (dev); }
Greg Kroah-Hartman
maintainerPATCH 498/744 media: nxp: imx8-isi: Add missing v4l2_subdev_cleanup() in crossbar and pipe
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaolei Wang <[email protected]>
commit 567418eedd25b3d86d489807682030b4b98b73d9 upstream.
Both mxc_isi_crossbar_init() and mxc_isi_pipe_init() call v4l2_subdev_init_finalize() which allocates the subdev active state, but neither mxc_isi_crossbar_cleanup() nor mxc_isi_pipe_cleanup() calls v4l2_subdev_cleanup() to free it.
This causes a memory leak on every rmmod, reported by kmemleak:
unreferenced object 0xffff0000d06fc800 (size 192):
comm "(udev-worker)", pid 254, jiffies 4294913455
backtrace (crc 36eeae58):
kmemleak_alloc+0x34/0x40
__kvmalloc_node_noprof+0x5f8/0x7d8
__v4l2_subdev_state_alloc+0x1fc/0x30c
__v4l2_subdev_init_finalize+0x178/0x368Add the missing v4l2_subdev_cleanup() calls before media_entity_cleanup() in both crossbar and pipe cleanup paths.
--- drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c | 1 + drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c | 1 + 2 files changed, 2 insertions(+)
drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +1 -0
@@ -491,6 +491,7 @@ err_free:void mxc_isi_crossbar_cleanup (struct mxc_isi_crossbar *xbar) { +v4l2_subdev_cleanup (&xbar->sd);media_entity_cleanup (&xbar->sd.entity);kfree (xbar->pads);kfree (xbar->inputs);
drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +1 -0
@@ -819,6 +819,7 @@ void mxc_isi_pipe_cleanup(struct mxc_isi {struct v4l2_subdev *sd = &pipe->sd; +v4l2_subdev_cleanup (sd);media_entity_cleanup (&sd->entity);mutex_destroy (&pipe->lock); }
Greg Kroah-Hartman
maintainerPATCH 499/744 media: nxp: imx8-isi: Clean up already-initialized pipes on probe failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaolei Wang <[email protected]>
commit d970b27cc48ec42f8a72bc3a4a4ad2e5c7a36395 upstream.
When mxc_isi_pipe_init() fails partway through the channel loop or when mxc_isi_v4l2_init() fails, the already initialized pipes are not cleaned up.
Fix this by calling mxc_isi_pipe_cleanup() for each already-initialized pipe in the err_xbar error path.
--- drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +2 -0
@@ -538,6 +538,8 @@ static int mxc_isi_probe(struct platformreturn 0 ; err_xbar: +while (i--) +mxc_isi_pipe_cleanup (&isi->pipes[i]);mxc_isi_crossbar_cleanup (&isi->crossbar);return ret;
Greg Kroah-Hartman
maintainerPATCH 500/744 media: nxp: imx8-isi: Fix missing v4l2_subdev_cleanup() in pipe init error path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaolei Wang <[email protected]>
commit 8262de0663318124824aaafd97ddb5d7bb53bd77 upstream.
After v4l2_subdev_init_finalize() succeeds in mxc_isi_pipe_init(), if platform_get_irq() or devm_request_irq() fails, the error path jumps to a label that only calls media_entity_cleanup() and mutex_destroy(), missing the v4l2_subdev_cleanup() call needed to free the subdev active state allocated by v4l2_subdev_init_finalize().
Add an error_subdev label that calls v4l2_subdev_cleanup() before falling through to the existing error cleanup.
--- drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +4 -2
@@ -796,18 +796,20 @@ int mxc_isi_pipe_init(struct mxc_isi_dev irq =platform_get_irq (to_platform_device (isi->dev), id);if (irq <0 ) { ret = irq; - goto error; + goto error_subdev; } ret =devm_request_irq (isi->dev, irq, mxc_isi_pipe_irq_handler,0 ,dev_name (isi->dev), pipe);if (ret <0 ) {dev_err (isi->dev,"failed to request IRQ (%d)\n" , ret); - goto error; + goto error_subdev; }return 0 ; +error_subdev: +v4l2_subdev_cleanup (sd); error:media_entity_cleanup (&sd->entity);mutex_destroy (&pipe->lock);
Greg Kroah-Hartman
maintainerPATCH 501/744 media: nxp: imx8-isi: Fix potential out-of-bounds issues
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guoniu Zhou <[email protected]>
commit 57a7ec5c9f38ce6c4d6209c4b75c8e57e1fea6cf upstream.
The maximum downscaling factor supported by ISI can be up to 16. Add minimum value constraint before applying the setting to hardware. Otherwise, the process will not respond even when Ctrl+C is executed.
--- drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h | 16 ++++++++++++++++ drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c | 11 ++++++++--- drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c | 13 ++++++++----- 3 files changed, 32 insertions(+), 8 deletions(-)
drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h +16 -0
@@ -11,6 +11,7 @@#define __MXC_ISI_CORE_H__#include <linux/list.h> +#include <linux/math.h> #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/types.h>
@@ -414,4 +415,19 @@ static inline void mxc_isi_debug_cleanup }#endif +/* +* ISI scaling engine works in two parts: it performs pre-decimation of +* the image followed by bilinear filtering to achieve the desired +* downscaling factor. +* +* The decimation filter provides a maximum downscaling factor of 8, and +* the subsequent bilinear filter provides a maximum downscaling factor +* of 2. Combined, the maximum scaling factor can be up to 16. +*/ +static inline unsigned int +mxc_isi_clamp_downscale_16 (unsigned int val,unsigned int max_val) +{ +return clamp (val,max (1U ,DIV_ROUND_UP (max_val,16 )), max_val); +} +#endif /* __MXC_ISI_CORE_H__ */
drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +8 -3
@@ -509,9 +509,14 @@ __mxc_isi_m2m_try_fmt_vid(struct mxc_isi const enum mxc_isi_video_type type) {if (type ==MXC_ISI_VIDEO_M2M_CAP ) { -/* Downscaling only */ - pix->width =min (pix->width, ctx->queues.out.format.width); - pix->height =min (pix->height, ctx->queues.out.format.height); +const struct v4l2_pix_format_mplane *format = + &ctx->queues.out.format; + +/* Downscaling only, by up to 16. */ + pix->width =mxc_isi_clamp_downscale_16 (pix->width, + format->width); + pix->height =mxc_isi_clamp_downscale_16 (pix->height, + format->height); }return mxc_isi_format_try (ctx->m2m->pipe, pix, type);
drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +8 -5
@@ -641,16 +641,19 @@ static int mxc_isi_pipe_set_selection(st/* Composing is supported on the sink only. */ return -EINVAL ; -/* The sink crop is bound by the sink format downscaling only). */ +/* +* The ISI supports downscaling only, with a factor up to 16. +* Clamp the compose rectangle size accordingly. +*/ format =mxc_isi_pipe_get_pad_format (pipe, state,MXC_ISI_PIPE_PAD_SINK ); sel->r.left =0 ; sel->r.top =0 ; - sel->r.width =clamp (sel->r.width,MXC_ISI_MIN_WIDTH , - format->width); - sel->r.height =clamp (sel->r.height,MXC_ISI_MIN_HEIGHT , - format->height); + sel->r.width =mxc_isi_clamp_downscale_16 (sel->r.width, + format->width); + sel->r.height =mxc_isi_clamp_downscale_16 (sel->r.height, + format->height); rect =mxc_isi_pipe_get_pad_compose (pipe, state,MXC_ISI_PIPE_PAD_SINK );
Greg Kroah-Hartman
maintainerPATCH 502/744 media: nxp: imx8-isi: Fix scale factor calculation for hardware rounding
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guoniu Zhou <[email protected]>
commit 5eb54da3f874b44149556542d949909898865e29 upstream.
The ISI hardware rounds the actual output size up to an integer, as described in i.MX93 Reference Manual section 57.7.8 (Channel 0 Scale Factor). The scale factor must be calculated to ensure the theoretical output value rounds up to exactly the desired size.
--- drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c +8 -1
@@ -112,7 +112,14 @@ static u32 mxc_isi_channel_scaling_ratioelse *dec =8 ; -return min_t (u32, from *0x1000 / (to * *dec),ISI_DOWNSCALE_THRESHOLD ); +/* +* The ISI rounds output dimensions up to the next integer (i.MX93 RM +* section 57.7.8). Calculate the scale factor such that the theoretical +* output (input / scale_factor) rounds up to exactly the desired +* output. +*/ +return min_t (u32,DIV_ROUND_UP (from *0x1000 , to * *dec), +ISI_DOWNSCALE_THRESHOLD ); } static void mxc_isi_channel_set_scaling(struct mxc_isi_pipe *pipe,
Greg Kroah-Hartman
maintainerPATCH 503/744 media: pci: dm1105: Free allocated workqueue
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Kozlowski <[email protected]>
commit 1a65db225b25bb8c8febf16974c060e0cc242eb9 upstream.
Destroy allocated workqueue in remove() callback to free its resources, thus fixing memory leak.
--- drivers/media/pci/dm1105/dm1105.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/pci/dm1105/dm1105.c +1 -0
@@ -1194,6 +1194,7 @@ static void dm1105_remove(struct pci_devdm1105_hw_exit (dev);free_irq (pdev->irq, dev); +destroy_workqueue (dev->wq);pci_iounmap (pdev, dev->io_mem);pci_release_regions (pdev);pci_disable_device (pdev);
Greg Kroah-Hartman
maintainerPATCH 504/744 media: pwc: Drain fill_buf on start_streaming() failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit 906e410dcffbbd99fb4081abab817a830033aa28 upstream.
pwc_isoc_init() submits its isochronous URBs with usb_submit_urb(.., GFP_KERNEL) in a loop. After the first URB is submitted, its completion handler pwc_isoc_handler() can run on another CPU before the loop finishes:
start_streaming()
pwc_isoc_init()
usb_submit_urb(urbs[0], GFP_KERNEL)
pwc_isoc_handler(urbs[0])
pdev->fill_buf =
pwc_get_next_fill_buf(pdev)
usb_submit_urb(urbs[i>0], ..) -> fails
pwc_isoc_cleanup(pdev) /* kills URBs */
return ret;
pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED)pwc_get_next_fill_buf() detaches a buffer from pdev->queued_bufs and stores it in pdev->fill_buf. The error path in start_streaming() only drains pdev->queued_bufs, so the buffer parked in pdev->fill_buf is leaked. vb2_start_streaming() then triggers WARN_ON(owned_by_drv_count).
stop_streaming() already handles this since commit 80b0963e1698 ("[media] pwc: fix WARN_ON"), which added the fill_buf drain in the teardown path but not in the start_streaming() error path. Mirror that handling on failure so start_streaming() returns with no buffer owned by the driver.
Issue identified by automated review of the INV-003 series at
https://sashiko.dev/
--- drivers/media/usb/pwc/pwc-if.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/media/usb/pwc/pwc-if.c +5 -0
@@ -726,6 +726,11 @@ static int start_streaming(struct vb2_qupwc_camera_power (pdev,0 );/* And cleanup any queued bufs!! */ pwc_cleanup_queued_bufs (pdev,VB2_BUF_STATE_QUEUED ); +if (pdev->fill_buf) { +vb2_buffer_done (&pdev->fill_buf->vb.vb2_buf, +VB2_BUF_STATE_QUEUED ); + pdev->fill_buf =NULL ; + } }mutex_unlock (&pdev->v4l2_lock);
Greg Kroah-Hartman
maintainerPATCH 505/744 media: pwc: Return queued buffers on start_streaming() failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit 975b2ee20e569d47821e4f6c9761b4664d48a6a4 upstream.
The vb2 framework hands buffers to the driver via buf_queue() before calling start_streaming(). If start_streaming() returns an error without first returning those buffers via vb2_buffer_done(), vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued buffers leak.
pwc's start_streaming() had two early returns that hit this trap:-ENODEV when the USB device was already disconnected, and -ERESTARTSYS when mutex_lock_interruptible() was interrupted by a signal. Call the existing pwc_cleanup_queued_bufs() helper with VB2_BUF_STATE_QUEUED before returning (matching the state already used by the pwc_isoc_init() error path in the same function).
This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo:
Return queued buffers on start_streaming() failure").
--- drivers/media/usb/pwc/pwc-if.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/media/usb/pwc/pwc-if.c +6 -2
@@ -710,11 +710,15 @@ static int start_streaming(struct vb2_qustruct pwc_device *pdev =vb2_get_drv_priv (vq);int r; -if (!pdev->udev) +if (!pdev->udev) { +pwc_cleanup_queued_bufs (pdev,VB2_BUF_STATE_QUEUED );return -ENODEV ; + } -if (mutex_lock_interruptible (&pdev->v4l2_lock)) +if (mutex_lock_interruptible (&pdev->v4l2_lock)) { +pwc_cleanup_queued_bufs (pdev,VB2_BUF_STATE_QUEUED );return -ERESTARTSYS ; + }/* Turn on camera and set LEDS on */ pwc_camera_power (pdev,1 );pwc_set_leds (pdev, leds[0 ], leds[1 ]);
Greg Kroah-Hartman
maintainerPATCH 506/744 media: qcom: camss: Fix RDI streaming for CSID 680
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryan O'Donoghue <[email protected]>
commit 93ea81d16570442dbca04d2e2563ae8c3e65fa1b upstream.
Fix streaming to RDI1 and RDI2. csid->phy.en_vc contains a bitmask of enabled CSID ports not virtual channels.
We cycle through the number of available CSID ports and test this value against the vc_en bitmask.
We then use the passed value both as an index to the port configuration macros and as a virtual channel index.
This is a very broken pattern. Reviewing the initial introduction of VC support it states that you can only map one CSID to one VFE. This is true however each CSID has multiple sources which can sink inside of the VFE - for example there is a "pixel" path for bayer stats which sources @ CSID(x):3 and sinks on VFE(x):pix.
That is CSID port # 3 should drive VFE port #3. With our current setup only a sensor which drives virtual channel number #3 could possibly enable that setup.
This is deeply wrong the virtual channel has no relevance to hooking CSID to VFE, a fact that is proven after this patch is applied allowing RDI0,RDI1 and RDI2 to function with VC0 whereas before only RDI1 worked.
Another way the current model breaks is the DT field. A sensor driving different data-types on the same VC would not be able to separate the VC:DT pair to separate RDI outputs, thus breaking another feature of VCs in the MIPI data-stream.
Default the VC back to zero. A follow on series will implement subdev streams to actually enable VCs without breaking CSID source to VFE sink.
--- drivers/media/platform/qcom/camss/camss-csid-680.c | 30 ++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-)
drivers/media/platform/qcom/camss/camss-csid-680.c +15 -15
@@ -219,9 +219,9 @@ static void __csid_configure_top(struct CSID_TOP_IO_PATH_CFG0(csid->id)); } -static void __csid_configure_rdi_stream (struct csid_device *csid,u8 enable,u8 vc) +static void __csid_configure_rdi_stream (struct csid_device *csid,u8 enable,u8 port,u8 vc) { -struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; +struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port];const struct csid_format_info *format =csid_get_fmt_entry (csid->res->formats->formats, csid->res->formats->nformats, input_format->code);
@@ -233,28 +233,28 @@ static void __csid_configure_rdi_stream( lane_cnt =4 ; val =0 ; -writel (val, csid->base +CSID_RDI_FRM_DROP_PERIOD (vc)); +writel (val, csid->base +CSID_RDI_FRM_DROP_PERIOD (port));/* * DT_ID is a two bit bitfield that is concatenated with * the four least significant bits of the five bit VC * bitfield to generate an internal CID value. * -* CSID_RDI_CFG0(vc) +* CSID_RDI_CFG0(port) * DT_ID : 28:27 * VC : 26:22 * DT : 21:16 * * CID : VC 3:0 << 2 | DT_ID 1:0 */ - dt_id = vc &0x03 ; + dt_id = port &0x03 ;/* note: for non-RDI path, this should be format->decode_format */ val |=DECODE_FORMAT_PAYLOAD_ONLY <<RDI_CFG0_DECODE_FORMAT ; val |= format->data_type <<RDI_CFG0_DATA_TYPE ; val |= vc <<RDI_CFG0_VIRTUAL_CHANNEL ; val |= dt_id <<RDI_CFG0_DT_ID ; -writel (val, csid->base +CSID_RDI_CFG0 (vc)); +writel (val, csid->base +CSID_RDI_CFG0 (port)); val =RDI_CFG1_TIMESTAMP_STB_FRAME ; val |=RDI_CFG1_BYTE_CNTR_EN ;
@@ -265,23 +265,23 @@ static void __csid_configure_rdi_stream( val |=RDI_CFG1_CROP_V_EN ; val |=RDI_CFG1_PACKING_MIPI ; -writel (val, csid->base +CSID_RDI_CFG1 (vc)); +writel (val, csid->base +CSID_RDI_CFG1 (port)); val =0 ; -writel (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PERIOD (vc)); +writel (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PERIOD (port)); val =1 ; -writel (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PATTERN (vc)); +writel (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PATTERN (port)); val =0 ; -writel (val, csid->base +CSID_RDI_CTRL (vc)); +writel (val, csid->base +CSID_RDI_CTRL (port)); - val =readl (csid->base +CSID_RDI_CFG0 (vc)); + val =readl (csid->base +CSID_RDI_CFG0 (port));if (enable) val |=RDI_CFG0_ENABLE ;else val &= ~RDI_CFG0_ENABLE ; -writel (val, csid->base +CSID_RDI_CFG0 (vc)); +writel (val, csid->base +CSID_RDI_CFG0 (port)); }static void csid_configure_stream (struct csid_device *csid,u8 enable)
@@ -290,11 +290,11 @@ static void csid_configure_stream(struct__csid_configure_top (csid); -/* Loop through all enabled VCs and configure stream for each */ +/* Loop through all enabled ports and configure a stream for each */ for (i =0 ; i <MSM_CSID_MAX_SRC_STREAMS ; i++) {if (csid->phy.en_vc &BIT (i)) { -__csid_configure_rdi_stream (csid, enable, i); -__csid_configure_rx (csid, &csid->phy, i); +__csid_configure_rdi_stream (csid, enable, i,0 ); +__csid_configure_rx (csid, &csid->phy,0 );__csid_ctrl_rdi (csid, enable, i); } }
Greg Kroah-Hartman
maintainerPATCH 507/744 media: qcom: camss: Fix RDI streaming for CSID GEN2
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryan O'Donoghue <[email protected]>
commit 618765634cefbdddafa84f07f82e9dd05b86cb9c upstream.
Fix streaming from CSIDn RDI1 and RDI2 to VFEn RDI1 and RDI2. A pattern we have replicated throughout CAMSS where we use the VC number to populate both the VC fields and port fields of the CSID means that in practice only VC = 0 on CSIDn:RDI0 to VFEn:RDI0 works.
Fix that for CSID gen2 by separating VC and port. Fix to VC zero as a bugfix we will look to properly populate the VC field with follow on patches later.
--- drivers/media/platform/qcom/camss/camss-csid-gen2.c | 47 ++++++++++---------- 1 file changed, 24 insertions(+), 23 deletions(-)
drivers/media/platform/qcom/camss/camss-csid-gen2.c +24 -23
@@ -203,10 +203,10 @@ static void __csid_ctrl_rdi(struct csid_writel_relaxed (val, csid->base +CSID_RDI_CTRL (rdi)); } -static void __csid_configure_testgen (struct csid_device *csid,u8 enable,u8 vc) +static void __csid_configure_testgen (struct csid_device *csid,u8 enable,u8 port,u8 vc) {struct csid_testgen_config *tg = &csid->testgen; -struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; +struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port];const struct csid_format_info *format =csid_get_fmt_entry (csid->res->formats->formats, csid->res->formats->nformats, input_format->code);
@@ -253,10 +253,10 @@ static void __csid_configure_testgen(strwritel_relaxed (val, csid->base +CSID_TPG_CTRL ); } -static void __csid_configure_rdi_stream (struct csid_device *csid,u8 enable,u8 vc) +static void __csid_configure_rdi_stream (struct csid_device *csid,u8 enable,u8 port,u8 vc) {/* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ -struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; +struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port];const struct csid_format_info *format =csid_get_fmt_entry (csid->res->formats->formats, csid->res->formats->nformats, input_format->code);
@@ -267,14 +267,14 @@ static void __csid_configure_rdi_stream(* the four least significant bits of the five bit VC * bitfield to generate an internal CID value. * -* CSID_RDI_CFG0(vc) +* CSID_RDI_CFG0(port) * DT_ID : 28:27 * VC : 26:22 * DT : 21:16 * * CID : VC 3:0 << 2 | DT_ID 1:0 */ -u8 dt_id = vc &0x03 ; +u8 dt_id = port &0x03 ; val =1 <<RDI_CFG0_BYTE_CNTR_EN ; val |=1 <<RDI_CFG0_FORMAT_MEASURE_EN ;
@@ -284,56 +284,57 @@ static void __csid_configure_rdi_stream( val |= format->data_type <<RDI_CFG0_DATA_TYPE ; val |= vc <<RDI_CFG0_VIRTUAL_CHANNEL ; val |= dt_id <<RDI_CFG0_DT_ID ; -writel_relaxed (val, csid->base +CSID_RDI_CFG0 (vc)); +writel_relaxed (val, csid->base +CSID_RDI_CFG0 (port));/* CSID_TIMESTAMP_STB_POST_IRQ */ val =2 <<RDI_CFG1_TIMESTAMP_STB_SEL ; -writel_relaxed (val, csid->base +CSID_RDI_CFG1 (vc)); +writel_relaxed (val, csid->base +CSID_RDI_CFG1 (port)); val =1 ; -writel_relaxed (val, csid->base +CSID_RDI_FRM_DROP_PERIOD (vc)); +writel_relaxed (val, csid->base +CSID_RDI_FRM_DROP_PERIOD (port)); val =0 ; -writel_relaxed (val, csid->base +CSID_RDI_FRM_DROP_PATTERN (vc)); +writel_relaxed (val, csid->base +CSID_RDI_FRM_DROP_PATTERN (port)); val =1 ; -writel_relaxed (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PERIOD (vc)); +writel_relaxed (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PERIOD (port)); val =0 ; -writel_relaxed (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PATTERN (vc)); +writel_relaxed (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PATTERN (port)); val =1 ; -writel_relaxed (val, csid->base +CSID_RDI_RPP_PIX_DROP_PERIOD (vc)); +writel_relaxed (val, csid->base +CSID_RDI_RPP_PIX_DROP_PERIOD (port)); val =0 ; -writel_relaxed (val, csid->base +CSID_RDI_RPP_PIX_DROP_PATTERN (vc)); +writel_relaxed (val, csid->base +CSID_RDI_RPP_PIX_DROP_PATTERN (port)); val =1 ; -writel_relaxed (val, csid->base +CSID_RDI_RPP_LINE_DROP_PERIOD (vc)); +writel_relaxed (val, csid->base +CSID_RDI_RPP_LINE_DROP_PERIOD (port)); val =0 ; -writel_relaxed (val, csid->base +CSID_RDI_RPP_LINE_DROP_PATTERN (vc)); +writel_relaxed (val, csid->base +CSID_RDI_RPP_LINE_DROP_PATTERN (port)); val =0 ; -writel_relaxed (val, csid->base +CSID_RDI_CTRL (vc)); +writel_relaxed (val, csid->base +CSID_RDI_CTRL (port)); - val =readl_relaxed (csid->base +CSID_RDI_CFG0 (vc)); + val =readl_relaxed (csid->base +CSID_RDI_CFG0 (port)); val |= enable <<RDI_CFG0_ENABLE ; -writel_relaxed (val, csid->base +CSID_RDI_CFG0 (vc)); +writel_relaxed (val, csid->base +CSID_RDI_CFG0 (port)); }static void csid_configure_stream (struct csid_device *csid,u8 enable) {struct csid_testgen_config *tg = &csid->testgen;u8 i; -/* Loop through all enabled VCs and configure stream for each */ + +/* Loop through all enabled ports and configure a stream for each */ for (i =0 ; i <MSM_CSID_MAX_SRC_STREAMS ; i++)if (csid->phy.en_vc &BIT (i)) {if (tg->enabled) -__csid_configure_testgen (csid, enable, i); +__csid_configure_testgen (csid, enable, i,0 ); -__csid_configure_rdi_stream (csid, enable, i); -__csid_configure_rx (csid, &csid->phy, i); +__csid_configure_rdi_stream (csid, enable, i,0 ); +__csid_configure_rx (csid, &csid->phy,0 );__csid_ctrl_rdi (csid, enable, i); } }
Greg Kroah-Hartman
maintainerPATCH 508/744 media: qcom: camss: Fix RDI streaming for CSID GEN3
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryan O'Donoghue <[email protected]>
commit ad136e52634d5a393a9dc93383f8ea1e898faf37 upstream.
Fix streaming from CSIDn RDI1 and RDI2 to VFEn RDI1 and RDI2. A pattern we have replicated throughout CAMSS where we use the VC number to populate both the VC fields and port fields of the CSID means that in practice only VC = 0 on CSIDn:RDI0 to VFEn:RDI0 works.
Fix that for CSID gen3 by separating VC and port. Fix to VC zero as a bugfix we will look to properly populate the VC field with follow on patches later.
--- drivers/media/platform/qcom/camss/camss-csid-gen3.c | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/media/platform/qcom/camss/camss-csid-gen3.c +14 -14
@@ -145,12 +145,12 @@ static void __csid_configure_wrapper(strwritel (val, csid->camss->csid_wrapper_base +CSID_IO_PATH_CFG0 (csid->id)); } -static void __csid_configure_rdi_stream (struct csid_device *csid,u8 enable,u8 vc) +static void __csid_configure_rdi_stream (struct csid_device *csid,u8 enable,u8 port,u8 vc) {u32 val;u8 lane_cnt = csid->phy.lane_cnt;/* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ -struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; +struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port];const struct csid_format_info *format =csid_get_fmt_entry (csid->res->formats->formats, csid->res->formats->nformats, input_format->code);
@@ -163,14 +163,14 @@ static void __csid_configure_rdi_stream(* the four least significant bits of the five bit VC * bitfield to generate an internal CID value. * -* CSID_RDI_CFG0(vc) +* CSID_RDI_CFG0(port) * DT_ID : 28:27 * VC : 26:22 * DT : 21:16 * * CID : VC 3:0 << 2 | DT_ID 1:0 */ -u8 dt_id = vc &0x03 ; +u8 dt_id = port &0x03 ; val =RDI_CFG0_TIMESTAMP_EN ; val |=RDI_CFG0_TIMESTAMP_STB_SEL ;
@@ -180,7 +180,7 @@ static void __csid_configure_rdi_stream( val |= format->data_type <<RDI_CFG0_DT ; val |= dt_id <<RDI_CFG0_DT_ID ; -writel (val, csid->base +CSID_RDI_CFG0 (vc)); +writel (val, csid->base +CSID_RDI_CFG0 (port)); val =RDI_CFG1_PACKING_FORMAT_MIPI ; val |=RDI_CFG1_PIX_STORE ;
@@ -189,22 +189,22 @@ static void __csid_configure_rdi_stream( val |=RDI_CFG1_CROP_H_EN ; val |=RDI_CFG1_CROP_V_EN ; -writel (val, csid->base +CSID_RDI_CFG1 (vc)); +writel (val, csid->base +CSID_RDI_CFG1 (port)); val =0 ; -writel (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PERIOD (vc)); +writel (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PERIOD (port)); val =1 ; -writel (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PATTERN (vc)); +writel (val, csid->base +CSID_RDI_IRQ_SUBSAMPLE_PATTERN (port)); val =0 ; -writel (val, csid->base +CSID_RDI_CTRL (vc)); +writel (val, csid->base +CSID_RDI_CTRL (port)); - val =readl (csid->base +CSID_RDI_CFG0 (vc)); + val =readl (csid->base +CSID_RDI_CFG0 (port));if (enable) val |=RDI_CFG0_EN ; -writel (val, csid->base +CSID_RDI_CFG0 (vc)); +writel (val, csid->base +CSID_RDI_CFG0 (port)); }static void csid_configure_stream (struct csid_device *csid,u8 enable)
@@ -213,11 +213,11 @@ static void csid_configure_stream(struct__csid_configure_wrapper (csid); -/* Loop through all enabled VCs and configure stream for each */ +/* Loop through all enabled ports and configure a stream for each */ for (i =0 ; i <MSM_CSID_MAX_SRC_STREAMS ; i++)if (csid->phy.en_vc &BIT (i)) { -__csid_configure_rdi_stream (csid, enable, i); -__csid_configure_rx (csid, &csid->phy, i); +__csid_configure_rdi_stream (csid, enable, i,0 ); +__csid_configure_rx (csid, &csid->phy,0 );__csid_ctrl_rdi (csid, enable, i); } }
Greg Kroah-Hartman
maintainerPATCH 509/744 media: qcom: camss: Fix RDI streaming for CSID 340
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryan O'Donoghue <[email protected]>
commit cc1c35619c9895f918f9e388e3caa6ab2ff2fbe7 upstream.
Fix streaming from CSIDn RDI1 and RDI2 to VFEn RDI1 and RDI2. A pattern we have replicated throughout CAMSS where we use the VC number to populate both the VC fields and port fields of the CSID means that in practice only VC = 0 on CSIDn:RDI0 to VFEn:RDI0 works.
Fix that for CSID 340 by separating VC and port. Fix to VC zero as a bugfix we will look to properly populate the VC field with follow on patches later.
--- drivers/media/platform/qcom/camss/camss-csid-340.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
drivers/media/platform/qcom/camss/camss-csid-340.c +10 -8
@@ -74,9 +74,9 @@ static void __csid_ctrl_rdi(struct csid_writel_relaxed (!!enable, csid->base +CSID_RDI_CTRL (rdi)); } -static void __csid_configure_rdi_stream (struct csid_device *csid,u8 enable,u8 vc) +static void __csid_configure_rdi_stream (struct csid_device *csid,u8 enable,u8 port,u8 vc) { -struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; +struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port];const struct csid_format_info *format =csid_get_fmt_entry (csid->res->formats->formats, csid->res->formats->nformats, input_format->code);
@@ -88,14 +88,14 @@ static void __csid_configure_rdi_stream(* the four least significant bits of the five bit VC * bitfield to generate an internal CID value. * -* CSID_RDI_CFG0(vc) +* CSID_RDI_CFG0(port) * DT_ID : 28:27 * VC : 26:22 * DT : 21:16 * * CID : VC 3:0 << 2 | DT_ID 1:0 */ - dt_id = vc &0x03 ; + dt_id = port &0x03 ; val =CSID_RDI_CFG0_DECODE_FORMAT_NOP ;/* only for RDI path */ val |=FIELD_PREP (CSID_RDI_CFG0_DT_MASK , format->data_type);
@@ -105,10 +105,11 @@ static void __csid_configure_rdi_stream(if (enable) val |=CSID_RDI_CFG0_ENABLE ; -dev_dbg (csid->camss->dev,"CSID%u: Stream %s (dt:0x%x vc=%u)\n" , - csid->id, enable ?"enable" :"disable" , format->data_type, vc); +dev_dbg (csid->camss->dev,"CSID%u: Stream %s (dt:0x%x port=%u vc=%u)\n" , + csid->id, enable ?"enable" :"disable" , format->data_type, + port, vc); -writel_relaxed (val, csid->base +CSID_RDI_CFG0 (vc)); +writel_relaxed (val, csid->base +CSID_RDI_CFG0 (port)); }static void csid_configure_stream (struct csid_device *csid,u8 enable)
@@ -117,9 +118,10 @@ static void csid_configure_stream(struct__csid_configure_rx (csid, &csid->phy); +/* Loop through all enabled ports and configure a stream for each */ for (i =0 ; i <MSM_CSID_MAX_SRC_STREAMS ; i++) {if (csid->phy.en_vc &BIT (i)) { -__csid_configure_rdi_stream (csid, enable, i); +__csid_configure_rdi_stream (csid, enable, i,0 );__csid_ctrl_rdi (csid, enable, i); } }
Greg Kroah-Hartman
maintainerPATCH 510/744 media: radio-si476x: Unregister v4l2_device on probe failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 436a693af04ffb889aaf87cb69ec1f2b21d3569c upstream.
si476x_radio_probe() registers radio->v4l2dev before allocating the V4L2 controls and before registering the video device. If any of those later steps fails, probe returns through the exit label after freeing only the control handler.
A failed probe does not call si476x_radio_remove(), so the v4l2_device_unregister() there is not reached. This leaves the parent device reference taken by v4l2_device_register() behind on the error path.
Unregister the V4L2 device in the probe error path after freeing the controls.
--- drivers/media/radio/radio-si476x.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/radio/radio-si476x.c +1 -0
@@ -1493,6 +1493,7 @@ static int si476x_radio_probe(struct plareturn 0 ; exit:v4l2_ctrl_handler_free (radio->videodev.ctrl_handler); +v4l2_device_unregister (&radio->v4l2dev);return rval; }
Greg Kroah-Hartman
maintainerPATCH 511/744 media: rtl2832: fix use-after-free in rtl2832_remove()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
commit 680daf40a82d483949f87f0d8f98639dc47e610c upstream.
cancel_delayed_work_sync() is called before i2c_mux_del_adapters() in rtl2832_remove(). While the cancel waits for any running instance of i2c_gate_work to finish, it does not prevent the timer from being rescheduled by a concurrent thread.
During probe, the r820t_attach() call attempts I2C transfers through the mux adapter. These transfers go through i2c_mux_master_xfer(), which calls rtl2832_deselect() after the transfer completes, rescheduling i2c_gate_work via schedule_delayed_work(). If this transfer is still in flight when rtl2832_remove() runs, rtl2832_deselect() can reschedule i2c_gate_work after it has been cancelled, causing a use-after-free when kfree(dev) is called.
Fix this by calling i2c_mux_del_adapters() before cancel_delayed_work_sync(). Once the mux adapter is unregistered, no new I2C transfers can go through it, so rtl2832_deselect() can no longer reschedule i2c_gate_work. The subsequent cancel_delayed_work_sync() is then guaranteed to be final.
--- drivers/media/dvb-frontends/rtl2832.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/dvb-frontends/rtl2832.c +2 -2
@@ -1115,10 +1115,10 @@ static void rtl2832_remove(struct i2c_cldev_dbg (&client->dev,"\n" ); -cancel_delayed_work_sync (&dev->i2c_gate_work); -i2c_mux_del_adapters (dev->muxc); +cancel_delayed_work_sync (&dev->i2c_gate_work); +regmap_exit (dev->regmap);kfree (dev);
Greg Kroah-Hartman
maintainerPATCH 512/744 media: rtl2832_sdr: Return queued buffers on start_streaming() failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit 33ca0aab6f4bd90921fc1395478f38f72c4d19af upstream.
The vb2 framework hands buffers to the driver via buf_queue() before calling start_streaming(). If start_streaming() returns an error without first returning those buffers via vb2_buffer_done(), vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued buffers leak.
rtl2832_sdr_start_streaming() had multiple error paths that hit this
trap: two direct early returns (-ENODEV, -ERESTARTSYS), plus six goto err paths covering subdev s_power, tuner setup, ADC setup, stream-buffer allocation, urb allocation, and urb submission failures. None of them returned the queued buffers.
The original function had no distinct success exit and fell straight through into the err label, which previously only did mutex_unlock and "return ret". Adding queued-buffer cleanup at err must therefore be paired with an explicit success return; otherwise every successful start would also drain the buffer queue and kill streaming. Add that success return, then add rtl2832_sdr_cleanup_queued_bufs() at the err label and before each early return.
The cleanup helper takes a vb2_buffer_state argument so that the start_streaming error paths can pass VB2_BUF_STATE_QUEUED (as expected by userspace on start_streaming failure) while stop_streaming keeps its existing VB2_BUF_STATE_ERROR semantics.
This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo:
Return queued buffers on start_streaming() failure").
The err label still does not roll back power_ctrl(), frontend_ctrl(), the POWER_ON flag, or stream/URB allocations that may have happened before the failing step. Those are pre-existing leaks of a different class and are not addressed here.
--- drivers/media/dvb-frontends/rtl2832_sdr.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
drivers/media/dvb-frontends/rtl2832_sdr.c +14 -5
@@ -399,7 +399,8 @@ static int rtl2832_sdr_alloc_urbs(struct }/* Must be called with vb_queue_lock hold */ -static void rtl2832_sdr_cleanup_queued_bufs (struct rtl2832_sdr_dev *dev) +static void rtl2832_sdr_cleanup_queued_bufs (struct rtl2832_sdr_dev *dev, +enum vb2_buffer_state state) {struct platform_device *pdev = dev->pdev;unsigned long flags;
@@ -413,7 +414,7 @@ static void rtl2832_sdr_cleanup_queued_b buf =list_entry (dev->queued_bufs.next, struct rtl2832_sdr_frame_buf, list);list_del (&buf->list); -vb2_buffer_done (&buf->vb.vb2_buf,VB2_BUF_STATE_ERROR ); +vb2_buffer_done (&buf->vb.vb2_buf, state); }spin_unlock_irqrestore (&dev->queued_bufs_lock, flags); }
@@ -855,11 +856,15 @@ static int rtl2832_sdr_start_streaming(sdev_dbg (&pdev->dev,"\n" ); -if (!dev->udev) +if (!dev->udev) { +rtl2832_sdr_cleanup_queued_bufs (dev,VB2_BUF_STATE_QUEUED );return -ENODEV ; + } -if (mutex_lock_interruptible (&dev->v4l2_lock)) +if (mutex_lock_interruptible (&dev->v4l2_lock)) { +rtl2832_sdr_cleanup_queued_bufs (dev,VB2_BUF_STATE_QUEUED );return -ERESTARTSYS ; + }if (d->props->power_ctrl) d->props->power_ctrl (d,1 );
@@ -900,7 +905,11 @@ static int rtl2832_sdr_start_streaming(sif (ret) goto err; +mutex_unlock (&dev->v4l2_lock); +return 0 ; + err: +rtl2832_sdr_cleanup_queued_bufs (dev,VB2_BUF_STATE_QUEUED );mutex_unlock (&dev->v4l2_lock);return ret;
@@ -920,7 +929,7 @@ static void rtl2832_sdr_stop_streaming(srtl2832_sdr_kill_urbs (dev);rtl2832_sdr_free_urbs (dev);rtl2832_sdr_free_stream_bufs (dev); -rtl2832_sdr_cleanup_queued_bufs (dev); +rtl2832_sdr_cleanup_queued_bufs (dev,VB2_BUF_STATE_ERROR );rtl2832_sdr_unset_adc (dev);/* sleep tuner */
Greg Kroah-Hartman
maintainerPATCH 513/744 media: rzg2l-cru: Skip ICnMC configuration when ICnSVC is used
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tommaso Merciai <[email protected]>
commit cd4ce68875f406b0cf3f5a94c0fd22989689222f upstream.
When the CRU is configured to use ICnSVC for virtual channel mapping, as on the RZ/{G3E, V2H/P} SoC, the ICnMC register must not be programmed.
Return early after setting up ICnSVC to avoid overriding the ICnMC register, which is not applicable in this mode.
This prevents unintended register programming when ICnSVC is enabled.
--- drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h | 1 drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 17 +++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-)
drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h +1 -0
@@ -60,6 +60,7 @@#define ICnMC_CSCTHR BIT(5)#define ICnMC_INF (x) ((x) << 16)#define ICnMC_VCSEL (x) ((x) << 22) +#define ICnMC_VCSEL_MASK GENMASK(23, 22)#define ICnMC_INF_MASK GENMASK(21, 16)#define ICnMS_IA BIT(2)
drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +11 -6
@@ -262,19 +262,24 @@ static void rzg2l_cru_csi2_setup(struct u8 csi_vc) {const struct rzg2l_cru_info *info = cru->info; -u32 icnmc =ICnMC_INF (ip_fmt->datatype); +u32 icnmc =rzg2l_cru_read (cru, info->image_conv) & ~(ICnMC_INF_MASK | + ICnMC_VCSEL_MASK); + icnmc |=ICnMC_INF (ip_fmt->datatype); +/* +* VC filtering goes through SVC register on G3E/V2H. +* +* FIXME: virtual channel filtering is likely broken and only VC=0 +* works. +*/ if (cru->info->regs[ICnSVC]) {rzg2l_cru_write (cru, ICnSVCNUM, csi_vc);rzg2l_cru_write (cru, ICnSVC,ICnSVC_SVC0 (0 ) |ICnSVC_SVC1 (1 ) |ICnSVC_SVC2 (2 ) |ICnSVC_SVC3 (3 )); + }else { + icnmc |=ICnMC_VCSEL (csi_vc); } - icnmc |=rzg2l_cru_read (cru, info->image_conv) & ~ICnMC_INF_MASK; - -/* Set virtual channel CSI2 */ - icnmc |=ICnMC_VCSEL (csi_vc); -rzg2l_cru_write (cru, info->image_conv, icnmc); }
Greg Kroah-Hartman
maintainerPATCH 514/744 media: rzv2h-ivc: Wait for frame end in stop_streaming
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacopo Mondi <[email protected]>
commit b4e6ddce16b8ae0ddbec7c96c675779260ad4697 upstream.
The rzv2h-ivc driver fails to handle back-2-back streaming sessions that do not go through a peripheral reset. As the driver uses an autosuspend delay of 2 seconds, it is quite possible that two consecutive streaming sessions won't go through a suspend/resume sequence.
If the peripheral is not reset the second streaming session hangs and no frames are delivered to the ISP.
This is because the stop_streaming() procedure implemented in the driver doesn't match what's prescribed by the chip datasheet:
1) The chip manual suggests to poll the RZV2H_IVC_FM_INT_STAT_STPEND bit of RZV2H_IVC_REG_FM_INT_STA instead of polling on RZV2H_IVC_REG_FM_STOP and prescribes to clear the bit after polling has completed
2) More importantly: the RZV2H_IVC_REG_FM_STOP_FSTOP bit has to be set on RZV2H_IVC_REG_FM_STOP -only- if a frame transfer to the ISP is in progress. Setting the RZV2H_IVC_REG_FM_STOP_FSTOP bit when no frame is being transferred causes the polling routine to timeout and the next streaming session fails to start
As a frame transfer of an image in 1920x1080@10bi takes 5 milliseconds at most, it is quite possible that the frame transfer completion interrupt races with the stop procedure.
Instead of forcing a frame transfer abort, simply wait for the in-progress transfer to complete by polling the ivc->vvalid_ifp status variable in an hand-rolled loop that allows to inspect the variable while holding the spinlock, to allow the irq handler to complete the current buffer.
With this change, streaming back-2-back without suspending the peripheral works successfully.
--- .../renesas/rzv2h-ivc/rzv2h-ivc-video.c | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-)
drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-video.c +26 -5
@@ -297,12 +297,33 @@ static int rzv2h_ivc_start_streaming(struct vb2_queue *q, unsigned int count)static void rzv2h_ivc_stop_streaming (struct vb2_queue *q) {struct rzv2h_ivc *ivc =vb2_get_drv_priv (q); -u32 val =0 ; +unsigned int loop =5 ; -rzv2h_ivc_write (ivc,RZV2H_IVC_REG_FM_STOP ,RZV2H_IVC_REG_FM_STOP_FSTOP ); -readl_poll_timeout (ivc->base +RZV2H_IVC_REG_FM_STOP , - val, !(val &RZV2H_IVC_REG_FM_STOP_FSTOP ), -10 *USEC_PER_MSEC ,250 *USEC_PER_MSEC ); +/* +* If no frame transfer is in progress, we're done, otherwise, wait for +* the transfer to complete. +* +* Transferring a 1920x1080@10bit frame to the ISP takes less than 5 +* msec so sleep for 2.5 msec (+- 25%) and give up after 5 attempts. +*/ +for (; loop >0 ; loop--) { +unsigned int vvalid_ifp; + +/* +* Inspect the ivc->vvalid_ifp variable holding the spinlock not +* to the race with the rzv2h_ivc_buffer_done() call in the irq +* handler. +*/ + scoped_guard(spinlock_irq, &ivc->spinlock) { + vvalid_ifp = ivc->vvalid_ifp; + } +if (vvalid_ifp <2 ) +break ; + +fsleep (2500 ); + } +if (!loop) +dev_err (ivc->dev,"Failed to stop streaming\n" );rzv2h_ivc_return_buffers (ivc,VB2_BUF_STATE_ERROR );video_device_pipeline_stop (&ivc->vdev.dev);
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 515/744 media: saa7134: Fix a possible memory leak in saa7134_video_init1
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ma Ke <[email protected]>
commit f86ed548386e3050e5f8f25b450d09dc009d9a88 upstream.
In saa7134_video_init1(), the return value of the first saa7134_pgtable_alloc() is not checked. If it fails, the function continues as if successful, leaving the driver with an invalid page table. Additionally, if vb2_queue_init() for the VBI queue fails after the video queue page table has been allocated, the allocated memory is not freed before returning. The second saa7134_pgtable_alloc() also lacks a return value check. Errors occur during device probing before the device is fully registered, the normal cleanup path in saa7134_finidev() is not executed, leading to memory leaks and potential use of uninitialized DMA resources.
Check the return value of both saa7134_pgtable_alloc() calls and propagate errors. On failure of any later step, free allocated page tables to avoid memory leaks. Ensure control handlers are also released on error to prevent further resource leakage.
Found by code review.
--- drivers/media/pci/saa7134/saa7134-video.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
drivers/media/pci/saa7134/saa7134-video.c +20 -5
@@ -1714,8 +1714,10 @@ int saa7134_video_init1(struct saa7134_d q->dev = &dev->pci->dev; ret =vb2_queue_init (q);if (ret) -return ret; -saa7134_pgtable_alloc (dev->pci, &dev->video_q.pt); + goto err_free_ctrl; + ret =saa7134_pgtable_alloc (dev->pci, &dev->video_q.pt); +if (ret) + goto err_free_ctrl; q = &dev->vbi_vbq; q->type =V4L2_BUF_TYPE_VBI_CAPTURE ;
@@ -1732,11 +1734,24 @@ int saa7134_video_init1(struct saa7134_d q->lock = &dev->lock; q->dev = &dev->pci->dev; ret =vb2_queue_init (q); -if (ret) -return ret; -saa7134_pgtable_alloc (dev->pci, &dev->vbi_q.pt); +if (ret) { +saa7134_pgtable_free (dev->pci, &dev->video_q.pt); + goto err_free_ctrl; + } + + ret =saa7134_pgtable_alloc (dev->pci, &dev->vbi_q.pt); +if (ret) { +saa7134_pgtable_free (dev->pci, &dev->video_q.pt); + goto err_free_ctrl; + }return 0 ; + +err_free_ctrl: +v4l2_ctrl_handler_free (&dev->ctrl_handler); +if (card_has_radio (dev)) +v4l2_ctrl_handler_free (&dev->radio_ctrl_handler); +return ret; }void saa7134_video_fini (struct saa7134_dev *dev)
Greg Kroah-Hartman
maintainerPATCH 516/744 media: stm32-dcmipp: Return queued buffers on start_streaming() failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit ffc8eec06378a340d708c889184ab3e14b57d540 upstream.
The vb2 framework hands buffers to the driver via buf_queue() before calling start_streaming(). If start_streaming() returns an error without first returning those buffers via vb2_buffer_done(), vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued buffers leak.
dcmipp_bytecap_start_streaming() returned -EINVAL when the source subdevice could not be resolved from the media graph, before pm_runtime_resume_and_get() and media_pipeline_start() had been called. The remaining error paths already converge on the err_buffer_done label, which calls dcmipp_bytecap_all_buffers_done(..., VB2_BUF_STATE_QUEUED). Jump to that label directly: the intermediate err_pm_put / err_media_pipeline_stop labels are skipped, which is correct because nothing they would undo has happened yet.
This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo:
Return queued buffers on start_streaming() failure").
--- drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c +4 -2
@@ -401,8 +401,10 @@ static int dcmipp_bytecap_start_streamin*/ if (!vcap->s_subdev) { pad =media_pad_remote_pad_first (&vcap->vdev.entity.pads[0 ]); -if (!pad || !is_media_entity_v4l2_subdev (pad->entity)) -return -EINVAL ; +if (!pad || !is_media_entity_v4l2_subdev (pad->entity)) { + ret = -EINVAL ; + goto err_buffer_done; + } vcap->s_subdev =media_entity_to_v4l2_subdev (pad->entity); vcap->s_subdev_pad_nb = pad->index; }
Greg Kroah-Hartman
maintainerPATCH 517/744 media: stm32: dcmi: unregister notifier on probe failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 084973ebd67b28f0945c5d45408f86c58b540110 upstream.
dcmi_graph_init() registers the async notifier before dcmi_probe() toggles the reset line. If reset_control_assert() or reset_control_deassert() fails afterwards, probe returns through err_cleanup and the driver core will not call dcmi_remove().
Unregister the notifier before cleaning it up on that error path, matching the successful remove path and the V4L2 async notifier lifetime rules.
--- drivers/media/platform/st/stm32/stm32-dcmi.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/platform/st/stm32/stm32-dcmi.c +1 -0
@@ -2195,6 +2195,7 @@ static int dcmi_probe(struct platform_dereturn 0 ; err_cleanup: +v4l2_async_nf_unregister (&dcmi->notifier);v4l2_async_nf_cleanup (&dcmi->notifier); err_media_entity_cleanup:media_entity_cleanup (&dcmi->vdev->entity);
Greg Kroah-Hartman
maintainerPATCH 518/744 media: sun4i-csi: Return queued buffers on start_streaming() failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit bbba3e260a62810a717b4442a3bb96d0ec0f6309 upstream.
The vb2 framework hands buffers to the driver via buf_queue() before calling start_streaming(). If start_streaming() returns an error without first returning those buffers via vb2_buffer_done(), vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued buffers leak.
sun4i_csi_start_streaming() returned -EINVAL when no matching CSI format could be found, before any setup (scratch buffer allocation, pipeline start) had been performed. The remaining error paths already converge on the err_clear_dma_queue label, which calls return_all_buffers(..., VB2_BUF_STATE_QUEUED) under csi->qlock. Jump to that label directly: the intermediate err_disable_device / err_disable_pipeline / err_free_scratch_buffer labels are skipped, which is correct because nothing they would undo has happened yet.
This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo:
Return queued buffers on start_streaming() failure").
--- drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +4 -2
@@ -234,8 +234,10 @@ static int sun4i_csi_start_streaming(strint ret; csi_fmt =sun4i_csi_find_format (&csi->fmt.pixelformat,NULL ); -if (!csi_fmt) -return -EINVAL ; +if (!csi_fmt) { + ret = -EINVAL ; + goto err_clear_dma_queue; + }dev_dbg (csi->dev,"Starting capture\n" );
Greg Kroah-Hartman
maintainerPATCH 519/744 media: synopsys: hdmirx: Fix HPD lane hold time
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Osipenko <[email protected]>
commit d1162a5adbb5e95953d460b5bde3a04cd4473fe9 upstream.
Increase time of holding HPD lane low by 50ms. This fixes EDID change not detected by source/display side.
--- drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +2 -2
@@ -506,9 +506,9 @@ static void hdmirx_hpd_ctrl(struct snps_hdmirx_writel (hdmirx_dev,CORE_CONFIG , hdmirx_dev->hpd_trigger_level_high ? en : !en); -/* 100ms delay as per HDMI spec */ +/* 100ms delay as per HDMI spec + extra 50ms to cover internal delay */ if (!en) -msleep (100 ); +msleep (100 +50 ); } static void hdmirx_write_edid_data(struct snps_hdmirx_dev *hdmirx_dev,
Greg Kroah-Hartman
maintainerPATCH 520/744 media: tegra-video: vi: fix invalid u32 return value in format lookup
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hungyu Lin <[email protected]>
commit d5b50055338e131a1a99f923ebb0361974a00f36 upstream.
tegra_get_format_fourcc_by_idx() returns a u32 but uses -EINVAL to signal an out-of-bounds index. This results in a large unsigned value being returned, which may be interpreted as a valid fourcc.
Returning 0 is not a valid fourcc either. This condition should never happen, so use WARN_ON_ONCE() to catch unexpected out-of-bounds access and return a valid fallback format instead.
--- drivers/staging/media/tegra-video/vi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/media/tegra-video/vi.c +2 -2
@@ -80,8 +80,8 @@ static int tegra_get_format_idx_by_code(static u32 tegra_get_format_fourcc_by_idx (struct tegra_vi *vi,unsigned int index) { -if (index >= vi->soc->nformats) -return -EINVAL ; +if (WARN_ON_ONCE (index >= vi->soc->nformats)) +return vi->soc->video_formats[0 ].fourcc;return vi->soc->video_formats[index].fourcc; }
Greg Kroah-Hartman
maintainerPATCH 521/744 media: ti: vpe: Fix fwnode_handle leak in vip_probe_complete()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
commit 34ca1065a4b2cf776c28d7cece6f6c9d90f7e3a3 upstream.
In vip_probe_complete(), the fwnode_handle reference is not released if the loop continues via the default switch case or if alloc_port() fails. This results in a reference count leak.
Switch to using the __free(fwnode_handle) cleanup attribute to ensure the reference is automatically released when the handle goes out of scope.
--- drivers/media/platform/ti/vpe/vip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/media/platform/ti/vpe/vip.c +4 -4
@@ -9,6 +9,7 @@*/ #include <linux/clk.h> +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/err.h>
@@ -3389,7 +3390,6 @@ static int vip_probe_complete(struct platform_device *pdev)struct vip_port *port;struct vip_dev *dev;struct device_node *parent = pdev->dev.of_node; -struct fwnode_handle *ep =NULL ;unsigned int syscon_args[5 ];int ret, i, slice_id, port_id, p;
@@ -3411,8 +3411,9 @@ static int vip_probe_complete(struct platform_device *pdev) ctrl->syscon_bit_field[i] = syscon_args[i +1 ];for (p =0 ; p < (VIP_NUM_PORTS *VIP_NUM_SLICES ); p++) { - ep =fwnode_graph_get_next_endpoint_by_regs (of_fwnode_handle (parent), - p,0 ); + struct fwnode_handle *ep __free(fwnode_handle) = +fwnode_graph_get_next_endpoint_by_regs ( +of_fwnode_handle (parent), p,0 );if (!ep)continue ;
@@ -3447,7 +3448,6 @@ static int vip_probe_complete(struct platform_device *pdev) port = dev->ports[port_id];vip_register_subdev_notify (port, ep); -fwnode_handle_put (ep); }return 0 ; }
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 522/744 media: ti: vpe: Fix the error code of devm_kzalloc() in vip_probe_slice()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
commit e8f319eae96a3d718e810d52432020a2b77f5f60 upstream.
In vip_probe_slice(), the error check for devm_kzalloc() incorrectly uses PTR_ERR_OR_ZERO() which returns 0 for NULL pointer.
Return -ENOMEM for devm_kzalloc() failure.
--- drivers/media/platform/ti/vpe/vip.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/media/platform/ti/vpe/vip.c +3 -3
@@ -3490,7 +3490,7 @@ static int vip_probe_slice(struct platform_device *pdev, int slice) parser =devm_kzalloc (&pdev->dev,sizeof (*dev->parser),GFP_KERNEL );if (!parser) -return PTR_ERR_OR_ZERO (parser); +return -ENOMEM ; parser->base = dev->base + (slice ?VIP_SLICE1_PARSER :VIP_SLICE0_PARSER );if (IS_ERR (parser->base))
@@ -3502,7 +3502,7 @@ static int vip_probe_slice(struct platform_device *pdev, int slice) dev->sc_assigned =VIP_NOT_ASSIGNED ; sc =devm_kzalloc (&pdev->dev,sizeof (*dev->sc),GFP_KERNEL );if (!sc) -return PTR_ERR_OR_ZERO (sc); +return -ENOMEM ; sc->base = dev->base + (slice ?VIP_SLICE1_SC :VIP_SLICE0_SC );if (IS_ERR (sc->base))
@@ -3514,7 +3514,7 @@ static int vip_probe_slice(struct platform_device *pdev, int slice) dev->csc_assigned =VIP_NOT_ASSIGNED ; csc =devm_kzalloc (&pdev->dev,sizeof (*dev->csc),GFP_KERNEL );if (!csc) -return PTR_ERR_OR_ZERO (csc); +return -ENOMEM ; csc->base = dev->base + (slice ?VIP_SLICE1_CSC :VIP_SLICE0_CSC );if (IS_ERR (csc->base))
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 523/744 media: ti: vpe: Fix the error code of devm_request_irq()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
commit 5e78a431a3f74c632351791d7902c60199d1ce83 upstream.
Return the actual error code from devm_request_irq() instead of incorrectly returning -ENOMEM.
--- drivers/media/platform/ti/vpe/vip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti/vpe/vip.c +1 -1
@@ -3472,7 +3472,7 @@ static int vip_probe_slice(struct platform_device *pdev, int slice) ret =devm_request_irq (&pdev->dev, dev->irq, vip_irq,0 ,VIP_MODULE_NAME , dev);if (ret <0 ) -return -ENOMEM ; +return ret;spin_lock_init (&dev->slock);mutex_init (&dev->mutex);
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 524/744 media: ti: vpe: unwind v4l2 device registration on probe error
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit e0f1c9a90ef665f2587c274a8fed59f2dfc575a6 upstream.
If the vpe_top resource is missing, vpe_probe() returns -ENODEV after v4l2_device_register() has succeeded. Probe failures do not call the driver's remove callback, so the v4l2 device remains registered on that error path.
Route that failure through the existing v4l2_device_unregister() unwind label, matching the other errors after v4l2_device_register().
--- drivers/media/platform/ti/vpe/vpe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/media/platform/ti/vpe/vpe.c +2 -1
@@ -2539,7 +2539,8 @@ static int vpe_probe(struct platform_dev "vpe_top");if (!dev->res) {dev_err (&pdev->dev,"missing 'vpe_top' resources data\n" ); -return -ENODEV ; + ret = -ENODEV ; + goto v4l2_dev_unreg; }/*
Greg Kroah-Hartman
maintainerPATCH 525/744 media: uapi: rkisp: Correct name version enum
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Niklas Söderlund <[email protected]>
commit c4c01c4fd4a3916ffdfb35ad9f511c48e289f51c upstream.
The name of the enum to hold the mapping of parameter buffer versions have a typo in the name, correct it. While this is a uAPI header the impact should be minimal as the enum is only used as a collection for the one version number supported.
--- include/uapi/linux/rkisp1-config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
include/uapi/linux/rkisp1-config.h +3 -3
@@ -1535,11 +1535,11 @@ struct rkisp1_ext_params_wdr_config { sizeof(struct rkisp1_ext_params_wdr_config))/** -* enum rksip1_ext_param_buffer_version - RkISP1 extensible parameters version +* enum rkisp1_ext_param_buffer_version - RkISP1 extensible parameters version * * @RKISP1_EXT_PARAM_BUFFER_V1: First version of RkISP1 extensible parameters */ -enum rksip1_ext_param_buffer_version { +enum rkisp1_ext_param_buffer_version {RKISP1_EXT_PARAM_BUFFER_V1 =V4L2_ISP_PARAMS_VERSION_V1 , };
@@ -1601,7 +1601,7 @@ enum rksip1_ext_param_buffer_version {* +---------------------------------------------------------------------+ * * @version: The RkISP1 extensible parameters buffer version, see -* :c:type:`rksip1_ext_param_buffer_version` +* :c:type:`rkisp1_ext_param_buffer_version` * @data_size: The RkISP1 configuration data effective size, excluding this * header * @data: The RkISP1 extensible configuration data blocks
Greg Kroah-Hartman
maintainerPATCH 526/744 media: v4l2-ctrls-request: add NULL check in v4l2_ctrl_request_complete()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergey Shtylyov <[email protected]>
commit caced3578bf9f104a4aaad8f46c4c719e705d9a6 upstream.
If CONFIG_MEDIA_CONTROLLER is undefined, media_request_object_find() will always return NULL, so its 2nd call in v4l2_ctrl_request_complete() would fail as well as the 1st one and thus cause hdl to have a wrong value (at the top of memory) and list_for_each_entry() to iterate over the garbage data located there. Add NULL check for the 2nd call and place the error cleanup at the end of v4l2_ctrl_request_complete()...
Found by Linux Verification Center (linuxtesting.org) with the Svace static analysis tool.
--- drivers/media/v4l2-core/v4l2-ctrls-request.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
drivers/media/v4l2-core/v4l2-ctrls-request.c +9 -5
@@ -348,13 +348,12 @@ void v4l2_ctrl_request_complete(struct m ret =v4l2_ctrl_handler_init (hdl, (main_hdl->nr_of_buckets -1 ) *8 );if (!ret) ret =v4l2_ctrl_request_bind (req, hdl, main_hdl); -if (ret) { -v4l2_ctrl_handler_free (hdl); -kfree (hdl); -return ; - } +if (ret) + goto error; hdl->request_is_queued = true; obj =media_request_object_find (req, &req_ops, main_hdl); +if (!obj) + goto error; } hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
@@ -389,6 +388,11 @@ void v4l2_ctrl_request_complete(struct mmutex_unlock (main_hdl->lock);media_request_object_complete (obj);media_request_object_put (obj); +return ; + +error: +v4l2_ctrl_handler_free (hdl); +kfree (hdl); }EXPORT_SYMBOL (v4l2_ctrl_request_complete);
Greg Kroah-Hartman
maintainerPATCH 527/744 media: v4l2-ctrls: validate HEVC active reference counts
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit afbe4bc252d90a6f8fad869b06d5430f615f22f9 upstream.
HEVC slice parameters are shared stateless V4L2 controls, but the common validation path does not verify the active L0/L1 reference counts before driver-specific code consumes them.
The original report came from Cedrus, but the active count bounds are not Cedrus-specific. Validate them in the common HEVC slice control path so stateless HEVC drivers get the same basic guarantees as soon as the control is queued.
Do not reject ref_idx_l0/ref_idx_l1 entries here. Existing userspace may use out-of-range sentinel values such as 0xff for missing references, and some hardware can use that information for concealment. Keep this common check limited to the active reference counts.
--- drivers/media/v4l2-core/v4l2-ctrls-core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/media/v4l2-core/v4l2-ctrls-core.c +13 -0
@@ -971,6 +971,7 @@ static int std_validate_compound(const sstruct v4l2_ctrl_hevc_ext_sps_st_rps *p_hevc_st_rps;struct v4l2_ctrl_hevc_sps *p_hevc_sps;struct v4l2_ctrl_hevc_pps *p_hevc_pps; +struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params;struct v4l2_area *area;
@@ -1260,6 +1261,18 @@ static int std_validate_compound(const sbreak ;case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS : + p_hevc_slice_params = p; + +if (p_hevc_slice_params->num_ref_idx_l0_active_minus1 >= +V4L2_HEVC_DPB_ENTRIES_NUM_MAX ) +return -EINVAL ; + +if (p_hevc_slice_params->slice_type !=V4L2_HEVC_SLICE_TYPE_B ) +break ; + +if (p_hevc_slice_params->num_ref_idx_l1_active_minus1 >= +V4L2_HEVC_DPB_ENTRIES_NUM_MAX ) +return -EINVAL ;break ;case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS :
Greg Kroah-Hartman
maintainerPATCH 528/744 media: v4l2-fwnode: Fix subdev owner overwritten in v4l2_async_register_subdev_sensor()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mirela Rabulea <[email protected]>
commit 06cb687a5132fcffe624c0070576ab852ac6b568 upstream.
The v4l2 helper v4l2_async_register_subdev_sensor() calls v4l2_async_register_subdev(), which is a macro that expands to __v4l2_async_register_subdev(sd,THIS_MODULE). Since the macro is expanded inside v4l2-fwnode.c, THIS_MODULE resolves to the v4l2-fwnode module rather than the sensor driver module that originally set sd->owner. When v4l2-fwnode is built-in, THIS_MODULE evaluates to NULL, which then overwrites the sensor driver's owner with NULL.
This causes the problem that the sensor module's reference count is never incremented during async registration, so the module can be removed while the subdevice is still in use by a notifier (e.g., a CSI-2 receiver bridge driver).
Fix this by renaming v4l2_async_register_subdev_sensor() to __v4l2_async_register_subdev_sensor() with an added explicit module argument and introducing a wrapper macro:
#define v4l2_async_register_subdev_sensor(sd) \
__v4l2_async_register_subdev_sensor(sd, THIS_MODULE)This ensures the sensor driver module is properly referenced even when the sensor driver does not init the owner field before calling v4l2_async_register_subdev_sensor() and prevents premature module removal.
--- drivers/media/v4l2-core/v4l2-fwnode.c | 6 +++--- include/media/v4l2-async.h | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-)
drivers/media/v4l2-core/v4l2-fwnode.c +3 -3
@@ -1256,7 +1256,7 @@ v4l2_async_nf_parse_fwnode_sensor(structreturn 0 ; } -int v4l2_async_register_subdev_sensor (struct v4l2_subdev *sd) +int __v4l2_async_register_subdev_sensor (struct v4l2_subdev *sd,struct module *module) {struct v4l2_async_notifier *notifier;int ret;
@@ -1282,7 +1282,7 @@ int v4l2_async_register_subdev_sensor(stif (ret <0 ) goto out_cleanup; - ret =v4l2_async_register_subdev (sd); + ret =__v4l2_async_register_subdev (sd, module);if (ret <0 ) goto out_unregister;
@@ -1300,7 +1300,7 @@ out_cleanup:return ret; } -EXPORT_SYMBOL_GPL (v4l2_async_register_subdev_sensor); +EXPORT_SYMBOL_GPL (__v4l2_async_register_subdev_sensor);MODULE_DESCRIPTION ("V4L2 fwnode binding parsing library" );MODULE_LICENSE ("GPL" );
include/media/v4l2-async.h +3 -1
@@ -333,8 +333,10 @@ int __v4l2_async_register_subdev(struct* An error is returned if the module is no longer loaded on any attempts * to register it. */ +#define v4l2_async_register_subdev_sensor (sd) \ + __v4l2_async_register_subdev_sensor(sd, THIS_MODULE)int __must_check -v4l2_async_register_subdev_sensor (struct v4l2_subdev *sd); +__v4l2_async_register_subdev_sensor (struct v4l2_subdev *sd,struct module *module);/** * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous
Greg Kroah-Hartman
maintainerPATCH 529/744 media: v4l2-subdev: Fail {enable,disable}_streams and s_streaming nicely
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sakari Ailus <[email protected]>
commit 0bcbfd1c1142d85faef8df5cb679d37f71394c5f upstream.
If a sub-device does not set enable_streams() and disable_streams() pad ops while it sets the s_stream() video op to v4l2_subdev_s_stream_helper(), enabling or disabling streaming either way on the sub-device will result calling v4l2_subdev_s_stream_helper() and v4l2_subdev_{enable,disable}_streams() recursively, exhausting the stack. Return -ENOIOCTLCMD in this case to handle the situation gracefully.
--- drivers/media/v4l2-core/v4l2-subdev.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/media/v4l2-core/v4l2-subdev.c +4 -0
@@ -2504,6 +2504,10 @@ int v4l2_subdev_s_stream_helper(struct vu64 source_mask =0 ;int pad_index =-1 ; +if (WARN_ON (!v4l2_subdev_has_op (sd, pad, enable_streams) || + !v4l2_subdev_has_op (sd, pad, disable_streams))) +return -ENOIOCTLCMD ; +/* * Find the source pad. This helper is meant for subdevs that have a * single source pad, so failures shouldn't happen, but catch them
Greg Kroah-Hartman
maintainerPATCH 530/744 media: vb2: use ssize_t for vb2_read/vb2_write
In reply to Greg Kroah-Hartman7.1-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
@@ -2990,8 +2990,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;
@@ -3154,15 +3154,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
@@ -1093,8 +1093,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_write() - implements write() syscall logic. * @q: pointer to &struct vb2_queue with videobuf2 queue.
@@ -1103,8 +1103,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 531/744 media: verisilicon: Export only needed pixels formats
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Gaignard <[email protected]>
commit e0f5d6ae76423ec5b6f97c7c3e1f02187b988afd upstream.
Some pixel formats can only be produced if the decoder outputs reference pictures directly. In some cases, such as AV1 film-grain, the use of the post-processor is strictly required. In this case, only enumerate the post-processor supported formats. The exception is when V4L2_FMTDESC_FLAG_ENUM_ALL is set, in this case, we enumerate everything regardless of the state.
--- drivers/media/platform/verisilicon/hantro_v4l2.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/media/platform/verisilicon/hantro_v4l2.c +5 -1
@@ -222,6 +222,7 @@ static int vidioc_enum_fmt(struct file *unsigned int num_fmts, i, j =0 ;bool skip_mode_none, enum_all_formats;u32 index = f->index & ~V4L2_FMTDESC_FLAG_ENUM_ALL ; +bool need_postproc = ctx->need_postproc;/* * If the V4L2_FMTDESC_FLAG_ENUM_ALL flag is set, we want to enumerate all
@@ -230,6 +231,9 @@ static int vidioc_enum_fmt(struct file * enum_all_formats = !!(f->index &V4L2_FMTDESC_FLAG_ENUM_ALL ); f->index = index; +if (enum_all_formats) + need_postproc =HANTRO_AUTO_POSTPROC ; +/* * When dealing with an encoder: * - on the capture side we want to filter out all MODE_NONE formats.
@@ -242,7 +246,7 @@ static int vidioc_enum_fmt(struct file **/ skip_mode_none = capture == ctx->is_encoder; - formats =hantro_get_formats (ctx, &num_fmts,HANTRO_AUTO_POSTPROC ); + formats =hantro_get_formats (ctx, &num_fmts, need_postproc);for (i =0 ; i < num_fmts; i++) {bool mode_none = formats[i].codec_mode ==HANTRO_MODE_NONE ; fmt = &formats[i];
Greg Kroah-Hartman
maintainerPATCH 532/744 media: vidtv: fix reference leak on failed device registration
In reply to Greg Kroah-Hartman7.1-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
@@ -594,8 +594,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 533/744 media: vimc: fix reference leak on failed device registration
In reply to Greg Kroah-Hartman7.1-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
@@ -421,6 +421,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 534/744 media: vivid: add vivid_update_reduced_fps()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hans Verkuil <[email protected]>
commit 1d793a29efb4260f90913f5287939bf95573b073 upstream.
Don't call vivid_update_format_cap() when switching to/from reduced fps for HDMI inputs: that will also reset the format, which is overkill for this.
Make a new vivid_update_reduced_fps() function that just updates the dev->timeperframe_vid_cap.
--- drivers/media/test-drivers/vivid/vivid-ctrls.c | 3 +- drivers/media/test-drivers/vivid/vivid-vid-cap.c | 32 +++++++++++++---------- drivers/media/test-drivers/vivid/vivid-vid-cap.h | 1 3 files changed, 22 insertions(+), 14 deletions(-)
drivers/media/test-drivers/vivid/vivid-ctrls.c +2 -1
@@ -609,7 +609,8 @@ static int vivid_vid_cap_s_ctrl(struct vbreak ;case VIVID_CID_REDUCED_FPS : dev->reduced_fps = ctrl->val; -vivid_update_format_cap (dev, true); +if (dev->input_type[dev->input] ==HDMI ) +vivid_update_reduced_fps (dev);break ;case VIVID_CID_HAS_CROP_CAP : dev->has_crop_cap = ctrl->val;
drivers/media/test-drivers/vivid/vivid-vid-cap.c +19 -13
@@ -364,6 +364,24 @@ static enum tpg_pixel_aspect vivid_get_preturn TPG_PIXEL_ASPECT_SQUARE ; } +void vivid_update_reduced_fps (struct vivid_dev *dev) +{ +struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; +unsigned int size =V4L2_DV_BT_FRAME_WIDTH (bt) *V4L2_DV_BT_FRAME_HEIGHT (bt); +u64 pixelclock; + +if (dev->reduced_fps &&can_reduce_fps (bt)) { + pixelclock =div_u64 (bt->pixelclock *1000 ,1001 ); + bt->flags |=V4L2_DV_FL_REDUCED_FPS ; + }else { + pixelclock = bt->pixelclock; + bt->flags &= ~V4L2_DV_FL_REDUCED_FPS ; + } + dev->timeperframe_vid_cap = (struct v4l2_fract ) { + size /100 , (u32 )pixelclock /100 + }; +} +/* * Called whenever the format has to be reset which can occur when * changing inputs, standard, timings, etc.
@@ -372,8 +390,6 @@ void vivid_update_format_cap(struct vivi {struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;u32 dims[V4L2_CTRL_MAX_DIMS ] = {}; -unsigned size; -u64 pixelclock;switch (dev->input_type[dev->input]) {case WEBCAM :
@@ -402,17 +418,7 @@ void vivid_update_format_cap(struct vivicase HDMI : dev->src_rect.width = bt->width; dev->src_rect.height = bt->height; - size =V4L2_DV_BT_FRAME_WIDTH (bt) *V4L2_DV_BT_FRAME_HEIGHT (bt); -if (dev->reduced_fps &&can_reduce_fps (bt)) { - pixelclock =div_u64 (bt->pixelclock *1000 ,1001 ); - bt->flags |=V4L2_DV_FL_REDUCED_FPS ; - }else { - pixelclock = bt->pixelclock; - bt->flags &= ~V4L2_DV_FL_REDUCED_FPS ; - } - dev->timeperframe_vid_cap = (struct v4l2_fract ) { - size /100 , (u32 )pixelclock /100 - }; +vivid_update_reduced_fps (dev);if (bt->interlaced) dev->field_cap =V4L2_FIELD_ALTERNATE ;else
drivers/media/test-drivers/vivid/vivid-vid-cap.h +1 -0
@@ -9,6 +9,7 @@#define _VIVID_VID_CAP_H_void vivid_update_quality (struct vivid_dev *dev); +void vivid_update_reduced_fps (struct vivid_dev *dev);void vivid_update_format_cap (struct vivid_dev *dev,bool keep_controls);void vivid_update_outputs (struct vivid_dev *dev);void vivid_update_connected_outputs (struct vivid_dev *dev);
Greg Kroah-Hartman
maintainerPATCH 535/744 media: vivid: check for vb2_is_busy() when toggling caps
In reply to Greg Kroah-Hartman7.1-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
@@ -613,14 +613,20 @@ static int vivid_vid_cap_s_ctrl(struct vvivid_update_reduced_fps (dev);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 ;
@@ -1117,14 +1123,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
@@ -391,6 +391,12 @@ void vivid_update_format_cap(struct vivistruct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;u32 dims[V4L2_CTRL_MAX_DIMS ] = {}; +/* +* 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
@@ -214,6 +214,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 536/744 media: vivid: fix cleanup bugs in vivid_init()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit a07c179a92e949172ca52f6d4a13202ea88cd4b7 upstream.
When platform_device_register() fails in vivid_init(), the embedded struct device in vivid_pdev has already been initialized by device_initialize(), but the failure path jumps to free_output_strings without dropping the device reference for the current platform device:
vivid_init()
-> platform_device_register(&vivid_pdev)
-> device_initialize(&vivid_pdev.dev)
-> setup_pdev_dma_masks(&vivid_pdev)
-> platform_device_add(&vivid_pdev)This leads to a reference leak when platform_device_register() fails. Fix this by calling platform_device_put() before jumping to the common cleanup path.
Also, the unreg_driver label incorrectly calls platform_driver_register() instead of platform_driver_unregister(), which breaks cleanup when workqueue creation fails after successful driver registration. Fix that as well.
The reference leak was identified by a static analysis tool I developed and confirmed by manual review. The incorrect cleanup call was found during code inspection.
--- drivers/media/test-drivers/vivid/vivid-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/media/test-drivers/vivid/vivid-core.c +4 -2
@@ -2289,8 +2289,10 @@ static int __init vivid_init(void) } } ret =platform_device_register (&vivid_pdev); -if (ret) +if (ret) { +platform_device_put (&vivid_pdev); goto free_output_strings; + } ret =platform_driver_register (&vivid_pdrv);if (ret) goto unreg_device;
@@ -2311,7 +2313,7 @@ static int __init vivid_init(void) destroy_hdmi_wq:destroy_workqueue (update_hdmi_ctrls_workqueue); unreg_driver: -platform_driver_register (&vivid_pdrv); +platform_driver_unregister (&vivid_pdrv); unreg_device:platform_device_unregister (&vivid_pdev); free_output_strings:
Greg Kroah-Hartman
maintainerPATCH 537/744 media: vpif_capture: fix OF node reference imbalance
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 2282f979560af6bbc8ee2c1ee8663197312cee5b upstream.
The driver reuses the OF node of the parent device but fails to take another reference to balance the one dropped by the platform bus code when unbinding the parent and releasing the child devices.
Fix this by using the intended helper for reusing OF nodes.
--- drivers/media/platform/ti/davinci/vpif_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti/davinci/vpif_capture.c +1 -1
@@ -1498,7 +1498,7 @@ vpif_capture_get_pdata(struct platform_d* video ports & endpoints data. */ if (pdev->dev.parent && pdev->dev.parent->of_node) - pdev->dev.of_node = pdev->dev.parent->of_node; +device_set_of_node_from_dev (&pdev->dev, pdev->dev.parent);if (!IS_ENABLED (CONFIG_OF ) || !pdev->dev.of_node)return pdev->dev.platform_data;
Greg Kroah-Hartman
maintainerPATCH 538/744 ALSA: hda/realtek: Fix speakers on Lunnen Ground 14
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikita Maksimov <[email protected]>
commit 5c3f8dac531b454bf67b6ee3c2aac89f0aaaef74 upstream.
The firmware on the Lunnen Ground 14 marks pin 0x1b as unused even though the internal speakers are connected to it. As a result, the speakers are not detected.
Add a pin configuration quirk for PCI subsystem ID 2782:a212 to configure pin 0x1b as an internal speaker.
The pin configuration was tested on a Lunnen Ground 14 (DMI product LL4FA) with an ALC269VC codec. The internal speakers and microphone work as expected.
--- sound/hda/codecs/realtek/alc269.c | 9 +++++++++ 1 file changed, 9 insertions(+)
sound/hda/codecs/realtek/alc269.c +9 -0
@@ -3891,6 +3891,7 @@ enum {ALC269_FIXUP_DMIC_THINKPAD_ACPI ,ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13 ,ALC269VC_FIXUP_INFINIX_Y4_MAX , +ALC269VC_FIXUP_LUNNEN_GROUND_14 ,ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO ,ALC255_FIXUP_ACER_MIC_NO_PRESENCE , ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
@@ -4345,6 +4346,13 @@ static const struct hda_fixup alc269_fix .chained = true, .chain_id =ALC269_FIXUP_LIMIT_INT_MIC_BOOST }, + [ALC269VC_FIXUP_LUNNEN_GROUND_14] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl []) { + {0x1b ,0x90170150 },/* internal speaker */ + { } + }, + }, [ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl []) {
@@ -7875,6 +7883,7 @@ static const struct hda_quirk alc269_fixSND_PCI_QUIRK (0x2782 ,0x1705 ,"MEDION E15433" ,ALC269VC_FIXUP_INFINIX_Y4_MAX ),SND_PCI_QUIRK (0x2782 ,0x1707 ,"Vaio VJFE-ADL" ,ALC298_FIXUP_SPK_VOLUME ),SND_PCI_QUIRK (0x2782 ,0x4900 ,"MEDION E15443" ,ALC233_FIXUP_MEDION_MTL_SPK ), +SND_PCI_QUIRK (0x2782 ,0xa212 ,"Lunnen Ground 14" ,ALC269VC_FIXUP_LUNNEN_GROUND_14 ),SND_PCI_QUIRK (0x7017 ,0x2014 ,"Star Labs StarFighter" ,ALC233_FIXUP_STARLABS_STARFIGHTER ),SND_PCI_QUIRK (0x8086 ,0x2074 ,"Intel NUC 8" ,ALC233_FIXUP_INTEL_NUC8_DMIC ), SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
Greg Kroah-Hartman
maintainerPATCH 539/744 ALSA: seq: close a re-opened queue timer in the destructor
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit 2c4dc0ed50b05cd847a4b34b8cebf0775f19aeb9 upstream.
queue_delete() closes the queue timer, then frees it. snd_seq_timer_close() clears q->timer->timeri. snd_use_lock_sync() then drains borrowers, and snd_seq_timer_delete() frees q->timer.
A borrower can re-open the timer inside that window. A SET_QUEUE_CLIENT that took a queueptr() use_lock reference before the queue was unlinked runs snd_seq_timer_open() after the close. Open refuses re-open only while timeri is set, and the close just cleared it, so it re-opens timeri.
snd_seq_timer_delete() does not close that instance. Its snd_seq_timer_stop() is a no-op, because running was cleared first. So it frees q->timer with the instance still live. The queue is freed next.
The instance stays on the global timer with callback_data pointing at the freed queue. A non-owner START on the unlocked queue arms it. The next tick derefs the freed queue in snd_seq_timer_interrupt().
Reachable by an unprivileged user with access to /dev/snd/seq. No CAP and no queue ownership required.
Close any lingering instance in the destructor. There, ->timeri can no longer change: the queue is unlinked and all use_lock borrowers have drained, so no snd_seq_queue_use() can re-open it. Close it before clearing q->timer. snd_timer_close() waits for any in-flight snd_seq_timer_interrupt() to finish, and that callback still reads q->timer (via snd_seq_check_queue()), so q->timer must stay valid until it drains.
--- sound/core/seq/seq_timer.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
sound/core/seq/seq_timer.c +12 -1
@@ -61,12 +61,23 @@ struct snd_seq_timer *snd_seq_timer_new(void snd_seq_timer_delete (struct snd_seq_timer **tmr) {struct snd_seq_timer *t = *tmr; - *tmr =NULL ; +struct snd_timer_instance *ti;if (t ==NULL ) {pr_debug ("ALSA: seq: snd_seq_timer_delete() called with NULL timer\n" );return ; } + + scoped_guard(spinlock_irq, &t->lock) { + ti = t->timeri; + t->timeri =NULL ; + } +if (ti) { +snd_timer_close (ti); +snd_timer_instance_free (ti); + } + + *tmr =NULL ; t->running =0 ;/* reset time */
Greg Kroah-Hartman
maintainerPATCH 540/744 ALSA: hda: codecs: hdmi: disable keep-alive before audio format change
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kai Vehmanen <[email protected]>
commit a3d6d3cedfe87bbd5a677d52b22ac20d28e59cf8 upstream.
When a keep-alive (KAE) silent stream is active on an Intel HDMI/DP codec, opening a real PCM stream reprograms the converter format and the audio infoframe in snd_hda_hdmi_generic_pcm_prepare(). Part of that reprogramming - the converter channel count and the channel mapping in snd_hda_hdmi_setup_audio_infoframe() - is not safe to do while a keep-alive stream is active. This is most visible when switching to a multichannel PCM configuration, where the active channel count actually changes. In that case the newly opened PCM stream plays no sound.
Add an optional hdmi_ops .prepare hook, called at the start of the PCM prepare sequence (before the format and infoframe are touched), and implement it for HSW+ to release keep-alive. Keep-alive is then re-enabled as before once the new stream has been set up, in the setup_stream op.
--- sound/hda/codecs/hdmi/hdmi.c | 3 +++ sound/hda/codecs/hdmi/hdmi_local.h | 9 +++++++++ sound/hda/codecs/hdmi/intelhdmi.c | 36 ++++++++++++++++++++++++++++++------ 3 files changed, 42 insertions(+), 6 deletions(-)
sound/hda/codecs/hdmi/hdmi.c +3 -0
@@ -1688,6 +1688,9 @@ int snd_hda_hdmi_generic_pcm_prepare(str per_pin->channels = substream->runtime->channels; per_pin->setup = true; +if (spec->ops.prepare) + spec->ops.prepare (codec, per_pin); +if (get_wcaps (codec, cvt_nid) &AC_WCAP_STRIPE ) { stripe =snd_hdac_get_stream_stripe_ctl (&codec->bus->core, substream);
sound/hda/codecs/hdmi/hdmi_local.h +9 -0
@@ -74,6 +74,15 @@ struct hdmi_ops { hda_nid_t pin_nid, int dev_id, u32 stream_tag, int format); +/* +* Optional hook invoked at the beginning of the PCM prepare +* sequence, before the audio infoframe and stream format are +* (re)programmed. Used to disable keep-alive / silent stream so +* that the format change is not done while keep-alive is active. +*/ +void (*prepare)(struct hda_codec *codec, +struct hdmi_spec_per_pin *per_pin); +void (*pin_cvt_fixup)(struct hda_codec *codec,struct hdmi_spec_per_pin *per_pin,hda_nid_t cvt_nid);
sound/hda/codecs/hdmi/intelhdmi.c +30 -6
@@ -418,6 +418,28 @@ static void intel_not_share_assigned_cvtintel_not_share_assigned_cvt (codec, pin_nid, dev_id, mux_idx); } +/* +* prepare ops override for HSW+ +* +* Disable keep-alive before the converter format and audio infoframe are +* reprogrammed by the PCM prepare sequence. Changing the audio format (e.g. +* the channel count when switching to multichannel PCM) while a keep-alive +* stream is active is not safe, so release keep-alive here, early in the +* sequence. It is re-enabled once the new stream has been set up, in +* i915_hsw_setup_stream(). +*/ +static void i915_hsw_prepare (struct hda_codec *codec, +struct hdmi_spec_per_pin *per_pin) +{ +struct hdmi_spec *spec = codec->spec; + +if (spec->silent_stream_type ==SILENT_STREAM_KAE && per_pin->silent_stream) { +silent_stream_set_kae (codec, per_pin, false); +/* wait for pending transfers in codec to clear */ +usleep_range (100 ,200 ); + } +} +/* setup_stream ops override for HSW+ */ static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, hda_nid_t pin_nid, int dev_id, u32 stream_tag,
@@ -435,15 +457,16 @@ static int i915_hsw_setup_stream(structhaswell_verify_D0 (codec, cvt_nid, pin_nid); -if (spec->silent_stream_type ==SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) { -silent_stream_set_kae (codec, per_pin, false); -/* wait for pending transfers in codec to clear */ -usleep_range (100 ,200 ); - } - res =snd_hda_hdmi_setup_stream (codec, cvt_nid, pin_nid, dev_id, stream_tag, format); +/* +* Keep-alive was disabled in i915_hsw_prepare(), re-enable it now. +* The pin lookup above resolves to the same per_pin that prepare +* used (pin_nid comes from that per_pin), so this stays balanced; a +* NULL per_pin only occurs on a lookup failure that also implies no +* active keep-alive stream to restore. +*/ if (spec->silent_stream_type ==SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {usleep_range (100 ,200 );silent_stream_set_kae (codec, per_pin, true);
@@ -607,6 +630,7 @@ static int intel_hsw_common_init(struct codec->depop_delay =0 ; codec->auto_runtime_pm =1 ; + spec->ops.prepare = i915_hsw_prepare; spec->ops.setup_stream = i915_hsw_setup_stream; spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; spec->ops.silent_stream = i915_set_silent_stream;
Greg Kroah-Hartman
maintainerPATCH 541/744 ALSA: timer: drain a slaves callback before its master detaches it
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit bdefe1346a8e6b8dc8593406dc2617e985fcbcab upstream.
snd_timer_close_locked() drains the closing instance's own in-flight callback (IFLG_CALLBACK) before freeing it, but not its slaves'. When a master instance is closed, remove_slave_links() clears each slave's ->timer; the slave's own close then reads timer == NULL and takes the branch that skips the drain entirely (snd_timer_stop_slave() also no-ops on a NULL timer). So a slave whose callback is still running when the master is closed is freed underneath the live callback, leading to use-after-free.
Drain the slaves too before remove_slave_links() severs them. snd_timer_stop() has already taken this instance off the active list, so no new slave callback can be queued. Take the slaves off the ack list so a pending one can't fire either, then wait for any that is already in flight.
--- sound/core/timer.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
sound/core/timer.c +12 -2
@@ -448,10 +448,20 @@ static void snd_timer_close_locked(strucsnd_timer_stop (timeri);if (timer) { +struct snd_timer_instance *slave; +bool busy; + timer->num_instances--; -/* wait, until the active callback is finished */ +/* unqueue then drain the slaves' callbacks before remove_slave_links() severs them */ spin_lock_irq (&timer->lock); -while (timeri->flags &SNDRV_TIMER_IFLG_CALLBACK ) { +list_for_each_entry (slave, &timeri->slave_list_head, open_list) +list_del_init (&slave->ack_list); +for (;;) { + busy = timeri->flags &SNDRV_TIMER_IFLG_CALLBACK ; +list_for_each_entry (slave, &timeri->slave_list_head, open_list) + busy |= slave->flags &SNDRV_TIMER_IFLG_CALLBACK ; +if (!busy) +break ;spin_unlock_irq (&timer->lock);udelay (10 );spin_lock_irq (&timer->lock);
Greg Kroah-Hartman
maintainerPATCH 542/744 ALSA: timer: dont re-enter an instance callback that is still running
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit 70d28bfcd6224eed75986b3b987b997e59643fa4 upstream.
The userspace-driven timer (utimer) TRIGGER ioctl calls snd_timer_interrupt() directly with no serialization, so two threads triggering the same utimer can run snd_timer_interrupt() on one snd_timer concurrently.
snd_timer_process_callbacks() drops timer->lock around each instance callback and marks the in-flight callback with the single SNDRV_TIMER_IFLG_CALLBACK bit; snd_timer_close_locked() waits on that bit to drain an in-flight callback before freeing the instance. The bit cannot represent two concurrent callbacks: when a second interrupt re-queues an instance whose callback is still running, both run at once, the first to finish clears the bit, and the close-path drain then frees the instance (and its callback_data) while the other callback is still live - a use-after-free reachable by any user able to open /dev/snd/timer, both via a user timer instance and via a sequencer queue timer bound to the utimer.
snd_timer_interrupt() sets IFLG_CALLBACK before dropping timer->lock, so a concurrent interrupt already observes it under the lock. Skip re-queuing an instance (and its slaves) to the ack/sack list while its callback is in flight; the accumulated pticks are delivered on the next tick, so no event is lost.
--- sound/core/timer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
sound/core/timer.c +5 -2
@@ -894,12 +894,15 @@ void snd_timer_interrupt(struct snd_time ack_list_head = &timer->ack_list_head; else ack_list_head = &timer->sack_list_head; -if (list_empty (&ti->ack_list)) +/* don't requeue an instance whose callback is still running */ +if (list_empty (&ti->ack_list) && + !(ti->flags &SNDRV_TIMER_IFLG_CALLBACK ))list_add_tail (&ti->ack_list, ack_list_head);list_for_each_entry (ts, &ti->slave_active_head, active_list) { ts->pticks = ti->pticks; ts->resolution = resolution; -if (list_empty (&ts->ack_list)) +if (list_empty (&ts->ack_list) && + !(ts->flags &SNDRV_TIMER_IFLG_CALLBACK ))list_add_tail (&ts->ack_list, ack_list_head); } }
Greg Kroah-Hartman
maintainerPATCH 543/744 wifi: ath6kl: fix OOB access from firmware ADDBA window size
In reply to Greg Kroah-Hartman7.1-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
@@ -1723,13 +1723,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 544/744 wifi: ath6kl: fix use-after-free in aggr_reset_state()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Hodges <[email protected]>
commit ba7debb4dd6427386862220e8335a53a4bfc235d upstream.
The aggr_reset_state() function uses timer_delete() (non-synchronous) for the aggregation timer before proceeding to delete TID state and before the structure is freed by callers like aggr_module_destroy().
If the timer callback (aggr_timeout) is executing when aggr_reset_state() is called, the callback will continue to access aggr_conn fields like rx_tid[] and stat[] which may be freed immediately after by kfree(aggr_info->aggr_conn) in aggr_module_destroy().
Additionally, the timer callback can re-arm itself via mod_timer() while aggr_reset_state() is running, creating a more complex race condition.
Use timer_delete_sync() instead to ensure any running timer callback has completed before returning.
--- drivers/net/wireless/ath/ath6kl/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/ath/ath6kl/txrx.c +1 -1
@@ -1830,7 +1830,7 @@ void aggr_reset_state(struct aggr_info_creturn ;if (aggr_conn->timer_scheduled) { -timer_delete (&aggr_conn->timer); +timer_delete_sync (&aggr_conn->timer); aggr_conn->timer_scheduled = false; }
Greg Kroah-Hartman
maintainerPATCH 545/744 wifi: mwifiex: fix NULL dereference when the AP has HT-cap but no HT-oper
In reply to Greg Kroah-Hartman7.1-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 546/744 wifi: wilc1000: validate assoc response length before subtracting header
In reply to Greg Kroah-Hartman7.1-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
@@ -600,6 +600,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 547/744 wifi: mt76: mt7615: drop TXRX_NOTIFY on non-mmio buses
In reply to Greg Kroah-Hartman7.1-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").
--- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7615/mac.c +6 -0
@@ -1601,6 +1601,8 @@ bool mt7615_rx_check(struct mt76_dev *mdswitch (type) {case PKT_TYPE_TXRX_NOTIFY : +if (!mt76_is_mmio (mdev)) +return false;mt7615_mac_tx_free (dev, data, len);return false;case PKT_TYPE_TXS :
@@ -1634,6 +1636,10 @@ void mt7615_queue_rx_skb(struct mt76_devdev_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->data, skb->len);dev_kfree_skb (skb);break ;
Greg Kroah-Hartman
maintainerPATCH 548/744 wifi: mt76: mt7921: drop TXRX_NOTIFY on non-mmio buses
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Devin Wittmayer <[email protected]>
commit da4082e91acabc1498611ed8ccc53f0610baefc6 upstream.
PKT_TYPE_TXRX_NOTIFY is an mmio-only event, but mt7921_rx_check() and mt7921_queue_rx_skb() dispatch it to mt7921_mac_tx_free() on every bus. mt7921_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 USB and SDIO it is NULL, so a TXRX_NOTIFY there calls a NULL pointer in the RX worker:
BUG: kernel NULL pointer dereference, address: 0000000000000000 RIP: 0010:0x0 Call Trace: mt7921_mac_tx_free+0x64/0x310 [mt7921_common] mt7921_rx_check+0x5f/0xf0 [mt7921_common] mt76u_rx_worker+0x1b9/0x620 [mt76_usb]
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").
--- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +7 -3
@@ -569,8 +569,9 @@ bool mt7921_rx_check(struct mt76_dev *mdswitch (type) {case PKT_TYPE_TXRX_NOTIFY : -/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ -mt7921_mac_tx_free (dev, data, len);/* mmio */ +if (!mt76_is_mmio (mdev)) +return false; +mt7921_mac_tx_free (dev, data, len);return false;case PKT_TYPE_TXS :for (rxd +=2 ; rxd +8 <= end; rxd +=8 )
@@ -599,7 +600,10 @@ void mt7921_queue_rx_skb(struct mt76_devswitch (type) {case PKT_TYPE_TXRX_NOTIFY : -/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ +if (!mt76_is_mmio (mdev)) { +napi_consume_skb (skb,1 ); +break ; + }mt7921_mac_tx_free (dev, skb->data, skb->len);napi_consume_skb (skb,1 );break ;
Greg Kroah-Hartman
maintainerPATCH 549/744 wifi: mt76: mt7925: drop TXRX_NOTIFY on non-mmio buses
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Devin Wittmayer <[email protected]>
commit feeff151c83e7f0ffcdedcad5343852d23d1f6e1 upstream.
PKT_TYPE_TXRX_NOTIFY is an mmio-only event, but mt7925_rx_check() and mt7925_queue_rx_skb() dispatch it to mt7925_mac_tx_free() on every bus. mt7925_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 USB it is NULL, so a TXRX_NOTIFY there calls a NULL pointer in the RX worker:
BUG: kernel NULL pointer dereference, address: 0000000000000000 RIP: 0010:0x0 Call Trace: mt7925_mac_tx_free+0x58/0x350 [mt7925_common] mt7925_rx_check+0xe2/0x130 [mt7925_common] mt76u_rx_worker+0x1b9/0x620 [mt76_usb]
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").
--- drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7925/mac.c +7 -3
@@ -1194,8 +1194,9 @@ bool mt7925_rx_check(struct mt76_dev *mdswitch (type) {case PKT_TYPE_TXRX_NOTIFY : -/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ -mt7925_mac_tx_free (dev, data, len);/* mmio */ +if (!mt76_is_mmio (mdev)) +return false; +mt7925_mac_tx_free (dev, data, len);return false;case PKT_TYPE_TXS :for (rxd +=4 ; rxd +12 <= end; rxd +=12 )
@@ -1231,7 +1232,10 @@ void mt7925_queue_rx_skb(struct mt76_devswitch (type) {case PKT_TYPE_TXRX_NOTIFY : -/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ +if (!mt76_is_mmio (mdev)) { +napi_consume_skb (skb,1 ); +break ; + }mt7925_mac_tx_free (dev, skb->data, skb->len);napi_consume_skb (skb,1 );break ;
Greg Kroah-Hartman
maintainerPATCH 550/744 wifi: mt76: restrict NPU/PPE active checks to MMIO devices
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Devin Wittmayer <[email protected]>
commit 7981aca2bd28a1f7ad7eeab89715442a95b1f72e upstream.
mt76_npu_device_active() and mt76_ppe_device_active() read dev->mmio.npu and dev->mmio.ppe_dev. The mmio, usb and sdio bus structs share a union in struct mt76_dev, so on USB and SDIO these read unrelated data from the usb/sdio struct, which is non-NULL in practice.
mt76_npu_device_active() then returns true on USB, and mt76_rx_poll_complete() takes the offload path and skips mt76_rx_aggr_reorder(). RX A-MPDU subframes are delivered out of order and the peer's TCP stack treats that as loss: heavy retransmissions and reduced throughput in AP mode. Seen on mt7921u, mt7925u, mt76x2u and mt76x0u.
Gate both helpers on mt76_is_mmio() so they only run for the bus type that owns the mmio union member.
--- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76.h +2 -2
@@ -1735,12 +1735,12 @@ static inline int mt76_npu_send_txrx_addstatic inline bool mt76_npu_device_active (struct mt76_dev *dev) { -return !!rcu_access_pointer (dev->mmio.npu); +return mt76_is_mmio (dev) && !!rcu_access_pointer (dev->mmio.npu); }static inline bool mt76_ppe_device_active (struct mt76_dev *dev) { -return !!rcu_access_pointer (dev->mmio.ppe_dev); +return mt76_is_mmio (dev) && !!rcu_access_pointer (dev->mmio.ppe_dev); } static inline int mt76_npu_send_msg(struct airoha_npu *npu, int ifindex,
Greg Kroah-Hartman
maintainerPATCH 551/744 wifi: brcmfmac: drain bus_reset work on device removal
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 43b25879f004c98defa2776bedc6ca4763c51945 upstream.
brcmf_fw_crashed() and the debugfs "reset" entry both schedule drvr->bus_reset, whose callback recovers drvr through container_of() and dereferences it. The removal path frees drvr (brcmf_free -> wiphy_free) without draining the work, so a bus_reset callback pending or running during removal can outlive drvr.
Cancellation cannot live in brcmf_detach() or brcmf_free(): the work callback reaches teardown through the bus .reset op (PCIe brcmf_pcie_reset -> brcmf_detach; SDIO brcmf_sdio_bus_reset -> brcmf_sdiod_remove -> brcmf_free), so cancelling there would wait for the running work and deadlock.
Add a per-bus mutex (bus_reset_lock) and route all arming through brcmf_bus_schedule_reset(), which under the lock skips when the bus is marked removing. Each bus remove entry calls brcmf_bus_cancel_reset_work(), which under the same lock sets removing and cancels the work. Holding the mutex across cancel_work_sync() makes the set-removing + drain step atomic. Every producer reaches the arming path from process context -- the PCIe firmware-halt notification runs in the threaded IRQ handler (brcmf_pcie_isr_thread) and the SDIO hostmail path runs from the data workqueue -- so the mutex is taken only in sleepable contexts. Where applicable the remove entry first stops the firmware-crash producer: on PCIe mask the mailbox and synchronize_irq; on SDIO unregister the bus interrupt and cancel the data worker, which also reports firmware halts through brcmf_fw_crashed(). The mutex is initialized at bus allocation. The SDIO suspend power-off path frees drvr through the same brcmf_sdiod_remove() and takes the same lock; resume re-allows the work only on a successful re-probe.
Also guard brcmf_fw_crashed() against a NULL bus_if/drvr: it can fire before brcmf_attach() wires up drvr, and it dereferences drvr (bphy_err/brcmf_dev_coredump) before reaching the arming gate.
The bus_reset work is shared across buses, so the drain is applied to every remove path: PCIe (the .reset op introduced by the Fixes commit), SDIO (arms the same work through brcmf_fw_crashed()), and USB (via the debugfs "reset" entry). cancel_work_sync() drains a running or pending bus_reset work item before removal frees drvr, and patch 1/2 makes the scratch-buffer release safe when reset teardown has already released those DMA buffers.
This patch fixes the lifetime of the bus_reset work item itself. It does not attempt to address the separate, pre-existing lifetime of the asynchronous firmware completion started by the PCIe reset path. That callback needs its own lifetime/ownership protocol and is being tracked separately.
This issue was found by an in-house static analysis tool.
--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 13 +++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 6 + drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 46 ++++++++++++-- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 6 + drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 6 + drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h | 1 drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 3 7 files changed, 77 insertions(+), 4 deletions(-)
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +13 -0
@@ -1069,6 +1069,7 @@ static int brcmf_ops_sdio_probe(struct s bus_if =kzalloc_obj (*bus_if);if (!bus_if)return -ENOMEM ; +mutex_init (&bus_if->bus_reset_lock); sdiodev =kzalloc_obj (*sdiodev);if (!sdiodev) {kfree (bus_if);
@@ -1130,6 +1131,14 @@ static void brcmf_ops_sdio_remove(structif (func->num !=1 )return ; +/* Drain bus_reset before the shared brcmf_sdiod_remove() +* teardown, which the SDIO reset callback also reaches. The +* data worker can arm bus_reset via brcmf_fw_crashed(); cancel +* it first. +*/ +brcmf_sdio_cancel_datawork (sdiodev->bus); +brcmf_bus_cancel_reset_work (bus_if); +/* only proceed with rest of cleanup if func 1 */ brcmf_sdiod_remove (sdiodev);
@@ -1204,6 +1213,8 @@ static int brcmf_ops_sdio_suspend(struct }else {/* power will be cut so remove device, probe again in resume */ brcmf_sdiod_intr_unregister (sdiodev); +brcmf_sdio_cancel_datawork (sdiodev->bus); +brcmf_bus_cancel_reset_work (bus_if); ret =brcmf_sdiod_remove (sdiodev);if (ret)brcmf_err ("Failed to remove device on suspend\n" );
@@ -1229,6 +1240,8 @@ static int brcmf_ops_sdio_resume(struct ret =brcmf_sdiod_probe (sdiodev);if (ret)brcmf_err ("Failed to probe device on resume\n" ); +else +brcmf_bus_allow_reset_work (bus_if); }else {if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported)disable_irq_wake (sdiodev->settings->bus.sdio.oob_irq_nr);
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +6 -0
@@ -9,6 +9,7 @@#include <linux/kernel.h> #include <linux/firmware.h> #include <linux/device.h> +#include <linux/mutex.h> #include "debug.h" /* IDs of the 6 default common rings of msgbuf protocol */
@@ -179,6 +180,8 @@ struct brcmf_bus {enum brcmf_fwvendor fwvid;bool always_use_fws_queue;bool wowl_supported; +bool removing;/* device removal in progress; quiesce async work */ +struct mutex bus_reset_lock;const struct brcmf_bus_ops *ops;struct brcmf_bus_msgbuf *msgbuf;
@@ -186,6 +189,9 @@ struct brcmf_bus {struct list_head list; }; +void brcmf_bus_cancel_reset_work (struct brcmf_bus *bus_if); +void brcmf_bus_allow_reset_work (struct brcmf_bus *bus_if); +/* * callback wrappers */
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +42 -4
69 lines not on this page · raw message
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +6 -0
@@ -2499,6 +2499,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, c ret = -ENOMEM ; goto fail; } +mutex_init (&bus->bus_reset_lock); bus->msgbuf =kzalloc_obj (*bus->msgbuf);if (!bus->msgbuf) { ret = -ENOMEM ;
@@ -2594,6 +2595,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)if (devinfo->ci)brcmf_pcie_intr_disable (devinfo); +if (devinfo->irq_allocated) +synchronize_irq (pdev->irq); + +brcmf_bus_cancel_reset_work (bus); +brcmf_detach (&pdev->dev);brcmf_free (&pdev->dev);
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +6 -0
@@ -4560,6 +4560,12 @@ fail:return ret; } +void brcmf_sdio_cancel_datawork (struct brcmf_sdio *bus) +{ +if (bus) +cancel_work_sync (&bus->datawork); +} +/* Detach and free everything */ void brcmf_sdio_remove (struct brcmf_sdio *bus) {
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +1 -0
@@ -361,6 +361,7 @@ int brcmf_sdiod_remove(struct brcmf_sdioint brcmf_sdio_probe (struct brcmf_sdio_dev *sdiodev);void brcmf_sdio_remove (struct brcmf_sdio *bus);void brcmf_sdio_isr (struct brcmf_sdio *bus,bool in_isr); +void brcmf_sdio_cancel_datawork (struct brcmf_sdio *bus);void brcmf_sdio_wd_timer (struct brcmf_sdio *bus,bool active);void brcmf_sdio_wowl_config (struct device *dev,bool enabled);
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +3 -0
@@ -1260,6 +1260,7 @@ static int brcmf_usb_probe_cb(struct brc ret = -ENOMEM ; goto fail; } +mutex_init (&bus->bus_reset_lock); bus->dev = dev; bus_pub->bus = bus;
@@ -1329,6 +1330,8 @@ brcmf_usb_disconnect_cb(struct brcmf_usbreturn ;brcmf_dbg (USB ,"Enter, bus_pub %p\n" , devinfo); +brcmf_bus_cancel_reset_work (devinfo->bus_pub.bus); +brcmf_detach (devinfo->dev);brcmf_free (devinfo->dev);kfree (devinfo->bus_pub.bus);
Greg Kroah-Hartman
maintainerPATCH 552/744 wifi: brcmfmac: make release_scratchbuffers idempotent
In reply to Greg Kroah-Hartman7.1-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
@@ -1383,16 +1383,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 553/744 wifi: brcmfmac: set F2 blocksize to 256 for BCM43752
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: LiangCheng Wang <[email protected]>
commit 29ab31f3f27157648f2f7e6d5e1fd9792fdf0614 upstream.
The BCM43752 is not reliable with the default 512-byte SDIO function 2 block size: on an i.MX8MP board with an AMPAK AP6275S module at SDR104 / 200 MHz, an iperf TX stress test kills WLAN within seconds:
mmc_submit_one: CMD53 sg block write failed -84
brcmf_sdio_dpc: failed backplane access over SDIO, halting operation
Commit d2587c57ffd8 ("brcmfmac: add 43752 SDIO ids and initialization") set up the 43752 like the 4373 for the F2 watermark but missed the F2 block size, which the 4373 limits to 256 bytes. The vendor driver (bcmdhd) also programs a 256-byte F2 block size for this chip and runs the same hardware without errors.
Group the 43752 with the 4373, matching the F2 watermark handling. With this change a 10-minute bidirectional iperf3 soak completes with zero SDIO errors at ~270 Mbit/s in each direction.
Backporting note: kernels before v6.18 name this id SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, so on those trees the case label added by this patch must be adjusted to that name. Cherry-picking the rename commit 74e2ef72bd4b ("wifi: brcmfmac: fix 43752 SDIO FWVID incorrectly labelled as Cypress (CYW)") first is not a clean
alternative: on trees before v6.17 its context collides with the 43751 additions, and trees before v6.2 lack the FWVID framework it touches.
--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +1 -0
@@ -911,6 +911,7 @@ int brcmf_sdiod_probe(struct brcmf_sdio_return ret; }switch (sdiodev->func2->device) { +case SDIO_DEVICE_ID_BROADCOM_43752 :case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373 : f2_blksz =SDIO_4373_FUNC2_BLOCKSIZE ;break ;
Greg Kroah-Hartman
maintainerPATCH 554/744 wifi: ath11k: fix refcount leak in ath11k_ahb_fw_resources_init()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 0e120ee0822b7cc650bd7b29682a34e137cec10d upstream.
of_get_child_by_name() returns a node pointer with refcount incremented, but the error path when ath11k_ahb_setup_msa_resources() fails does not release it. Add the missing of_node_put() to avoid leaking the reference.
--- drivers/net/wireless/ath/ath11k/ahb.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/ath/ath11k/ahb.c +1 -0
@@ -996,6 +996,7 @@ static int ath11k_ahb_fw_resources_init( ret =ath11k_ahb_setup_msa_resources (ab);if (ret) {ath11k_err (ab,"failed to setup msa resources\n" ); +of_node_put (node);return ret; }
Greg Kroah-Hartman
maintainerPATCH 555/744 wifi: ath12k: fix NULL pointer dereference in rhash table destroy
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jose Ignacio Tornos Martinez <[email protected]>
commit 70231dcd782201579990ded73e0435d18bb524ca upstream.
When unbinding the ath12k driver, kernel NULL pointer dereferences occur in irq_work_sync() called from rhashtable_destroy().
Two hash tables are affected:
1. ath12k_link_sta hash table in ath12k_base
2. ath12k_dp_link_peer hash table in ath12k_dp
The issue happens because the destroy functions are called unconditionally in cleanup paths, but the hash tables are only initialized late in their respective init functions. If the device was never fully started or if the init functions failed before initializing the hash tables, the pointers will be NULL. The issues are always reproducible from a VM because the MSI addressing initialization is failing.
Call trace for ath12k_link_sta_rhash_tbl_destroy:
RIP: irq_work_sync+0x1e/0x70 rhashtable_destroy+0x12/0x60 ath12k_link_sta_rhash_tbl_destroy+0x19/0x40 [ath12k] ath12k_core_stop+0xe/0x80 [ath12k] ath12k_core_hw_group_cleanup+0x6b/0xb0 [ath12k] ath12k_pci_remove+0x60/0x110 [ath12k]
Call trace for ath12k_dp_link_peer_rhash_tbl_destroy:
RIP: irq_work_sync+0x1e/0x70 rhashtable_destroy+0x12/0x60 ath12k_dp_link_peer_rhash_tbl_destroy+0x29/0x50 [ath12k] ath12k_dp_cmn_device_deinit+0x21/0x140 [ath12k] ath12k_core_hw_group_cleanup+0x6b/0xb0 [ath12k] ath12k_pci_remove+0x60/0x110 [ath12k]
Fix this by adding NULL checks before calling rhashtable_destroy() in both destroy functions.
The NULL check approach was chosen because the rhashtable pointer serves as the initialization state indicator. The init can fail at various points, leaving some components uninitialized. Checking the pointer directly is simpler than adding separate state flags that would need synchronization.
--- drivers/net/wireless/ath/ath12k/dp_peer.c | 7 +++++-- drivers/net/wireless/ath/ath12k/peer.c | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath12k/dp_peer.c +5 -2
@@ -274,11 +274,14 @@ int ath12k_dp_link_peer_rhash_tbl_init(svoid ath12k_dp_link_peer_rhash_tbl_destroy (struct ath12k_dp *dp) { -mutex_lock (&dp->link_peer_rhash_tbl_lock); +guard (mutex)(&dp->link_peer_rhash_tbl_lock); + +if (!dp->rhead_peer_addr) +return ; +rhashtable_destroy (dp->rhead_peer_addr);kfree (dp->rhead_peer_addr); dp->rhead_peer_addr =NULL ; -mutex_unlock (&dp->link_peer_rhash_tbl_lock); } static int ath12k_dp_link_peer_rhash_insert(struct ath12k_dp *dp,
drivers/net/wireless/ath/ath12k/peer.c +3 -0
@@ -444,6 +444,9 @@ err_free:void ath12k_link_sta_rhash_tbl_destroy (struct ath12k_base *ab) { +if (!ab->rhead_sta_addr) +return ; +rhashtable_destroy (ab->rhead_sta_addr);kfree (ab->rhead_sta_addr); ab->rhead_sta_addr =NULL ;
Greg Kroah-Hartman
maintainerPATCH 556/744 staging: rtl8723bs: fix OOB reads in rtw_get_wps_ie()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Moksh Panicker <[email protected]>
commit 0e95ff792ae0aa6fbad9455943e9e1e4062670e9 upstream.
rtw_get_wps_ie() iterates over IE data from network frames without validating that the IE header and payload fit within the remaining buffer before reading them. Specifically:
- in_ie[cnt + 1] is read without checking cnt + 1 < in_len
- memcmp(&in_ie[cnt + 2], ...) accesses cnt + 2 without bounds check
- in_ie[cnt + 1] is used as length without verifying payload fits
Add bounds checks at the top of the loop body to break early if fewer than 2 bytes remain for the IE header, or if the declared payload extends past the end of the buffer. Also require at least 4 bytes of payload before comparing the WPS OUI.
--- drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/staging/rtl8723bs/core/rtw_ieee80211.c +8 -1
@@ -671,7 +671,14 @@ u8 *rtw_get_wps_ie(u8 *in_ie, uint in_lewhile (cnt < in_len) { eid = in_ie[cnt]; -if ((eid ==WLAN_EID_VENDOR_SPECIFIC ) && (!memcmp (&in_ie[cnt +2 ], wps_oui,4 ))) { +if (cnt +2 > in_len) +break ; + +if (in_ie[cnt +1 ] +2 > in_len - cnt) +break ; + +if ((eid ==WLAN_EID_VENDOR_SPECIFIC ) && (in_ie[cnt +1 ] >=4 ) && + (!memcmp (&in_ie[cnt +2 ], wps_oui,4 ))) { wpsie_ptr = &in_ie[cnt];if (wps_ie)
Greg Kroah-Hartman
maintainerPATCH 557/744 staging: rtl8723bs: fix inverted HT40 secondary channel offset
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: MinJea Kim <[email protected]>
commit 30d49cba27f8905bc288cef5846963f0004f644c upstream.
rtw_get_chan_type() maps the driver's channel offset to nl80211 channel types the wrong way around.
In this driver HAL_PRIME_CHNL_OFFSET_LOWER means the primary channel is the lower 20 MHz half of the 40 MHz pair, i.e. the secondary channel is above the primary one: rtw_get_center_ch() computes the center channel as "channel + 2" for OFFSET_LOWER, and bwmode_update_check() sets OFFSET_LOWER when the AP's HT operation IE announces SCA (secondary channel above). In nl80211 terms that is NL80211_CHAN_HT40PLUS, not HT40MINUS.
Because of the inversion, cfg80211_rtw_get_channel() reports an HT40+ association as HT40-. For an HT40+ AP on a low channel (e.g. channel 3) the resulting chandef spans below the 2.4 GHz band edge and is invalid, so the regulatory core tears the connection down 60 seconds (REG_ENFORCE_GRACE_MS) after the AP's country IE triggers a regdomain
change: reg_check_chans_work() considers the reported chandef unusable and calls cfg80211_leave(). The supplicant then reconnects, the country IE changes the regdomain again, and the cycle repeats, causing a disconnect/reconnect loop every ~65 seconds for as long as the link is up.
Observed on a TECLAST X80 Power tablet (RTL8723BS) associated to an HT40+ AP on channel 3 with a KR country IE; a kprobe trace showed cfg80211_disconnect() being invoked from reg_check_chans_work(). With the mapping fixed, "iw dev wlan0 info" reports the correct "width: 40 MHz, center1: 2432 MHz" and the periodic disconnects stop.
--- drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +1 -1
@@ -1956,7 +1956,7 @@ static u8 rtw_get_chan_type(struct adaptelse return NL80211_CHAN_NO_HT ;case CHANNEL_WIDTH_40 : -if (mlme_ext->cur_ch_offset ==HAL_PRIME_CHNL_OFFSET_UPPER ) +if (mlme_ext->cur_ch_offset ==HAL_PRIME_CHNL_OFFSET_LOWER )return NL80211_CHAN_HT40PLUS ;else return NL80211_CHAN_HT40MINUS ;
Greg Kroah-Hartman
maintainerPATCH 558/744 Bluetooth: hci_sync: Protect UUID list traversal
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit e9027ffbf5a0f3c12ca8900822e884eae9f0821b upstream.
The hci_sync conversion moved class-of-device and EIR generation from an HCI request built under hdev->lock to asynchronous command sync work. The worker holds hdev->req_lock, but that lock does not serialize access to hdev->uuids against add_uuid() and remove_uuid(), which update the list under hdev->lock.
The following interleaving can therefore occur:
CPU0 (command sync work) CPU1 (management socket)
fetch uuid from the list
list_del(&uuid->list)
kfree(uuid) read uuid->size
KASAN reports the resulting use-after-free:
BUG: KASAN: slab-use-after-free in eir_create+0xb8f/0xee0 Read of size 1 at addr ffff88810dbd8620 by task kworker/u17:0/87 Workqueue: hci0 hci_cmd_sync_work Call Trace: eir_create+0xb8f/0xee0 hci_update_eir_sync+0x1c0/0x330 hci_cmd_sync_work+0x13c/0x290 process_one_work+0x63a/0x1070 worker_thread+0x45b/0xd10 Allocated by task 86: __kasan_kmalloc+0x8f/0xa0 add_uuid+0x18a/0x4b0 hci_sock_sendmsg+0x1033/0x1ea0 Freed by task 92: __kasan_slab_free+0x43/0x70 kfree+0x131/0x3c0 remove_uuid+0x25e/0x560 hci_sock_sendmsg+0x1033/0x1ea0
Hold hdev->lock while generating and committing the class-of-device and EIR snapshots. Release it before sending an HCI command, so controller waits do not happen under the device lock. This protects all UUID list walks in these paths and restores the serialization lost in the command sync conversion.
--- net/bluetooth/hci_sync.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
net/bluetooth/hci_sync.c +11 -2
@@ -929,12 +929,16 @@ int hci_update_eir_sync(struct hci_dev *memset (&cp,0 ,sizeof (cp)); +hci_dev_lock (hdev);eir_create (hdev, cp.data); -if (memcmp (cp.data, hdev->eir,sizeof (cp.data)) ==0 ) +if (memcmp (cp.data, hdev->eir,sizeof (cp.data)) ==0 ) { +hci_dev_unlock (hdev);return 0 ; + }memcpy (hdev->eir, cp.data,sizeof (cp.data)); +hci_dev_unlock (hdev);return __hci_cmd_sync_status (hdev,HCI_OP_WRITE_EIR ,sizeof (cp), &cp,HCI_CMD_TIMEOUT );
@@ -966,6 +970,7 @@ int hci_update_class_sync(struct hci_devif (hci_dev_test_flag (hdev,HCI_SERVICE_CACHE ))return 0 ; +hci_dev_lock (hdev); cod[0 ] = hdev->minor_class; cod[1 ] = hdev->major_class; cod[2 ] =get_service_classes (hdev);
@@ -973,8 +978,12 @@ int hci_update_class_sync(struct hci_devif (hci_dev_test_flag (hdev,HCI_LIMITED_DISCOVERABLE )) cod[1 ] |=0x20 ; -if (memcmp (cod, hdev->dev_class,3 ) ==0 ) +if (memcmp (cod, hdev->dev_class,3 ) ==0 ) { +hci_dev_unlock (hdev);return 0 ; + } + +hci_dev_unlock (hdev);return __hci_cmd_sync_status (hdev,HCI_OP_WRITE_CLASS_OF_DEV ,sizeof (cod), cod,HCI_CMD_TIMEOUT );
Greg Kroah-Hartman
maintainerPATCH 559/744 Bluetooth: RFCOMM: Fix session UAF in set_termios
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 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
@@ -1031,6 +1031,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
@@ -861,7 +861,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 */
@@ -982,9 +982,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 560/744 exec: fix unsigned loop counter wrap in transfer_args_to_stack()
In reply to Greg Kroah-Hartman7.1-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
@@ -736,7 +736,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_local_page (bprm->page[index]) + offset; sp -=PAGE_SIZE - offset;
Greg Kroah-Hartman
maintainerPATCH 561/744 binfmt_misc: set have_execfd only once the interpreter is opened
In reply to Greg Kroah-Hartman7.1-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
@@ -228,9 +228,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 )
@@ -260,6 +257,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 562/744 platform/loongarch: laptop: Explicitly reset bl_powered state when suspend
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zixing Liu <[email protected]>
commit 91a70492c03040d51b36f595530d6491d5d6c541 upstream.
On EAECIS NL60R with EC firmware version 1.11, resuming from S3 has a very high chance (>90%) of causing the EC to lose the previous backlight power state. When this happens, the laptop resumes normally from S3, but the backlight remains off (when shining on the screen with a flash light, we can see the screen contents are updating normally).
Since there is no generic way to query the EC's backlight state on Loongson laptop platforms, assume the worst-case scenario and restart the backlight power inside the kernel each time the system resumes.
--- drivers/platform/loongarch/loongson-laptop.c | 1 + 1 file changed, 1 insertion(+)
drivers/platform/loongarch/loongson-laptop.c +1 -0
@@ -189,6 +189,7 @@ static int __init setup_acpi_notify(strustatic int loongson_hotkey_suspend (struct device *dev) { + bl_powered = false;return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 563/744 rust_binder: only print failure if error has source
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alice Ryhl <[email protected]>
commit bb66b1a3452534adb8b72abf2f761375970fe472 upstream.
The commit that fixes BINDER_GET_EXTENDED_ERROR changed the condition for printing transaction failures so errors are printed even if the cause is a dead or frozen process. Undo this change so that the error is only printed if the failure has an errno associated with it.
--- drivers/android/binder/thread.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/android/binder/thread.rs +7 -7
@@ -1273,14 +1273,14 @@ impl Thread { inner.extended_error =ExtendedError ::new (info.debug_idas u32 , err.reply, source.to_errno ()); } - } -pr_warn! ( -"{}:{} transaction to {} failed: {err:?}" , - info.from_pid, - info.from_tid, - info.to_pid - ); +pr_warn! ( +"{}:{} transaction to {} failed: {err:?}" , + info.from_pid, + info.from_tid, + info.to_pid + ); + } } }
Greg Kroah-Hartman
maintainerPATCH 564/744 rust: time: fix as_micros_ceil() to round correctly for negative Delta
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: FUJITA Tomonori <[email protected]>
commit 880c43b185ca52239e75bc546cc4f4d9154d0fed upstream.
The ceiling-division idiom (n + d - 1) / d only produces the correct result when n is non-negative.
For example, if n = -1000 (exactly -1us), the old code computed (-1000
+ 999) / 1000 == 0 instead of -1.
For negative n, truncating division already rounds towards positive infinity, so no bias is needed in that case.
--- rust/kernel/time.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
rust/kernel/time.rs +9 -2
@@ -441,15 +441,22 @@ impl Delta {/// to the value in the [`Delta`]. #[inline] pub fn as_micros_ceil (self) ->i64 { +let n = self.as_nanos (); +let n =if n >=0 { + n.saturating_add (NSEC_PER_USEC -1 ) + }else { + n + }; +#[cfg( CONFIG_64BIT )] { - self.as_nanos ().saturating_add (NSEC_PER_USEC -1 ) /NSEC_PER_USEC + n /NSEC_PER_USEC }#[cfg(not( CONFIG_64BIT ))] // SAFETY: It is always safe to call `ktime_to_us()` with any value. unsafe { - bindings::ktime_to_us (self.as_nanos ().saturating_add (NSEC_PER_USEC -1 )) + bindings::ktime_to_us (n) } }
Greg Kroah-Hartman
maintainerPATCH 565/744 rust: device: avoid trailing ; in printing macros
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alice Ryhl <[email protected]>
commit a19bda861b3a79e25417462539df8b0d77c6b322 upstream.
These macros are used like expressions, so they should not emit a semicolon. This is being turned into a hard error in a future release of Rust.
error: trailing semicolon in macro used in expression position
--> drivers/gpu/nova-core/firmware/fsp.rs:79:34
|
79 | .inspect_err(|_| dev_err!(dev, "FMC firmware missing '{}' section\n", name))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
= note: this error originates in the macro `dev_err` (in Nightly builds, run with -Z macro-backtrace for more info)[ I was doubly surprised since upstream made it a deny-by-default lint
a year ago for Rust 1.91.0, and yet we didn't see it; plus I hadn't seen this in my CI even yesterday.
It turns out this just landed into today's nightly (nightly-2026-07-16, using upstream commit d0babd8b6):
Link: https://github.com/rust-lang/rust/pull/159222
which says:
"The semicolon_in_expressions_from_macros lint previously
suppressed warnings about non-local macros. This masks a lint that will subsequently become a hard error."
So that explains it. And this is the PR that will make it a hard error at some point in the future:
Link: https://github.com/rust-lang/rust/pull/159218
Thus starting with Rust 1.99.0 (expected 2026-10-01), we will be seeing the deny-by-default lint above, so clean it up already.
- Miguel ]
--- rust/kernel/device.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-)
rust/kernel/device.rs +9 -11
@@ -737,9 +737,7 @@ macro_rules! impl_device_context_into_ar#[macro_export] macro_rules! dev_printk { ($method:ident, $dev:expr, $($f:tt)*) => { - { - $crate::device::Device ::$method($dev.as_ref (), $crate::prelude::fmt!($($f)*)) - } + $crate::device::Device ::$method($dev.as_ref (), $crate::prelude::fmt!($($f)*)) } }
@@ -766,7 +764,7 @@ macro_rules! dev_printk {/// ``` #[macro_export] macro_rules! dev_emerg { - ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); } + ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*) } }/// Prints an alert-level message (level 1) prefixed with device information.
@@ -792,7 +790,7 @@ macro_rules! dev_emerg {/// ``` #[macro_export] macro_rules! dev_alert { - ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); } + ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*) } }/// Prints a critical-level message (level 2) prefixed with device information.
@@ -818,7 +816,7 @@ macro_rules! dev_alert {/// ``` #[macro_export] macro_rules! dev_crit { - ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); } + ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*) } }/// Prints an error-level message (level 3) prefixed with device information.
@@ -844,7 +842,7 @@ macro_rules! dev_crit {/// ``` #[macro_export] macro_rules! dev_err { - ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); } + ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*) } }/// Prints a warning-level message (level 4) prefixed with device information.
@@ -870,7 +868,7 @@ macro_rules! dev_err {/// ``` #[macro_export] macro_rules! dev_warn { - ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); } + ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*) } }/// Prints a notice-level message (level 5) prefixed with device information.
@@ -896,7 +894,7 @@ macro_rules! dev_warn {/// ``` #[macro_export] macro_rules! dev_notice { - ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); } + ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*) } }/// Prints an info-level message (level 6) prefixed with device information.
@@ -922,7 +920,7 @@ macro_rules! dev_notice {/// ``` #[macro_export] macro_rules! dev_info { - ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); } + ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*) } }/// Prints a debug-level message (level 7) prefixed with device information.
@@ -948,5 +946,5 @@ macro_rules! dev_info {/// ``` #[macro_export] macro_rules! dev_dbg { - ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); } + ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*) } }
Greg Kroah-Hartman
maintainerPATCH 566/744 rust: allow `suspicious_runtime_symbol_definitions` lint for Rust >= 1.98
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miguel Ojeda <[email protected]>
commit 608045a91d9176d66b2114d0006bc8b57dff2ca9 upstream.
Starting with Rust 1.98.0 (expected 2026-08-20), Rust is introducing a couple new lints, invalid_runtime_symbol_definitions (deny-by-default) and suspicious_runtime_symbol_definitions (warn-by-default), which check the signature of items whose symbol name is a runtime symbol expected by core.
Our build hits the second one, i.e. the warning:
error: suspicious definition of the runtime `strlen` symbol used by the standard library
--> rust/bindings/bindings_generated.rs:20018:5
|
20018 | pub fn strlen(s: *const ffi::c_char) -> usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected `unsafe extern "C" fn(*const i8) -> usize`
found `unsafe extern "C" fn(*const u8) -> usize`
= help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]`
= help: allow this lint if the signature is compatible
= note: `-D suspicious-runtime-symbol-definitions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(suspicious_runtime_symbol_definitions)]`
error: suspicious definition of the runtime `strlen` symbol used by the standard library
--> rust/uapi/uapi_generated.rs:14236:5
|
14236 | pub fn strlen(s: *const ffi::c_char) -> usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected `unsafe extern "C" fn(*const i8) -> usize`
found `unsafe extern "C" fn(*const u8) -> usize`
= help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]`
= help: allow this lint if the signature is compatible
= note: `-D suspicious-runtime-symbol-definitions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(suspicious_runtime_symbol_definitions)]`Thus allow the lint in bindings and uapi.
A more targeted alternative to avoid allowing it would be to pass --blocklist-function strlen to bindgen, but we would perhaps need to adjust if other C headers end up adding more (or Rust checking more). Since it is just the less critical one that we hit, and since eventually this should be properly fixed by getting upstream Rust to provide a flag like GCC/Clang's -funsigned-char [2][3], just allow it for now.
--- init/Kconfig | 3 +++ rust/bindings/lib.rs | 4 ++++ rust/uapi/lib.rs | 4 ++++ 3 files changed, 11 insertions(+)
init/Kconfig +3 -0
@@ -190,6 +190,9 @@ config RUSTC_HAS_FILE_WITH_NUL config RUSTC_HAS_FILE_AS_C_STR def_bool RUSTC_VERSION >= 109100 +config RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS + def_bool RUSTC_VERSION >= 109800 + config PAHOLE_VERSION int default "$(PAHOLE_VERSION)"
rust/bindings/lib.rs +4 -0
@@ -27,6 +27,10 @@#[allow(clippy::ref_as_ptr)] #[allow(clippy::undocumented_unsafe_blocks)] #[cfg_attr( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES , allow(unnecessary_transmutes))] +#[cfg_attr( +CONFIG_RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS , +allow(suspicious_runtime_symbol_definitions) +)] mod bindings_raw {use pin_init::{MaybeZeroable ,Zeroable };
rust/uapi/lib.rs +4 -0
@@ -24,6 +24,10 @@ unsafe_op_in_unsafe_fn )]#![cfg_attr( CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES , allow(unnecessary_transmutes))] +#![cfg_attr( +CONFIG_RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS , +allow(suspicious_runtime_symbol_definitions) +)] #![feature(cfi_encoding)] // Manual definition of blocklisted types.
Greg Kroah-Hartman
maintainerPATCH 567/744 rust: allow `clippy::unwrap_or_default` globally
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexandre Courbot <[email protected]>
commit 4688cf884b3abcd12498e03b625d1916bf49a1e4 upstream.
Starting with rustc 1.88, the clippy::unwrap_or_default lint triggers on rust/kernel/soc.rs if CONFIG_CC_OPTIMIZE_FOR_SIZE=y:
warning: use of `unwrap_or` to construct default value
--> ../rust/kernel/soc.rs:66:10
|
66 | .unwrap_or(core::ptr::null())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`This is a clippy bug [1]: the lint decides whether an expression is equivalent to Default::default() by inspecting the optimized MIR of <*const T as Default>::default exported by core, so its outcome depends on the optimization level core was built with. Moreover, its suggestion ignores our MSRV of 1.85 (Default for *const T is only stable since Rust 1.88), so we could not apply it anyway.
Disable the lint globally rather than working around this single occurrence; it can be re-enabled conditionally using rustc-min-version once clippy is fixed.
--- Makefile | 5 +++++ 1 file changed, 5 insertions(+)
Makefile +5 -0
@@ -473,6 +473,10 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS) # These flags apply to all Rust code in the tree, including the kernel and # host programs. +# +# `-Aclippy::unwrap_or_default`: the lint is buggy [1] and ignores our +# MSRV. It can trigger depending on the optimization level. +# [1] https://github.com/rust-lang/rust-clippy/issues/17379 export rust_common_flags := --edition=2021 \ -Zbinary_dep_depinfo=y \ -Astable_features \
@@ -501,6 +505,7 @@ export rust_common_flags := --edition=20 -Aclippy::uninlined_format_args \ -Wclippy::unnecessary_safety_comment \ -Wclippy::unnecessary_safety_doc \ + -Aclippy::unwrap_or_default \ -Wrustdoc::missing_crate_level_docs \ -Wrustdoc::unescaped_backticks
Greg Kroah-Hartman
maintainerPATCH 568/744 objtool/rust: add one more `noreturn` Rust function for Rust 1.99.0
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miguel Ojeda <[email protected]>
commit 5a81c35c3b18cd59ded56171a6a9f643b92a6759 upstream.
Starting with Rust 1.99.0 (expected 2026-10-01), under CONFIG_RUST_DEBUG_ASSERTIONS=y, objtool may report:
rust/kernel.o: warning: objtool: _R..._6kernel12module_param9set_paramaEB4_() falls through to next function _R..._6kernel12module_param9set_paramhEB4_()
(and many others) due to calls to the noreturn symbol [1]:
core::panicking::panic_null_reference_constructed
Thus add the mangled one to the list so that objtool knows it is actually noreturn.
See commit 56d680dd23c3 ("objtool/rust: list noreturn Rust functions") for more details.
--- tools/objtool/check.c | 1 + 1 file changed, 1 insertion(+)
tools/objtool/check.c +1 -0
@@ -211,6 +211,7 @@ static bool is_rust_noreturn(const strucstr_ends_with (func->name,"_4core9panicking18panic_nounwind_fmt" ) ||str_ends_with (func->name,"_4core9panicking19assert_failed_inner" ) ||str_ends_with (func->name,"_4core9panicking30panic_null_pointer_dereference" ) || +str_ends_with (func->name,"_4core9panicking32panic_null_reference_constructed" ) ||str_ends_with (func->name,"_4core9panicking36panic_misaligned_pointer_dereference" ) ||str_ends_with (func->name,"_7___rustc17rust_begin_unwind" ) || strstr(func->name, "_4core9panicking13assert_failed") ||
Greg Kroah-Hartman
maintainerPATCH 569/744 LoongArch: Fix address space mismatch in kexec command line lookup
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: George Guo <[email protected]>
commit 485ed44db5694d8d2e5027f63ad608e705286f30 upstream.
When searching the loaded segments for the "kexec" command line marker, the kexec_load(2) path (file_mode == 0) passes the user-space segment buffer straight to strncmp() through a bogus (char __user *) cast. This dereferences a user pointer in kernel context, which is wrong and is flagged by sparse:
arch/loongarch/kernel/machine_kexec.c:84:51: sparse: incorrect type in argument 2 (different address spaces) @@ expected char const * @@ got char [noderef] __user *
Here copy the marker-sized prefix of each segment into a small on-stack buffer with copy_from_user() before comparing, and skip segments that fault. The subsequent copy_from_user() that stages the full command line into the safe area is left unchanged.
--- arch/loongarch/kernel/machine_kexec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
arch/loongarch/kernel/machine_kexec.c +4 -1
@@ -42,6 +42,7 @@ static unsigned long first_ind_entry;int machine_kexec_prepare (struct kimage *kimage) {int i; +char head[8 ];char *bootloader ="kexec" ;void *cmdline_ptr = (void *)KEXEC_CMDLINE_ADDR ;
@@ -59,7 +60,9 @@ int machine_kexec_prepare(struct kimage }else {/* Find the command line */ for (i =0 ; i < kimage->nr_segments; i++) { -if (!strncmp (bootloader, (char __user *)kimage->segment[i].buf,strlen (bootloader))) { +if (copy_from_user (head, kimage->segment[i].buf,strlen (bootloader))) +continue ; +if (!strncmp (bootloader, head,strlen (bootloader))) {if (!copy_from_user (cmdline_ptr, kimage->segment[i].buf,COMMAND_LINE_SIZE )) kimage->arch.cmdline_ptr = (unsigned long )cmdline_ptr;break ;
Greg Kroah-Hartman
maintainerPATCH 570/744 LoongArch: Fix build errors due to wrong instructions for 32BIT
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huacai Chen <[email protected]>
commit 7ea74820edcb22ffa3fb068076d73c6821d7e6d2 upstream.
In some assembly files there are some instructions that only valid for 64BIT, but those files can be compiled for 32BIT and cause build errors.
So, replace those instructions with macros:
li.d --> LONG_LI (li.w or li.d), addi.d --> PTR_ADDI (addi.w or addi.d).
BTW, Re-tab the indention in the assembly files for alignment.
--- arch/loongarch/kernel/rethook_trampoline.S | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
arch/loongarch/kernel/rethook_trampoline.S +9 -9
@@ -71,27 +71,27 @@ cfi_ld s7, PT_R30 cfi_ld s8, PT_R31 LONG_L t0, sp, PT_CRMD - li.d t1, 0x7 /* mask bit[1:0] PLV, bit[2] IE */ + LONG_LI t1, 0x7 /* mask bit[1:0] PLV, bit[2] IE */ csrxchg t0, t1, LOONGARCH_CSR_CRMD .endm SYM_CODE_START(arch_rethook_trampoline) UNWIND_HINT_UNDEFINED - addi.d sp, sp, -PT_SIZE + PTR_ADDI sp, sp, -PT_SIZE save_all_base_regs - addi.d t0, sp, PT_SIZE - LONG_S t0, sp, PT_R3 + PTR_ADDI t0, sp, PT_SIZE + LONG_S t0, sp, PT_R3 - move a0, sp /* pt_regs */ + move a0, sp /* pt_regs */ - bl arch_rethook_trampoline_callback + bl arch_rethook_trampoline_callback /* use the result as the return-address */ - move ra, a0 + move ra, a0 restore_all_base_regs - addi.d sp, sp, PT_SIZE + PTR_ADDI sp, sp, PT_SIZE - jr ra + jr ra SYM_CODE_END(arch_rethook_trampoline)
Greg Kroah-Hartman
maintainerPATCH 571/744 LoongArch: Fix oops during single-step debugging
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoran Jiang <[email protected]>
commit 73555fdab5e1e4f24ca000c41a616b34edf4b55d upstream.
When entering KDB via a breakpoint and then performing single-step debugging, an oops is triggered. Now during single-step debugging, kdb_local() expects the reason to be KDB_REASON_SSTEP, but it is actually KDB_REASON_OOPS. In kdb_stub(), when determining the reason, the ex_vector for single-step should be 0, as already implemented on other architectures such as arm64 and riscv.
Before the patch:
[112]kdb> ss
Entering kdb (current=0x900020009f520000, pid 10661) on processor 112 Oops: (null)
due to oops @ 0x90000000005b57a4
--- arch/loongarch/kernel/kgdb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/loongarch/kernel/kgdb.c +2 -1
@@ -252,7 +252,8 @@ static int kgdb_loongarch_notify(structif (atomic_read (&kgdb_active) !=-1 )kgdb_nmicallback (smp_processor_id (), regs); -if (kgdb_handle_exception (args->trapnr, args->signr, cmd, regs)) +if (kgdb_handle_exception (regs->csr_era == stepped_address ?0 : args->trapnr, + args->signr, cmd, regs))return NOTIFY_DONE ;if (atomic_read (&kgdb_setting_breakpoint))
Greg Kroah-Hartman
maintainerPATCH 572/744 LoongArch: Increase TASK_STRUCT_OFFSET up to 2040 for 32BIT
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huacai Chen <[email protected]>
commit 7917d16d14fb512f8ffe3815b7940b6c93ff4fde upstream.
THREAD_INFO_IN_TASK increase the size of task_struct, which casuses a build error for the 32BIT kernel if RANDSTRUCT is enabled. So increase TASK_STRUCT_OFFSET as big as possible (2040), but can still be aligned and be fit in the addi.w instruction.
--- arch/loongarch/include/asm/asmmacro.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/loongarch/include/asm/asmmacro.h +1 -1
@@ -14,7 +14,7 @@#ifdef CONFIG_64BIT #define TASK_STRUCT_OFFSET 0#else -#define TASK_STRUCT_OFFSET 2000 +#define TASK_STRUCT_OFFSET 2040#endif .macro cpu_save_nonscratch thread
Greg Kroah-Hartman
maintainerPATCH 573/744 LoongArch: Move jump_label_init() before parse_early_param()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kanglong Wang <[email protected]>
commit ea68d444a658783234a06f05414e41cf93a18fb2 upstream.
When enabling both CONFIG_MEM_ALLOC_PROFILING=y and CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=y, then diabling memory profiling by adding the boot parameter 'sysctl.vm.mem_profiling=0' will cause the kernel failed to boot.
After analysis, this is because jump_label_init() must be called before parse_early_param(), the early param handlers may modify static keys by static_branch_enable/disable().
Fix this by moving jump_label_init() to before parse_early_param(). The solution is similar to other architectures.
--- arch/loongarch/kernel/setup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
arch/loongarch/kernel/setup.c +1 -2
@@ -602,6 +602,7 @@ void __init setup_arch(char **cmdline_p)memblock_init ();pagetable_init ();bootcmdline_init (cmdline_p); +jump_label_init ();/* Initialise the static keys for early params */ parse_early_param ();reserve_initrd_mem ();
@@ -609,8 +610,6 @@ void __init setup_arch(char **cmdline_p)arch_mem_init (cmdline_p);resource_init (); -jump_label_init ();/* Initialise the static keys for paravirtualization */ -#ifdef CONFIG_SMP plat_smp_setup ();prefill_possible_map ();
Greg Kroah-Hartman
maintainerPATCH 574/744 LoongArch: Retrieve CPU package ID from PPTT when available
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rong Bao <[email protected]>
commit 4e8f58620f6717f72f3d88a2c8f25c0c656d0ba7 upstream.
Currently, the LoongArch CPU topology initialization code calculates each core's package ID by dividing its physical ID by loongson_sysconf. cores_per_package. This relies on the assumption that cores_per_package counts in the same domain as physical IDs.
On Loongson-3B6000 (XB612B0V_1.2), cores_per_package matches the visible core count -- 24 in this case. However, the physical IDs range from 0 to 31 in a noncontinuous fashion:
$ cat /proc/cpuinfo | grep -i -F 'global_id'
global_id : 0
global_id : 1
global_id : 4
global_id : 5
global_id : 6
global_id : 7
global_id : 8
global_id : 9
global_id : 10
global_id : 11
global_id : 14
global_id : 15
global_id : 16
global_id : 17
global_id : 20
global_id : 21
global_id : 22
global_id : 23
global_id : 26
global_id : 27
global_id : 28
global_id : 29
global_id : 30
global_id : 31Retrieve the exact package ID from ACPI PPTT when available, in the same style as retrieving the core ID and thread ID in parse_acpi_topology(). Use this information in loongson_init_secondary() when the PPTT readout is successful. The original division logic is kept as a fallback.
Meanwhile, since some existing code paths like loongson3_cpufreq expect a continuous integer sequence of package IDs in [0, MAX_PACKAGES) when retrieving from cpu_data[], here we also canonicalize the package ID to be filled in parse_acpi_topology() to meet such an expectation.
--- arch/loongarch/kernel/acpi.c | 27 ++++++++++++++++++++++++++- arch/loongarch/kernel/smp.c | 4 ++-- 2 files changed, 28 insertions(+), 3 deletions(-)
arch/loongarch/kernel/acpi.c +26 -1
@@ -201,10 +201,12 @@ static void __init acpi_process_madt(voi }int pptt_enabled; +static int acpi_nr_packages; +static int acpi_package_ids[MAX_PACKAGES ];int __init parse_acpi_topology (void ) { -int cpu, topology_id; +int i, cpu, topology_id;for_each_possible_cpu (cpu) { topology_id =find_acpi_cpu_topology (cpu,0 );
@@ -222,6 +224,29 @@ int __init parse_acpi_topology(void) cpu_data[cpu].core = topology_id; } + + topology_id =find_acpi_cpu_topology_package (cpu); +if (topology_id <0 ) { +pr_warn ("Invalid BIOS PPTT\n" ); +return -ENOENT ; + } + +for (i =0 ; i < acpi_nr_packages; i++) +if (acpi_package_ids[i] == topology_id) +break ; + +if (i == acpi_nr_packages) + acpi_package_ids[acpi_nr_packages++] = topology_id; + + cpu_data[cpu].package = topology_id; + } + +for_each_possible_cpu (cpu) { +for (i =0 ; i < acpi_nr_packages; i++) +if (cpu_data[cpu].package == acpi_package_ids[i]) { + cpu_data[cpu].package = i;/* Canonicalize */ +break ; + } } pptt_enabled =1 ;
arch/loongarch/kernel/smp.c +2 -2
@@ -425,10 +425,10 @@ void loongson_init_secondary(void)numa_add_cpu (cpu);#endif per_cpu (cpu_state, cpu) =CPU_ONLINE ; - cpu_data[cpu].package = -cpu_logical_map (cpu) / loongson_sysconf.cores_per_package; cpu_data[cpu].core = pptt_enabled ? cpu_data[cpu].core :cpu_logical_map (cpu) % loongson_sysconf.cores_per_package; + cpu_data[cpu].package = pptt_enabled ? cpu_data[cpu].package : +cpu_logical_map (cpu) / loongson_sysconf.cores_per_package; cpu_data[cpu].global_id =cpu_logical_map (cpu); }
Greg Kroah-Hartman
maintainerPATCH 575/744 cdrom: fix stack out-of-bounds read in CDROMVOLCTRL
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 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
@@ -3187,6 +3187,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 576/744 rhashtable: clear stale iter->p on table restart
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft) <[email protected]>
commit 8173f7e2ce67e6ca1d4763f3da14e5b01ce77456 upstream.
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
@@ -776,6 +776,7 @@ int rhashtable_walk_start_check(struct r iter->walker.tbl =rht_dereference_rcu (ht->tbl, ht); iter->slot =0 ; iter->skip =0 ; + iter->p =NULL ;return -EAGAIN ; }
Greg Kroah-Hartman
maintainerPATCH 577/744 firmware: stratix10-svc: fix memory leaks and list corruption bugs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tze Yee Ng <[email protected]>
commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c upstream.
Fix a memory leak when gen_pool_alloc() fails by freeing pmem on the error path. Switch pmem allocation from devm_kzalloc() to kzalloc() with explicit kfree() in the free path to match its list-managed lifetime. Remove the erroneous list_del(&svc_data_mem) which corrupted the list head on failed lookups.
--- drivers/firmware/stratix10-svc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/firmware/stratix10-svc.c +6 -4
@@ -1845,14 +1845,16 @@ void *stratix10_svc_allocate_memory(strustruct gen_pool *genpool = chan->ctrl->genpool;size_t s =roundup (size,1 << genpool->min_alloc_order); - pmem =devm_kzalloc (chan->ctrl->dev,sizeof (*pmem),GFP_KERNEL ); + pmem =kzalloc_obj (*pmem);if (!pmem)return ERR_PTR (-ENOMEM );guard (mutex)(&svc_mem_lock); va =gen_pool_alloc (genpool, s); -if (!va) +if (!va) { +kfree (pmem);return ERR_PTR (-ENOMEM ); + }memset ((void *)va,0 , s); pa =gen_pool_virt_to_phys (genpool, va);
@@ -1878,6 +1880,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocatevoid stratix10_svc_free_memory (struct stratix10_svc_chan *chan,void *kaddr) {struct stratix10_svc_data_mem *pmem; +guard (mutex)(&svc_mem_lock);list_for_each_entry (pmem, &svc_data_mem, node)
@@ -1886,10 +1889,9 @@ void stratix10_svc_free_memory(struct st (unsigned long)kaddr, pmem->size); pmem->vaddr =NULL ;list_del (&pmem->node); +kfree (pmem);return ; } - -list_del (&svc_data_mem); }EXPORT_SYMBOL_GPL (stratix10_svc_free_memory);
Greg Kroah-Hartman
maintainerPATCH 578/744 firmware: stratix10-svc: fix teardown order in remove to prevent race
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Ng Ho Yin <[email protected]>
commit bba85375f8751d6c949036269b529cdcb2a2ed8f upstream.
In stratix10_svc_drv_remove(), stratix10_svc_async_exit() was called before client devices were unregistered. This created a race window where child devices could still be issuing service requests through the async channels after the async infrastructure had already been torn down.
Unregister client devices before tearing down the async threads and channels to ensure all in-flight service calls drain before the underlying infrastructure is destroyed.
--- drivers/firmware/stratix10-svc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/firmware/stratix10-svc.c +2 -2
@@ -2044,12 +2044,12 @@ static void stratix10_svc_drv_remove(strstruct stratix10_svc_controller *ctrl =platform_get_drvdata (pdev);struct stratix10_svc *svc = ctrl->svc; +platform_device_unregister (svc->stratix10_svc_rsu); +stratix10_svc_async_exit (ctrl);of_platform_depopulate (ctrl->dev); -platform_device_unregister (svc->stratix10_svc_rsu); -for (i =0 ; i <SVC_NUM_CHANNEL ; i++) {if (ctrl->chans[i].task) {kthread_stop (ctrl->chans[i].task);
Greg Kroah-Hartman
maintainerPATCH 579/744 firmware: stratix10-svc: handle NO_RESPONSE in async poll
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Ng Ho Yin <[email protected]>
commit 9e1dc434ca708e1134332e45918935752f4410cd upstream.
Define INTEL_SIP_SMC_STATUS_NO_RESPONSE (0x3) and handle it in stratix10_svc_async_poll() the same way as INTEL_SIP_SMC_STATUS_BUSY, returning -EAGAIN so callers can retry instead of treating the poll as a hard failure.
When the Secure Device Manager has not yet produced a response for an asynchronous transaction, ATF is expected to return INTEL_SIP_SMC_STATUS_NO_RESPONSE. Without this handling, the service layer maps the status to -EINVAL and async clients cannot distinguish "not ready yet" from a real error.
--- drivers/firmware/stratix10-svc.c | 5 +++-- include/linux/firmware/intel/stratix10-smc.h | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-)
drivers/firmware/stratix10-svc.c +3 -2
@@ -1487,8 +1487,9 @@ int stratix10_svc_async_poll(struct straWARN_ON_ONCE (1 ); }return 0 ; - }else if (handle->res.a0 ==INTEL_SIP_SMC_STATUS_BUSY ) { -dev_dbg (ctrl->dev,"async message is still in progress\n" ); + }else if (handle->res.a0 ==INTEL_SIP_SMC_STATUS_BUSY || + handle->res.a0 ==INTEL_SIP_SMC_STATUS_NO_RESPONSE ) { +dev_dbg (ctrl->dev,"async message is not ready yet\n" );return -EAGAIN ; }
include/linux/firmware/intel/stratix10-smc.h +4 -0
@@ -67,6 +67,9 @@* INTEL_SIP_SMC_STATUS_REJECTED: * Secure monitor software reject the service client's request. * +* INTEL_SIP_SMC_STATUS_NO_RESPONSE: +* Secure monitor software has no response for the request yet. +* * INTEL_SIP_SMC_STATUS_ERROR: * There is error during the process of service request. *
@@ -77,6 +80,7 @@#define INTEL_SIP_SMC_STATUS_OK 0x0#define INTEL_SIP_SMC_STATUS_BUSY 0x1#define INTEL_SIP_SMC_STATUS_REJECTED 0x2 +#define INTEL_SIP_SMC_STATUS_NO_RESPONSE 0x3#define INTEL_SIP_SMC_STATUS_ERROR 0x4#define INTEL_SIP_SMC_RSU_ERROR 0x7
Greg Kroah-Hartman
maintainerPATCH 580/744 x86/boot/compressed: Disable jump tables
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Chancellor <[email protected]>
commit 4a9ec5ec9555ad62dc5b81a37ac946025c2ea002 upstream.
After a recent upstream LLVM change to start generating jump and lookup tables in switch statements in more instances [1], linking the compressed x86 boot image when CONFIG_KERNEL_ZSTD is enabled fails with:
ld.lld: error: Unexpected run-time relocations (.rela) detected!
Dumping the relocations in misc.o, which is the only file influenced by CONFIG_KERNEL_ZSTD in the decompressor, shows dynamic relocations to some string constants, which correspond to the string literals in the switch statement in handle_zstd_error():
Relocation section '.rela.data.rel.ro' at offset 0x277b0 contains 31 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
0000000000000000 0000006600000001 R_X86_64_64 0000000000000000 .rodata.str1.1 + 73a 0000000000000008 0000006600000001 R_X86_64_64 0000000000000000 .rodata.str1.1 + 78e 0000000000000010 0000006600000001 R_X86_64_64 0000000000000000 .rodata.str1.1 + 78e 0000000000000018 0000006600000001 R_X86_64_64 0000000000000000 .rodata.str1.1 + 78e
...
This optimization is problematic for the decompressor environment, as it is built as -fPIE without any explicit absolute references (as described at the top of misc.c) while not applying any dynamic relocations, hence the linker assertion. To opt out of this optimization, which is of little value in this special early boot code, and to mirror the other x86 startup code in arch/x86/boot/startup, disable jump tables in the decompressor.
--- arch/x86/boot/compressed/Makefile | 1 + 1 file changed, 1 insertion(+)
arch/x86/boot/compressed/Makefile +1 -0
@@ -27,6 +27,7 @@ targets := vmlinux vmlinux.bin vmlinux.b KBUILD_CFLAGS := -m$(BITS) -O2 $(CLANG_FLAGS) KBUILD_CFLAGS += $(CC_FLAGS_DIALECT) KBUILD_CFLAGS += -fno-strict-aliasing -fPIE +KBUILD_CFLAGS += -fno-jump-tables KBUILD_CFLAGS += -Wundef KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING cflags-$(CONFIG_X86_32) := -march=i386
Greg Kroah-Hartman
maintainerPATCH 581/744 comedi: comedi_parport: deal with premature interrupt
In reply to Greg Kroah-Hartman7.1-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/comedi/drivers/comedi_parport.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/comedi/drivers/comedi_parport.c +10 -3
@@ -211,6 +211,13 @@ static irqreturn_t parport_interrupt(intunsigned int ctrl;unsigned short val =0 ; +/* +* 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 ;
@@ -233,6 +240,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);
@@ -288,9 +298,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 582/744 uio_hv_generic: Bind to FCopy device by default
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Hutchings <[email protected]>
commit 87d3621ccc63b3999d756bb59f0cedd738c28eb3 upstream.
The Hyper-V kernel-mode fcopy driver was removed in 6.10 and the new fcopy daemon requires this uio driver to function. However, by default the driver does not bind to any devices, and must be configured through the sysfs "new_id" file.
Since the FCopy device is now only usable through this driver, add its ID to the driver's ID table so that the daemon will work "out of the box".
--- drivers/uio/uio_hv_generic.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/uio/uio_hv_generic.c +7 -1
@@ -396,9 +396,15 @@ hv_uio_remove(struct hv_device *dev)vmbus_free_ring (dev->channel); } +static const struct hv_vmbus_device_id hv_uio_id_table[] = { + {HV_FCOPY_GUID }, + {} +}; +MODULE_DEVICE_TABLE (vmbus, hv_uio_id_table); +static struct hv_driver hv_uio_drv = { .name ="uio_hv_generic" , - .id_table =NULL ,/* only dynamic id's */ + .id_table = hv_uio_id_table, .probe = hv_uio_probe, .remove = hv_uio_remove, };
Greg Kroah-Hartman
maintainerPATCH 583/744 serial: sc16is7xx: implement gpio get_direction() callback
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit af071d9e07e57cfff239e8d09d2f3b05ebc9c667 upstream.
It's strongly recommended for GPIO drivers to always implement the .get_direction() callback - even when the direction is tracked in software. The GPIO core emits a warning when the callback is missing and a user reads the direction of a line, e.g. via /sys/kernel/debug/gpio.
--- drivers/tty/serial/sc16is7xx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/tty/serial/sc16is7xx.c +12 -0
@@ -1274,6 +1274,17 @@ static int sc16is7xx_gpio_set(struct gpireturn 0 ; } +static int sc16is7xx_gpio_get_direction (struct gpio_chip *chip,unsigned int offset) +{ +struct sc16is7xx_port *s =gpiochip_get_data (chip); +struct uart_port *port = &s->p[0 ].port; +unsigned int val; + + val =sc16is7xx_port_read (port,SC16IS7XX_IODIR_REG ); + +return val &BIT (offset) ?GPIO_LINE_DIRECTION_OUT :GPIO_LINE_DIRECTION_IN ; +} +static int sc16is7xx_gpio_direction_input (struct gpio_chip *chip,unsigned offset) {
@@ -1351,6 +1362,7 @@ static int sc16is7xx_setup_gpio_chip(str s->gpio.parent = dev; s->gpio.label =dev_name (dev); s->gpio.init_valid_mask = sc16is7xx_gpio_init_valid_mask; + s->gpio.get_direction = sc16is7xx_gpio_get_direction; s->gpio.direction_input = sc16is7xx_gpio_direction_input; s->gpio.get = sc16is7xx_gpio_get; s->gpio.direction_output = sc16is7xx_gpio_direction_output;
Greg Kroah-Hartman
maintainerPATCH 584/744 serial: 8250_mid: Fix NULL function pointer dereference on DNV/ICX-D/SNR platforms
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiangshan Yi <[email protected]>
commit 7fb13fd7e9a59a37cd911efff83abe19e3ee029d upstream.
Commit b1b4efea05a5 ("serial: 8250_mid: Disable DMA for selected platforms") replaced the dnv_board setup and exit callbacks with PTR_IF(false, ...), which evaluates to NULL. However, the three call sites in mid8250_probe() and mid8250_remove() unconditionally dereference these function pointers without NULL checks, causing a NULL pointer dereference (kernel oops) on any Denverton (DNV), Ice Lake Xeon D (ICX-D/CDF), or Snowridge (SNR) platform.
Fix this by adding the missing NULL checks before calling the setup and exit callbacks.
--- drivers/tty/serial/8250/8250_mid.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
drivers/tty/serial/8250/8250_mid.c +9 -5
@@ -318,9 +318,11 @@ static int mid8250_probe(struct pci_devif (!uart.port.membase)return -ENOMEM ; - ret = mid->board->setup (mid, &uart.port); -if (ret) -return ret; +if (mid->board->setup) { + ret = mid->board->setup (mid, &uart.port); +if (ret) +return ret; + } ret =mid8250_dma_setup (mid, &uart);if (ret)
@@ -336,7 +338,8 @@ static int mid8250_probe(struct pci_devreturn 0 ; err: - mid->board->exit (mid); +if (mid->board->exit) + mid->board->exit (mid);return ret; }
@@ -346,7 +349,8 @@ static void mid8250_remove(struct pci_deserial8250_unregister_port (mid->line); - mid->board->exit (mid); +if (mid->board->exit) + mid->board->exit (mid); }static const struct mid8250_board pnw_board = {
Greg Kroah-Hartman
maintainerPATCH 585/744 selftests: ntsync: correct CONFIG_NTSYNC name
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ethan Nelson-Moore <[email protected]>
commit f97752cfe511c1ed9933057455c73aaac07d6517 upstream.
The config fragment for these tests defines CONFIG_WINESYNC, which refers to an earlier name for the ntsync driver before it was merged [1]. Correct it to define CONFIG_NTSYNC instead.
[1] https://lore.kernel.org/all/[email protected]/
--- tools/testing/selftests/drivers/ntsync/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/drivers/ntsync/config +1 -1
@@ -1 +1 @@ -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y
Greg Kroah-Hartman
maintainerPATCH 586/744 mei: bus: access mei_device under device_lock on cleanup
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Usyskin <[email protected]>
commit f112ea910e554d58b4b39a4492b7d302f0f4204f upstream.
Fix couple of problems in mei_cl_bus_dev_release():
mei_cl_flush_queues() is running without lock. bus->file_list access after mei_dev_bus_put(bus) can become a use-after-free if this was the last reference to bus.
Protect queues cleanup and WARN traversal by device lock there to avoid the concurrent access problems.
Move WARN traversal before mei_dev_bus_put(bus).
This file uses bus variable name for mei_device, adjust code of mei_cl_bus_dev_release() to use bus variable too.
--- drivers/misc/mei/bus.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
drivers/misc/mei/bus.c +9 -7
@@ -4,6 +4,7 @@* Intel Management Engine Interface (Intel MEI) Linux driver */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/device.h> #include <linux/kernel.h>
@@ -1330,15 +1331,16 @@ static void mei_dev_bus_put(struct mei_dstatic void mei_cl_bus_dev_release (struct device *dev) {struct mei_cl_device *cldev =to_mei_cl_device (dev); -struct mei_device *mdev = cldev->cl->dev; +struct mei_device *bus = cldev->bus;struct mei_cl *cl; -mei_cl_flush_queues (cldev->cl,NULL ); -mei_me_cl_put (cldev->me_cl); -mei_dev_bus_put (cldev->bus); - -list_for_each_entry (cl, &mdev->file_list, link) -WARN_ON (cl == cldev->cl); + scoped_guard(mutex, &bus->device_lock) { +mei_cl_flush_queues (cldev->cl,NULL ); +mei_me_cl_put (cldev->me_cl); +list_for_each_entry (cl, &bus->file_list, link) +WARN_ON (cl == cldev->cl); + } +mei_dev_bus_put (bus);kfree (cldev->cl);kfree (cldev);
Greg Kroah-Hartman
maintainerPATCH 587/744 intel_th: fix MSC output device reference leak
In reply to Greg Kroah-Hartman7.1-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 @@ err_put_dev: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
@@ -1490,8 +1490,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 588/744 misc: nsm: only unlock nsm_dev on post-lock error paths
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit ce1fed11d18e163baf7f875152a33bf80f625c1a upstream.
nsm_dev_ioctl() jumps to the common out label even when the initial copy_from_user() fails before nsm->lock has been taken. The error path then blindly unlocks a mutex that was never acquired.
This issue was found by our static analysis tool and then manually reviewed against the current tree.
The grounded PoC kept the miscdevice ioctl entry and the pre-lock copy_from_user(&raw, argp, _IOC_SIZE(cmd)) failure path by issuing NSM_IOCTL_RAW with an invalid user pointer. That failure reaches the shared out label before mutex_lock(&nsm->lock). Lockdep reported:
WARNING: bad unlock balance detected!
exploit/193 is trying to release lock (&global_nsm.lock) at:
nsm_dev_ioctl+0x5f/0xcf [vuln_msv] but there are no more locks to release! no locks held by exploit/193.
Return immediately on the pre-lock copy_from_user() failure and keep the common unlock label for the post-lock paths only.
--- drivers/misc/nsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/misc/nsm.c +1 -1
@@ -367,7 +367,7 @@ static long nsm_dev_ioctl(struct file *f/* Copy user argument struct to kernel argument struct */ r = -EFAULT ;if (copy_from_user (&raw, argp,_IOC_SIZE (cmd))) - goto out; +return r;mutex_lock (&nsm->lock);
Greg Kroah-Hartman
maintainerPATCH 589/744 misc: nsm: pin the module while the device is open
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 3b231f1e9990f4c21220d0a69733ce2105891ff9 upstream.
misc_open() installs a misc driver's file operations with fops_get(), which pins file_operations::owner before replacing the file's f_op. The NSM misc device leaves nsm_dev_fops.owner unset, so opening /dev/nsm does not take a module reference on the nsm driver.
If the driver is built as a module, an open file descriptor can therefore survive rmmod of the module that provides its ioctl callbacks. A later ioctl through that descriptor can call into unloaded module text.
Set nsm_dev_fops.owner to THIS_MODULE so the misc core holds the module while any /dev/nsm file descriptor is open, matching the lifetime expectation for the installed file operations.
--- drivers/misc/nsm.c | 1 + 1 file changed, 1 insertion(+)
drivers/misc/nsm.c +1 -0
@@ -413,6 +413,7 @@ static int nsm_device_init_vq(struct vir }static const struct file_operations nsm_dev_fops = { + .owner =THIS_MODULE , .unlocked_ioctl = nsm_dev_ioctl, .compat_ioctl = compat_ptr_ioctl, };
Greg Kroah-Hartman
maintainerPATCH 590/744 tracing: Delay module ref count for "enable_event" trigger
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
commit e091351b38818ef620d27f44f4bfd625f13afbff upstream.
Triggers are now delayed from freeing, but can still be triggered until after the RCU grace period has ended. The freeing of the enable_event data is put into the private_data_free() callback, but the put of the module refcount is done immediately.
It is possible that if a module is removed that has an event that would enable (or disable) it is still active, it can read the data of the module after it is removed causing a use-after-free bug.
Move the trace_event_put_ref() that releases the module into the delayed callback so that the module can not be removed until any reference to its events are finished.
--- kernel/trace/trace_events_trigger.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/trace/trace_events_trigger.c +4 -2
@@ -1726,7 +1726,10 @@ int event_enable_trigger_print(struct seq_file *m,static void enable_trigger_private_data_free (struct event_trigger_data *data) { -kfree (data->private_data); +struct enable_trigger_data *enable_data = data->private_data; + +trace_event_put_ref (enable_data->file->event_call); +kfree (enable_data); }void event_enable_trigger_free (struct event_trigger_data *data)
@@ -1741,7 +1744,6 @@ void event_enable_trigger_free(struct event_trigger_data *data)/* Remove the SOFT_MODE flag */ trace_event_enable_disable (enable_data->file,0 ,1 ); data->private_data_free = enable_trigger_private_data_free; -trace_event_put_ref (enable_data->file->event_call);trigger_data_free (data); } }
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 591/744 tracing: Fix context switch counter truncation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Usama Arif <[email protected]>
commit 8f76afb9b114bee1c1251e0e52553e9dc7c59f20 upstream.
trace_user_fault_read() samples nr_context_switches_cpu() before enabling preemption and retries the user copy if the counter changes. The helper returns unsigned long long because rq->nr_switches is u64, but the saved value is unsigned int.
Once a CPU has performed 2^32 context switches, assigning the counter to cnt discards its upper bits. The comparison after the copy promotes cnt back to unsigned long long, but the lost bits remain zero, so it reports a change even when the task was never scheduled out. Every retry then fails the same way until the 100-try guard warns and the user copy is abandoned.
This affects long-running systems and workloads with high context-switch rates. A CPU switching 1,000 times per second takes about 50 days.
Store the sampled count in unsigned long long so the full value is preserved.
--- kernel/trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace.c +1 -1
@@ -6191,7 +6191,7 @@ char *trace_user_fault_read(struct trace {int cpu =smp_processor_id ();char *buffer =per_cpu_ptr (tinfo->tbuf, cpu)->buf; -unsigned int cnt; +unsigned long long cnt;int trys =0 ;int ret;
Greg Kroah-Hartman
maintainerPATCH 592/744 tracing: Fix mmiotrace possible NULL dereferencing of hiter->dev
In reply to Greg Kroah-Hartman7.1-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
@@ -146,7 +146,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 593/744 tracing: Fix resource leak on mmiotrace trace_pipe close
In reply to Greg Kroah-Hartman7.1-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
@@ -109,7 +109,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;
@@ -279,6 +278,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 594/744 tracing: Fix union collision of module and refcnt for dynamic events
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit b4eb07bde606c2096b24252be589e735eff6d413 upstream.
In 'struct trace_event_call', the 'module' pointer and the 'refcnt' atomic variable share the same memory space in a union. For dynamic events, the union member is 'refcnt', which acts as an active reference counter.
When a dynamic event (such as kprobe, uprobe, fprobe, eprobe, or wprobe) has a non-zero reference count (e.g. due to active event triggers or perf attachments), its 'call->module' evaluates to a small non-zero integer instead of NULL.
When filtering or setting events for a specific module (e.g., writing ':mod:<module>' to 'set_event'), the code in '__ftrace_set_clr_event_nolock()' and 'update_event_fields()' reads 'call->module' directly without checking whether the event is dynamic. This causes the kernel to treat the small integer (refcnt) as a 'struct module' pointer, leading to a NULL/invalid pointer dereference (Oops) when dereferencing the module name.
Fix this by ensuring that the 'TRACE_EVENT_FL_DYNAMIC' flag is checked before treating 'call->module' as a valid pointer in these code paths.
--- kernel/trace/trace_events.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/trace_events.c +3 -1
@@ -1350,7 +1350,9 @@ __ftrace_set_clr_event_nolock(struct tra call = file->event_call;/* If a module is specified, skip events that are not that module */ -if (module && (!call->module ||strcmp (module_name (call->module), module))) +if (module && + ((call->flags &TRACE_EVENT_FL_DYNAMIC ) || + !call->module ||strcmp (module_name (call->module), module)))continue ; name =trace_event_name (call);
Greg Kroah-Hartman
maintainerPATCH 595/744 tracing: perf: Fix stale head for perf syscall tracing
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
commit 2c2b322acdcc78575b8d6afa64a085cf92e03c12 upstream.
The code that can read the user space parameters of a system call may enable preemption and migrate. The head of the per CPU perf events list may be pointing to the wrong CPU event if the code migrates the task.
Reassign the head pointer if the system call event called the code that may have caused a migration.
--- kernel/trace/trace_syscalls.c | 5 +++++ 1 file changed, 5 insertions(+)
kernel/trace/trace_syscalls.c +5 -0
@@ -1436,6 +1436,11 @@ static void perf_syscall_enter(void *ignif (syscall_get_data (sys_data, args, &user_ptr, &size, user_sizes, &uargs, buf_size) <0 )return ; + +/* The above may have caused a migration */ + head =this_cpu_ptr (sys_data->enter_event->perf_events); +if (hlist_empty (head)) +return ; } head =this_cpu_ptr (sys_data->enter_event->perf_events);
Greg Kroah-Hartman
maintainerPATCH 596/744 tracing: Propagate errors from remote event bulk updates
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jackie Liu <[email protected]>
commit 655111f878a455f724e20122929cf2afa52b76e4 upstream.
remote_events_dir_enable_write() ignores the return value from trace_remote_enable_event(). If a remote rejects an event state change, the write therefore reports success even though the affected event remains in its previous state.
Keep trying all events, but retain and return the first error. This matches __ftrace_set_clr_event_nolock(), which permits partial updates while notifying userspace when an operation fails.
--- kernel/trace/trace_remote.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
kernel/trace/trace_remote.c +12 -1
@@ -1150,10 +1150,21 @@ static ssize_t remote_events_dir_enable_for (i =0 ; i < remote->nr_events; i++) {struct remote_event *evt = &remote->events[i]; +int eret; -trace_remote_enable_event (remote, evt, enable); + eret =trace_remote_enable_event (remote, evt, enable); +/* +* Save the first error and return that. Some events +* may still have been enabled, but let the user +* know that something went wrong. +*/ +if (!ret && eret) + ret = eret; } +if (ret) +return ret; +return count; }
Greg Kroah-Hartman
maintainerPATCH 597/744 ublk: wait on ublk_dev_ready() instead of ub->completion
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Lei <[email protected]>
commit 432a9b2780c0a01caf547bd1fc2fcf28aeb8d173 upstream.
ub->completion is only re-armed by a successful START_USER_RECOVERY. If the ublk server sends END_USER_RECOVERY without one - e.g. its START failed with -EBUSY and the error was ignored - the wait is satisfied by the stale completion of the previous recovery cycle, and the device is marked LIVE and the requeue list kicked while the FETCH stream is still running and ubq->canceling is still set. The kick redispatches a previously requeued request, __ublk_queue_rq_common() sees ->canceling and parks it again via __ublk_abort_rq(), and after the last FETCH clears ->canceling nothing ever kicks the requeue list again: the request is stranded there while holding its tag. If it is the flush machinery's flush_rq, every subsequent fsync piles up in uninterruptible sleep and teardown hangs on tag draining. This matches a report of a lost PREFLUSH with ext4 on top of ublk after daemon crash recovery.
ub->completion is an edge-triggered latch used as a proxy for the level condition "every queue has fetched all I/O commands", which can regress (F_BATCH's UNPREP, daemon death) and whose re-arm can be skipped. Drop it and wait on the real condition instead: the new helper ublk_wait_dev_ready_and_lock() waits on ublk_dev_ready() via wait_var_event_interruptible(), woken from ublk_mark_io_ready(), then re-checks it under ub->mutex, waiting again on regression, and returns with the mutex held and readiness guaranteed.
Readiness becomes true in the same ub->mutex critical section that clears the last queue's ->canceling, so END_USER_RECOVERY marks the device LIVE and kicks the requeue list strictly after ->canceling clears. The wait stays interruptible, so a server whose daemon died can still be signalled out. For ublk_ctrl_start_dev() this replaces the fail-fast -EINVAL on an F_BATCH ready->UNPREP regression with waiting until the device is ready again.
--- drivers/block/ublk_drv.c | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-)
drivers/block/ublk_drv.c +30 -17
@@ -19,6 +19,7 @@#include <linux/errno.h> #include <linux/major.h> #include <linux/wait.h> +#include <linux/wait_bit.h> #include <linux/blkdev.h> #include <linux/init.h> #include <linux/swap.h>
@@ -26,7 +27,6 @@#include <linux/compat.h> #include <linux/mutex.h> #include <linux/writeback.h> -#include <linux/completion.h> #include <linux/highmem.h> #include <linux/sysfs.h> #include <linux/miscdevice.h>
@@ -327,7 +327,6 @@ struct ublk_device {struct ublk_params params; -struct completion completion;u32 nr_queue_ready;bool unprivileged_daemons;struct mutex cancel_mutex;
@@ -3058,12 +3057,12 @@ static void ublk_mark_io_ready(struct ubif (ublk_dev_ready (ub)) {/* * All queues ready - clear device-level canceling flag -* and complete the recovery/initialization. +* and wake ublk_dev_ready() waiters. */ mutex_lock (&ub->cancel_mutex); ub->canceling = false;mutex_unlock (&ub->cancel_mutex); -complete_all (&ub->completion); +wake_up_var (&ub->nr_queue_ready); } }
@@ -4266,7 +4265,6 @@ static int ublk_init_queues(struct ublk_ goto fail; } -init_completion (&ub->completion);return 0 ; fail:
@@ -4410,6 +4408,26 @@ static bool ublk_validate_user_pid(strucreturn ub->ublksrv_tgid == ublksrv_pid; } +/* +* Wait until all queues have fetched their I/O commands, and return with +* ub->mutex held and readiness guaranteed: then every queue's ->canceling +* is cleared. Ready may regress between wakeup and mutex_lock() (F_BATCH +* UNPREP, daemon death), so re-check it under the mutex and wait again. +*/ +static int ublk_wait_dev_ready_and_lock (struct ublk_device *ub) +{ +while (true) { +if (wait_var_event_interruptible (&ub->nr_queue_ready, +ublk_dev_ready (ub))) +return -EINTR ; + +mutex_lock (&ub->mutex); +if (ublk_dev_ready (ub)) +return 0 ; +mutex_unlock (&ub->mutex); + } +} +static int ublk_ctrl_start_dev (struct ublk_device *ub,const struct ublksrv_ctrl_cmd *header) {
@@ -4492,15 +4510,10 @@ static int ublk_ctrl_start_dev(struct ub }; } -if (wait_for_completion_interruptible (&ub->completion) !=0 ) +if (ublk_wait_dev_ready_and_lock (ub))return -EINTR ; -if (!ublk_validate_user_pid (ub, ublksrv_pid)) -return -EINVAL ; - -mutex_lock (&ub->mutex); -/* device may become not ready in case of F_BATCH */ -if (!ublk_dev_ready (ub)) { +if (!ublk_validate_user_pid (ub, ublksrv_pid)) { ret = -EINVAL ; goto out_unlock; }
@@ -5064,7 +5077,6 @@ static int ublk_ctrl_start_recovery(stru goto out_unlock; }pr_devel ("%s: start recovery for dev id %d\n" , __func__, ub->ub_number); -init_completion (&ub->completion); ret =0 ; out_unlock:mutex_unlock (&ub->mutex);
@@ -5080,16 +5092,17 @@ static int ublk_ctrl_end_recovery(structpr_devel ("%s: Waiting for all FETCH_REQs, dev id %d...\n" , __func__, header->dev_id); -if (wait_for_completion_interruptible (&ub->completion)) +if (ublk_wait_dev_ready_and_lock (ub))return -EINTR ;pr_devel ("%s: All FETCH_REQs received, dev id %d\n" , __func__, header->dev_id); -if (!ublk_validate_user_pid (ub, ublksrv_pid)) -return -EINVAL ; +if (!ublk_validate_user_pid (ub, ublksrv_pid)) { + ret = -EINVAL ; + goto out_unlock; + } -mutex_lock (&ub->mutex);if (ublk_nosrv_should_stop_dev (ub)) goto out_unlock;
Greg Kroah-Hartman
maintainerPATCH 598/744 tracing/eprobe: Fix exact system name matching in eprobe_dyn_event_match()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit f418d68d71fd4a0a9cef92377bc8c4c3334b5b53 upstream.
eprobe_dyn_event_match() checks if the target event system in argv[0] matches ep->event_system using strncmp(ep->event_system, argv[0], len). However, if ep->event_system is longer than len (e.g. "eprobes" vs "ep/event"), strncmp() still returns 0 because the first len characters match.
Check that ep->event_system[len] is '\0' to ensure exact system name matching.
--- kernel/trace/trace_eprobe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/trace/trace_eprobe.c +2 -1
@@ -172,7 +172,8 @@ static bool eprobe_dyn_event_match(constif (!slash)return false; -if (strncmp (ep->event_system, argv[0 ], slash - argv[0 ])) +if (strncmp (ep->event_system, argv[0 ], slash - argv[0 ]) || + ep->event_system[slash - argv[0 ]] !='\0' )return false;if (strcmp (ep->event_name, slash +1 ))return false;
Greg Kroah-Hartman
maintainerPATCH 599/744 tracing/probes: Avoid temporary buffer truncation in trace_probe_match_command_args()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
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
@@ -2344,16 +2344,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 600/744 tracing/probes: Fix potential underflow in LEN_OR_ZERO macro
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
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
@@ -2018,7 +2018,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,enum probe_print_type ptype) {
Greg Kroah-Hartman
maintainerPATCH 601/744 tracing/probes: Prevent out-of-bounds write in __trace_probe_log_err()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
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
@@ -188,7 +188,7 @@ void __trace_probe_log_err(int offset, ilockdep_assert_held (&dyn_event_ops_mutex); -if (!trace_probe_log.argv) +if (!trace_probe_log.argv || !trace_probe_log.argc)return ;/* Recalculate the length and allocate buffer */
Greg Kroah-Hartman
maintainerPATCH 602/744 tracing/remotes: Fix page_va[] access before counter update in trace_remote_alloc_buffer()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fuad Tabba <[email protected]>
commit 94b83ff0c0a69e42f403b59918529fbca2a89daf upstream.
page_va[] is annotated __counted_by(nr_page_va), so nr_page_va must cover an index before that element is accessed. The allocation loop writes page_va[id] while nr_page_va is still id and increments it only afterwards, so every write is one element past the declared count.
The store is out of bounds with respect to the annotation: a build with CONFIG_UBSAN_BOUNDS on a toolchain that honours __counted_by (clang >= 20.1, gcc >= 15.1) flags it as an array-index overflow.
Increment nr_page_va before writing the element it now covers. A failed allocation then leaves the slot counted but NULL; the error path frees it with free_page(0), which is a no-op.
--- kernel/trace/trace_remote.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
kernel/trace/trace_remote.c +1 -2
@@ -1004,11 +1004,10 @@ int trace_remote_alloc_buffer(struct tra desc->nr_cpus++;for (id =0 ; id < nr_pages; id++) { + rb_desc->nr_page_va++; rb_desc->page_va[id] = (unsigned long )__get_free_page (GFP_KERNEL );if (!rb_desc->page_va[id]) goto err; - - rb_desc->nr_page_va++; } rb_desc =__next_ring_buffer_desc (rb_desc); }
Greg Kroah-Hartman
maintainerPATCH 603/744 arm64: make huge_ptep_get handled unaligned addresses
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dev Jain <[email protected]>
commit f73a8edc2ccc6ec72c37d5c578e7592d2e1f9922 upstream.
huge_ptep_get() can be handed a virtual address pointing to the middle of a contpmd/contpte mapped hugetlb folio (examples of callers are pagemap_hugetlb_range, page_mapped_in_vma).
The arm64 helper rewalks the pgtables in find_num_contig to answer whether the huge pte we have maps a contpmd or a contpte hugetlb folio, and returns CONT_PMDS or CONT_PTES, so that it can collect a/d bits over the contiguous ptes. We can falsely return CONT_PTES instead of CONT_PMDS if the addr is not aligned. On systems where CONT_PTES != CONT_PMDS (meaning page size is 16K), we could collect excess A/D bit state, meaning extra work for the kernel. Even worse, we may iterate beyond the PTE table and dereference a garbage ptep pointer to access physical memory we don't own. Since the ptep pointer is a linear map address, we may run off the end of the linear map or into a hole, dereference a VA not mapped into the kernel pgtables and cause kernel panic.
Fix this by aligning the pmdp pointer down to a contpmd base before checking equality with the passed huge pte pointer, to correctly answer whether the huge pte is the base of a contpmd block.
--- arch/arm64/mm/hugetlbpage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/mm/hugetlbpage.c +1 -1
@@ -87,7 +87,7 @@ static int find_num_contig(struct mm_str p4dp =p4d_offset (pgdp, addr); pudp =pud_offset (p4dp, addr); pmdp =pmd_offset (pudp, addr); -if ((pte_t *)pmdp == ptep) { +if ((pte_t *)PTR_ALIGN_DOWN (pmdp,sizeof (*pmdp) *CONT_PMDS ) == ptep) { *pgsize =PMD_SIZE ;return CONT_PMDS ; }
Greg Kroah-Hartman
maintainerPATCH 604/744 arm64: syscall: Ensure saved x0 is kept in-sync with tracer updates
In reply to Greg Kroah-Hartman7.1-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
@@ -2408,6 +2408,21 @@ static void report_syscall_exit(struct p } } +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_thread_flags ();
@@ -2417,12 +2432,26 @@ int syscall_trace_enter(struct pt_regs * ret =report_syscall_entry (regs);if (ret || (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 605/744 Revert "arm64: syscall: Ensure saved x0 is kept in-sync with tracer updates"
In reply to Greg Kroah-Hartman7.1-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
@@ -2408,21 +2408,6 @@ static void report_syscall_exit(struct p } } -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_thread_flags ();
@@ -2432,26 +2417,12 @@ int syscall_trace_enter(struct pt_regs * ret =report_syscall_entry (regs);if (ret || (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 606/744 mptcp: decrement subflows counter on failed passive join
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
commit f3ca0ee2cc308e33896536789cbc5f3a12ca7b30 upstream.
mptcp_pm_allow_new_subflow() increments extra_subflows before __mptcp_finish_join() on the passive MP_JOIN path.
In case of race conditions, the subflow is dropped without calling mptcp_close_ssk(), so the counter is not rolled back.
Call mptcp_pm_close_subflow() when the join completion fails to decrement the subflows counter.
--- net/mptcp/protocol.c | 1 + 1 file changed, 1 insertion(+)
net/mptcp/protocol.c +1 -0
@@ -3907,6 +3907,7 @@ bool mptcp_finish_join(struct sock *ssk)mptcp_data_unlock (parent);if (!ret) { +mptcp_pm_close_subflow (msk); err_prohibited: subflow->reset_reason =MPTCP_RST_EPROHIBIT ;return false;
Greg Kroah-Hartman
maintainerPATCH 607/744 mptcp: fix BUILD_BUG_ON on legacy ARM config
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
commit 133cca19d75b9264bc2bbcdf2c3b80e3da207649 upstream.
The 0-day bot managed to find kernel configs that cause build failures, e.g. when using the StrongARM SA1100 target (ARMv4).
On such legacy ARM architecture, all structures are apparently aligned to 32 bits, causing build issue here. Indeed, on such architecture, 'flags' size is not equivalent to sizeof(u16) as expected, but to sizeof(u32).
Instead, use memset(). It was not used before to ensure a simple clear operation was used by the compiler. But at the end, it shouldn't matter, and the compiler should optimise this to the same operation with or without memset() when -O above 0 is used. So let's switch to memset() to fix this issue, and reduce this complexity.
--- net/mptcp/options.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
net/mptcp/options.c +1 -4
@@ -573,10 +573,7 @@ static bool mptcp_established_options_dsbool ret = false;/* Zero `use_ack` and `use_map` flags with one shot. */ - BUILD_BUG_ON(sizeof_field(struct mptcp_ext, flags) != sizeof(u16)); -BUILD_BUG_ON (!IS_ALIGNED (offsetof(struct mptcp_ext , flags), -sizeof (u16))); - *(u16 *)&opts->ext_copy.flags =0 ; +memset (&opts->ext_copy.flags,0 ,sizeof (opts->ext_copy.flags)); opts->csum_reqd =READ_ONCE (msk->csum_enabled); mpext = skb ?mptcp_get_ext (skb) :NULL ;
Greg Kroah-Hartman
maintainerPATCH 608/744 mptcp: fix stale skb->sk reference on subflow close
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kalpan Jani <[email protected]>
commit bd7aae448f6ee9d82599a4474664de1e6e91a535 upstream.
The backlog list is updated by mptcp_data_ready() under mptcp_data_lock(). The cleanup of backlog references to a closing subflow, however, was performed in mptcp_close_ssk(), before __mptcp_close_ssk() acquires the ssk lock, and while holding neither the ssk lock nor mptcp_data_lock().
Because that traversal ran without mptcp_data_lock(), concurrent softirq RX processing on another CPU (subflow_data_ready() -> mptcp_data_ready() -> __mptcp_add_backlog(), under mptcp_data_lock()) could add a backlog entry referencing the ssk while the cleanup loop was in progress. Such an entry could be missed by the cleanup, or the concurrent list update could corrupt the traversal, leaving skb->sk pointing at the ssk after it is freed.
A later mptcp_backlog_purge() then dereferences the stale pointer, triggering a warning in inet_sock_destruct() (ssk->sk_rmem_alloc != 0) followed by a use-after-free in mptcp_backlog_purge().
Fix this by moving the backlog cleanup into __mptcp_close_ssk(), after subflow->closing is set to 1 and while the ssk lock is still held, serialized under mptcp_data_lock(). The cleanup runs only on the push path (MPTCP_CF_PUSH), where backlog references accumulate; on other teardown paths the caller already handles cleanup.
With subflow->closing set and mptcp_data_lock() held across the purge, any concurrent mptcp_data_ready() either completes its enqueue before the purge runs and is caught, or observes closing=1 and bails out. Once mptcp_data_unlock() is reached, no new skb referencing the ssk can be enqueued, so the cleanup is exhaustive.
Remove the unprotected traversal from mptcp_close_ssk() entirely.
--- net/mptcp/protocol.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-)
net/mptcp/protocol.c +19 -14
@@ -2545,6 +2545,22 @@ static void __mptcp_subflow_disconnect(s } } +static void mptcp_cleanup_ssk_backlog (struct sock *sk,struct sock *ssk) +{ +struct mptcp_sock *msk =mptcp_sk (sk); +struct sk_buff *skb; + +mptcp_data_lock (sk); +list_for_each_entry (skb, &msk->backlog_list, list) { +if (skb->sk != ssk) +continue ; + +atomic_sub (skb->truesize, &skb->sk->sk_rmem_alloc); + skb->sk =NULL ; + } +mptcp_data_unlock (sk); +} +/* subflow sockets can be either outgoing (connect) or incoming * (accept). *
@@ -2568,6 +2584,9 @@ static void __mptcp_close_ssk(struct soclock_sock_nested (ssk,SINGLE_DEPTH_NESTING ); subflow->closing =1 ; +if (flags &MPTCP_CF_PUSH ) +mptcp_cleanup_ssk_backlog (sk, ssk); +/* Borrow the fwd allocated page left-over; fwd memory for the subflow * could be negative at this point, but will be reach zero soon - when * the data allocated using such fragment will be freed.
@@ -2659,9 +2678,6 @@ out:void mptcp_close_ssk (struct sock *sk,struct sock *ssk,struct mptcp_subflow_context *subflow) { -struct mptcp_sock *msk =mptcp_sk (sk); -struct sk_buff *skb; -/* The first subflow can already be closed or disconnected */ if (subflow->close_event_done ||READ_ONCE (subflow->local_id) <0 )return ;
@@ -2671,17 +2687,6 @@ void mptcp_close_ssk(struct sock *sk, stif (sk->sk_state ==TCP_ESTABLISHED )mptcp_event (MPTCP_EVENT_SUB_CLOSED ,mptcp_sk (sk), ssk,GFP_KERNEL ); -/* Remove any reference from the backlog to this ssk; backlog skbs consume -* space in the msk receive queue, no need to touch sk->sk_rmem_alloc -*/ -list_for_each_entry (skb, &msk->backlog_list, list) { -if (skb->sk != ssk) -continue ; - -atomic_sub (skb->truesize, &skb->sk->sk_rmem_alloc); - skb->sk =NULL ; - } -/* subflow aborted before reaching the fully_established status * attempt the creation of the next subflow */
Greg Kroah-Hartman
maintainerPATCH 609/744 mptcp: only set DATA_FIN when a mapping is present
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit b2ff91b752b0d85e8815e7f44fd85205c4268094 upstream.
mptcp_get_options() clears only the status group of struct mptcp_options_received; data_seq, subflow_seq and data_len are filled in by mptcp_parse_option() exclusively inside the DSS mapping block, which runs only when the DSS M (mapping present) bit is set.
A peer can send a DSS option with the DATA_FIN flag set but the mapping bit clear. The parser then records mp_opt->data_fin while leaving data_len and data_seq uninitialized. For a zero-length segment mptcp_incoming_options() evaluates
if (mp_opt.data_fin && mp_opt.data_len == 1 && mptcp_update_rcv_data_fin(msk, mp_opt.data_seq, mp_opt.dsn64))
which reads the uninitialized data_len and data_seq; KMSAN reports an uninit-value in mptcp_incoming_options(). The stale data_seq can also be fed into the receive-side DATA_FIN sequence tracking.
Record the DATA_FIN flag only when the DSS option carries a mapping, so data_fin is never set without data_seq and data_len also being present. data_fin is part of the status group that mptcp_get_options() clears up front, so on the no-map path it stays zero and the zero-length DATA_FIN branch is simply skipped. A DATA_FIN is always transmitted together with a mapping (mptcp_write_data_fin() sets use_map along with data_seq and data_len), so legitimate DATA_FIN handling is unaffected.
Move the pr_debug() that logs the parsed DSS flags below the mapping block, so it reports the final data_fin value instead of the stale one it would otherwise print before the assignment.
--- net/mptcp/options.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
net/mptcp/options.c +6 -6
@@ -157,17 +157,11 @@ static void mptcp_parse_option(const str ptr++; flags = (*ptr++) &MPTCP_DSS_FLAG_MASK ; - mp_opt->data_fin = (flags &MPTCP_DSS_DATA_FIN ) !=0 ; mp_opt->dsn64 = (flags &MPTCP_DSS_DSN64 ) !=0 ; mp_opt->use_map = (flags &MPTCP_DSS_HAS_MAP ) !=0 ; mp_opt->ack64 = (flags &MPTCP_DSS_ACK64 ) !=0 ; mp_opt->use_ack = (flags &MPTCP_DSS_HAS_ACK ); -pr_debug ("data_fin=%d dsn64=%d use_map=%d ack64=%d use_ack=%d\n" , - mp_opt->data_fin, mp_opt->dsn64, - mp_opt->use_map, mp_opt->ack64, - mp_opt->use_ack); - expected_opsize =TCPOLEN_MPTCP_DSS_BASE ;if (mp_opt->use_ack) {
@@ -178,12 +172,18 @@ static void mptcp_parse_option(const str }if (mp_opt->use_map) { + mp_opt->data_fin = (flags &MPTCP_DSS_DATA_FIN ) !=0 ;if (mp_opt->dsn64) expected_opsize +=TCPOLEN_MPTCP_DSS_MAP64 ;else expected_opsize +=TCPOLEN_MPTCP_DSS_MAP32 ; } +pr_debug ("data_fin=%d dsn64=%d use_map=%d ack64=%d use_ack=%d\n" , + mp_opt->data_fin, mp_opt->dsn64, + mp_opt->use_map, mp_opt->ack64, + mp_opt->use_ack); +/* Always parse any csum presence combination, we will enforce * RFC 8684 Section 3.3.0 checks later in subflow_data_ready */
Greg Kroah-Hartman
maintainerPATCH 610/744 mptcp: pm: userspace: fix use-after-free in get_local_id
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geliang Tang <[email protected]>
commit 9bc6d5e4ca9f3cbb41d43400b3a31cb0403796c9 upstream.
In mptcp_pm_userspace_get_local_id(), the address entry is looked up under spinlock, but its id is read after dropping the lock. A concurrent deletion can free the entry between the unlock and the read, leading to UAF.
The race window is narrow. It was reproduced only with a locally constructed stress test that repeatedly overlaps an MP_JOIN SYN with a MPTCP_PM_CMD_SUBFLOW_DESTROY request.
However, the KASAN report below confirms that the race is reachable:
[ 666.319376] BUG: KASAN: slab-use-after-free in mptcp_userspace_pm_get_local_id+0x1dc/0x1f0 [ 666.319386] Read of size 1 at addr ffff888124845610 by task swapper/0/0 ... [ 666.319401] Call Trace: [ 666.319405] <IRQ> [ 666.319408] dump_stack_lvl+0x53/0x70 [ 666.319412] print_address_description.constprop.0+0x2c/0x3b0 [ 666.319418] print_report+0xbe/0x2b0 [ 666.319421] ? mptcp_userspace_pm_get_local_id+0x1dc/0x1f0 [ 666.319423] kasan_report+0xce/0x100 [ 666.319426] ? mptcp_userspace_pm_get_local_id+0x1dc/0x1f0 [ 666.319429] mptcp_userspace_pm_get_local_id+0x1dc/0x1f0 [ 666.319433] mptcp_pm_get_local_id+0x371/0x440 ... [ 666.319821] Allocated by task 45539: [ 666.319844] kasan_save_stack+0x33/0x60 [ 666.319855] kasan_save_track+0x14/0x30 [ 666.319858] __kasan_kmalloc+0x8f/0xa0 [ 666.319863] __kmalloc_noprof+0x1e7/0x520 [ 666.319867] sock_kmalloc+0xdf/0x130 [ 666.319885] sock_kmemdup+0x1b/0x40 [ 666.319888] mptcp_userspace_pm_append_new_local_addr+0x261/0x500 [ 666.319910] mptcp_pm_nl_announce_doit+0x16a/0x610 ... [ 666.319967] Freed by task 45560: [ 666.319988] kasan_save_stack+0x33/0x60 [ 666.319991] kasan_save_track+0x14/0x30 [ 666.319994] kasan_save_free_info+0x3b/0x60 [ 666.319998] __kasan_slab_free+0x43/0x70 [ 666.320000] kfree+0x166/0x440 [ 666.320003] sock_kfree_s+0x1d/0x50 [ 666.320007] mptcp_userspace_pm_delete_local_addr.isra.0+0x157/0x200 [ 666.320011] mptcp_pm_nl_subflow_destroy_doit+0x51d/0xea0
Fix by copying the id into a local variable while still holding the lock, and use -1 as a "not found" sentinel.
--- net/mptcp/pm_userspace.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/mptcp/pm_userspace.c +5 -2
@@ -132,12 +132,15 @@ int mptcp_userspace_pm_get_local_id(stru__be16 msk_sport = ((struct inet_sock *)inet_sk ((struct sock *)msk))->inet_sport;struct mptcp_pm_addr_entry *entry; +int id;spin_lock_bh (&msk->pm.lock); entry =mptcp_userspace_pm_lookup_addr (msk, &skc->addr); + id = entry ? entry->addr.id :-1 ;spin_unlock_bh (&msk->pm.lock); -if (entry) -return entry->addr.id; + +if (id !=-1 ) +return id;if (skc->addr.port == msk_sport) skc->addr.port =0 ;
Greg Kroah-Hartman
maintainerPATCH 611/744 selftests: mptcp: userspace_pm: fix undefined variable port
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geliang Tang <[email protected]>
commit e3213292c4fd69ba442c6ed4693f91a92b753140 upstream.
In make_connection(), the variable "port" is used but never defined. This leads to an empty argument being passed to wait_local_port_listen(), causing "printf: : invalid number" errors:
# INFO: Init
# 01 Created network namespaces ns1, ns2 [ OK ]
# INFO: Make connections
# ./../lib.sh: line 651: printf: : invalid number
# 02 Established IPv4 MPTCP Connection ns2 => ns1 [ OK ]
# INFO: Connection info: 10.0.1.2:59516 -> 10.0.1.1:50002 # ./../lib.sh: line 651: printf: : invalid number
# 03 Established IPv6 MPTCP Connection ns2 => ns1 [ OK ]
Fix it by using the correctly defined variable "app_port", which holds the appropriate port number for the connection.
--- tools/testing/selftests/net/mptcp/userspace_pm.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/net/mptcp/userspace_pm.sh +1 -1
@@ -212,7 +212,7 @@ make_connection() ./mptcp_connect -s MPTCP -w 300 -p $app_port -l $listen_addr > /dev/null 2>&1 & local server_pid=$! - mptcp_lib_wait_local_port_listen "${ns1}" "${port}" + mptcp_lib_wait_local_port_listen "${ns1}" "${app_port}" # Run the client, transfer $file and stay connected to the server # to conduct tests
Greg Kroah-Hartman
maintainerPATCH 612/744 afs: Fix afs_edit_dir_remove() to get, not find, block 0
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
commit 62d9853aa4ce6e9797b6949804891be14b219752 upstream.
Fix afs_edit_dir_remove() to use afs_dir_get_block() to get block 0 rather than afs_dir_find_block() as the latter caches the found block in the afs_dir_iter and may[*] switch out the page it's on if another afs_dir_find_block() is done. This parallels what afs_edit_dir_add() does.
[*] There's more than one block per page.
--- fs/afs/dir_edit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/afs/dir_edit.c +1 -1
@@ -415,7 +415,7 @@ void afs_edit_dir_remove(struct afs_vnodif (!afs_dir_init_iter (&iter, name))return ; - meta =afs_dir_find_block (&iter,0 ); + meta =afs_dir_get_block (&iter,0 );if (!meta)return ;
Greg Kroah-Hartman
maintainerPATCH 613/744 btrfs: do not try compression for data reloc inodes
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
commit ae4316f332e03e628712e9dfb89f2b7d3c70c21a upstream.
[BUG]
There is a syzbot report that the check inside get_new_location() triggered:
BTRFS info (device loop0): found 31 extents, stage: move data extents
BTRFS info (device loop0): leaf 8908800 gen 16 total ptrs 28 free space 1676 owner 18446744073709551607
item 0 key (256 INODE_ITEM 0) itemoff 3835 itemsize 160
inode generation 5 transid 0 size 0 nbytes 0
block group 0 mode 40755 links 1 uid 0 gid 0
rdev 0 sequence 0 flags 0x0
atime 1669132761.0
ctime 1669132761.0
mtime 1669132761.0
otime 0.0
item 1 key (256 INODE_REF 256) itemoff 3823 itemsize 12
index 0 name_len 2
item 2 key (258 INODE_ITEM 0) itemoff 3663 itemsize 160
inode generation 1 transid 16 size 733184 nbytes 106496
block group 0 mode 100600 links 0 uid 0 gid 0
rdev 0 sequence 24 flags 0x18
item 3 key (258 EXTENT_DATA 0) itemoff 3595 itemsize 68
generation 16 type 0
inline extent data size 47 ram_bytes 4096 compression 1
[...]
item 27 key (18446744073709551611 ORPHAN_ITEM 258) itemoff 2376 itemsize 0
BTRFS error (device loop0): unexpected non-zero offset in file extent item for data reloc inode 258 key offset 0 offset 9277520992061368337
------------[ cut here ]------------
btrfs_abort_should_print_stack(__error)[CAUSE]
The above dump tree shows the first file extent item is inlined, which should make no sense for data reloc inodes, as such inodes just represent where the data extents are in the relocation destination chunk.
However the relocation path preallocates space for each block, then dirties them, cluster by cluster.
It's possible to have a single block at the beginning of the block group, and no other block in the same cluster.
So relocation will preallocate a file extent for that block and dirty the first block. Then memory pressure forces the data reloc inode to be written back, before any other blocks are dirtied/allocated.
Finally commit 3eaf5f082c4c ("btrfs: extract inlined creation into a dedicated delalloc helper") changed the sequence of delalloc. Before that commit we always tried NOCOW first, so that dirtied block would be written back into the preallocated space, and appear as a regular extent.
But with that commit, we always try inline first, and since compression is forced, we try compressing the first block, and then inline the compressed data, resulting in the above inlined file extent in the data reloc tree.
Then the check in get_new_location() will check the file offset, without checking if the file extent is inlined or not, resulting in the above failure.
[FIX]
Do not allow compression for data reloc inodes.
Since data reloc inode sizes are always block aligned, as long as we do not compress, @data_len will always be at least one block, and that will cause can_cow_file_range_inline() to return false, thus no inlined extent will be created.
--- fs/btrfs/btrfs_inode.h | 2 ++ 1 file changed, 2 insertions(+)
fs/btrfs/btrfs_inode.h +2 -0
@@ -507,6 +507,8 @@ static inline bool btrfs_inode_can_comprif (inode->flags &BTRFS_INODE_NODATACOW || inode->flags &BTRFS_INODE_NODATASUM )return false; +if (btrfs_is_data_reloc_root (inode->root)) +return false;return true; }
Greg Kroah-Hartman
maintainerPATCH 614/744 userfaultfd: prevent registration of special VMAs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Rapoport (Microsoft) <[email protected]>
commit 3c58f641e813c3c71039f8fd4d4e2a3aab713288 upstream.
Vova Tokarev says:
userfaultfd allows registration on shadow stack VMAs. With userfaultfd access, you can register on the shadow stack, discard a page ... and inject a page with chosen return addresses via UFFDIO_COPY.
Update vma_can_userfault() to reject VM_SHADOW_STACK.
While on it, also reject VM_SPECIAL so that if a driver would implement vm_uffd_ops, it wouldn't be possible to register special VMAs with userfaultfd.
Since VM_SPECIAL includes VM_DONTEXPAND which is set but hugetlb, exclude hugetlb VMAs from the check for VM_SPECIAL.
--- mm/userfaultfd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
mm/userfaultfd.c +4 -1
@@ -2095,7 +2095,10 @@ bool vma_can_userfault(struct vm_area_st {const struct vm_uffd_ops *ops =vma_uffd_ops (vma); -if (vma->vm_flags &VM_DROPPABLE ) +if (vma->vm_flags & (VM_DROPPABLE |VM_SHADOW_STACK )) +return false; + +if (!is_vm_hugetlb_page (vma) && (vma->vm_flags &VM_SPECIAL ))return false; vm_flags &= __VM_UFFD_FLAGS;
Greg Kroah-Hartman
maintainerPATCH 615/744 mm/damon/core: validate ranges in damon_set_regions()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit 1292c0ecb1caefb8ca064a3639d5673991e8810c upstream.
DAMON core logic assumes zero length regions don't exist. However, a few DAMON API callers including DAMON_SYSFS, DAMON_RECLAIM and DAMON_LRU_SORT allow users to set empty monitoring target regions. This could result in WARN_ONCE() on CONFIG_DAMON_DEBUG_SANITY enabled kernel, and divide-by-zero from damon_merge_two_regions().
For example, the WANR_ONCE() can be triggered like below.
# grep DAMON_DEBUG_SANITY /boot/config-$(uname -r)
# CONFIG_DAMON_DEBUG_SANITY=y
# damo start
# cd /sys/kernel/mm/damon/admin/kdamonds/0
# echo 0 > contexts/0/targets/0/regions/0/start
# echo 0 > contexts/0/targets/0/regions/0/end
# echo commit > state
# dmesg
[....]
[ 73.705780] ------------[ cut here ]------------
[ 73.707552] start 0 >= end 0
[ 73.708452] WARNING: mm/damon/core.c:359 at damon_new_region+0x6e/0x80, CPU#1: kdamond.0/758
[...]All DAMON API callers eventually use damon_set_regions() to setup the regions. Add the validation logic in the function.
--- mm/damon/core.c | 6 ++++++ 1 file changed, 6 insertions(+)
mm/damon/core.c +6 -0
@@ -242,6 +242,12 @@ int damon_set_regions(struct damon_targeunsigned int i;int err; +for (i =0 ; i < nr_ranges; i++) { +if (ALIGN_DOWN (ranges[i].start, min_region_sz) >= +ALIGN (ranges[i].end, min_region_sz)) +return -EINVAL ; + } +/* Remove regions which are not in the new ranges */ damon_for_each_region_safe (r, next, t) {for (i =0 ; i < nr_ranges; i++) {
Greg Kroah-Hartman
maintainerPATCH 616/744 m68k: avoid -Wunused-but-set-parameter in clear_user_page()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Weißschuh <[email protected]>
commit 955b67c3ddf9912a670ed80eae7769745b4f405e upstream.
The loop in clear_user_pages() iterates over all pages and calls clear_user_page() for each of them. During the loop "vaddr" is modified. However on m68k clear_user() is a macro which does not use "vaddr". The compiler sees a variable which is modified but never used and emits a warning for that:
include/linux/highmem.h: In function 'clear_user_pages':include/linux/highmem.h:234:63: warning: parameter 'vaddr' set but not used [-Wunused-but-set-parameter=]
static inline void clear_user_pages(void *addr, unsigned long vaddr,
Other architectures use an inline function for clear_user_page() which avoids the warning. This is not possible on m68k, as dlush_dcache_page() is another macro which is not yet defined where clear_user_page() is defined. Including cacheflush_mm.h will trigger recursive and lots of other issues.
So hide the warning with a cast to (void) instead.
While we are here, do the same for copy_user_page().
--- arch/m68k/include/asm/page_mm.h | 2 ++ 1 file changed, 2 insertions(+)
arch/m68k/include/asm/page_mm.h +2 -0
@@ -55,10 +55,12 @@ static inline void clear_page(void *page#define clear_user_page (addr, vaddr, page) \ do { clear_page(addr); \ flush_dcache_page(page); \ + (void)(vaddr); \ } while (0)#define copy_user_page (to, from, vaddr, page) \ do { copy_page(to, from); \ flush_dcache_page(page); \ + (void)(vaddr); \ } while (0)extern unsigned long m68k_memoffset;
Greg Kroah-Hartman
maintainerPATCH 617/744 mm/damon/core: disallow overlapping input ranges for damon_set_regions()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit 954157679ec34661c2e87e7eb796104a797c32db upstream.
damon_set_regions() assumes the input ranges are sorted by the address and don't overlap each other. Hence the assumption was initially to be explicitly validated. But commit 97d482f4592f ("mm/damon/sysfs: reuse damon_set_regions() for regions setting") has mistakenly removed the validation.
This can make DAMON behave in unexpected ways. At the best, the monitoring results snapshot will just look weird since there will be overlapping regions. DAMOS will also work weirdly, applying the same action multiple times for overlapping regions, and make DAMOS quota weird. More seriously, depending on the setup and regions updates sequence, negative size regions can be made. It will trigger WARN_ONCE() if the kernel is built with CONFIG_DAMON_DEBUG_SANITY=y. Depending on the monitoring results, the negative size region can further trigger division by zero in damon_merge_two_regions().
Note that some of the consequences including the WARN_ONCE() and the divide by zero depend on commits that were introduced after the root cause commit 97d482f4592f ("mm/damon/sysfs: reuse damon_set_regions() for regions setting").
Fix the problems by checking the assumption and returning an error if the input ranges don't meet the assumption.
The issue was discovered [1] by Sashiko.
--- mm/damon/core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
mm/damon/core.c +9 -2
@@ -240,12 +240,19 @@ int damon_set_regions(struct damon_targe {struct damon_region *r, *next;unsigned int i; +unsigned long last_end;int err;for (i =0 ; i < nr_ranges; i++) { -if (ALIGN_DOWN (ranges[i].start, min_region_sz) >= -ALIGN (ranges[i].end, min_region_sz)) +unsigned long start, end; + + start =ALIGN_DOWN (ranges[i].start, min_region_sz); + end =ALIGN (ranges[i].end, min_region_sz); +if (start >= end) +return -EINVAL ; +if (i >0 && last_end > start)return -EINVAL ; + last_end = end; }/* Remove regions which are not in the new ranges */
Greg Kroah-Hartman
maintainerPATCH 618/744 mm/kmemleak: fix checksum computation for per-cpu objects
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
commit 79c37ae3733e93d9d8ea12ecb44f717e61439024 upstream.
The per-cpu object checksum folds each CPU's CRC together with XOR and seeds every CRC with 0. Both choices make update_checksum() miss content changes:
- XOR is self-cancelling, so equal contents on two CPUs cancel out and simultaneous identical changes leave the checksum unchanged.
- crc32(0, ...) over all-zero content is 0, so a freshly allocated, zeroed per-cpu area checksums to 0, matching the initial value, and the object is never seen to change.
See discussions at [0].
When update_checksum() wrongly reports an actively modified object as unchanged, kmemleak stops greying it for an extra scan and can report a live per-cpu object as a leak.
Fold the per-cpu CRC as a single rolling checksum across all CPUs and initialise the object checksum to ~0 so the first computed value always registers as a change, even for content that hashes to 0. reset_checksum() is seeded the same way.
--- mm/kmemleak.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
mm/kmemleak.c +4 -3
@@ -676,7 +676,7 @@ static struct kmemleak_object *__alloc_oatomic_set (&object->use_count,1 ); object->excess_ref =0 ; object->count =0 ;/* white color initially */ - object->checksum =0 ; + object->checksum = ~0 ; object->del_state =0 ;/* task information */
@@ -970,7 +970,7 @@ static void reset_checksum(unsigned long }raw_spin_lock_irqsave (&object->lock, flags); - object->checksum =0 ; + object->checksum = ~0 ;raw_spin_unlock_irqrestore (&object->lock, flags);put_object (object); }
@@ -1399,7 +1399,8 @@ static bool update_checksum(struct kmemlfor_each_possible_cpu (cpu) {void *ptr =per_cpu_ptr ((void __percpu *)object->pointer, cpu); - object->checksum ^=crc32 (0 ,kasan_reset_tag ((void *)ptr), object->size); + object->checksum =crc32 (object->checksum, +kasan_reset_tag ((void *)ptr), object->size); } }else { object->checksum =crc32 (0 ,kasan_reset_tag ((void *)object->pointer), object->size);
Greg Kroah-Hartman
maintainerPATCH 619/744 mm/memory-failure: trace: change memory_failure_event to ras subsystem
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xie Yuanbin <[email protected]>
commit e57d6e9e20b551e4910d7a6331a81775c3ad6693 upstream.
Commit 97f0b1345219 ("tracing: add trace event for memory-failure") introduced memory_failure_event in ras subsystem. commit 31807483d395 ("mm/memory-failure: remove the selection of RAS") changed memory_failure_event to memory_failure subsystem. This breaks the backward compatibility, some user programs rely on it.
Change memory_failure_event to ras subsystem to keep backward compatibility.
--- include/trace/events/memory-failure.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
include/trace/events/memory-failure.h +5 -1
@@ -1,6 +1,10 @@/* SPDX-License-Identifier: GPL-2.0 */ #undef TRACE_SYSTEM -#define TRACE_SYSTEM memory_failure +/* +* For historical versions, memory_failure_event is in ras subsystem, +* some user programs depend on it. +*/ +#define TRACE_SYSTEM ras#define TRACE_INCLUDE_FILE memory-failure#if !defined(_TRACE_MEMORY_FAILURE_H) || defined(TRACE_HEADER_MULTI_READ )
Greg Kroah-Hartman
maintainerPATCH 620/744 mm/page_vma_mapped: fix device-private PMD handling
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Yang <[email protected]>
commit f84ca9b1888d8fce7dfefe0e750fa971f8797486 upstream.
Commit 65edfda6f3f2 ("mm/rmap: extend rmap and migration support device-private entries") introduced the concept of device-private PMD entries, but did not correctly update the rmap walk code to account for them.
As a result, when page_vma_mapped_walk() encounters device-private PMD entries, it takes no action other than to acquire the PMD lock and exit.
However this is highly problematic for two reasons - firstly, device private entries possess a PFN so check_pmd() needs to be called to ensure an overlapping PFN range.
Secondly, and more importantly, if PVMW_MIGRATION is set the caller assumes the returned entry is a migration entry, resulting in memory corruption when the caller tries to interpret the device private entry as such.
In addition, commit 146287290023 ("mm/huge_memory: implement device-private THP splitting") allowed device private PMDs to be split like THP mappings, but again did not update this code path.
As a result, we might race a PMD split prior to acquiring the PMD lock.
This patch addresses all of these issues by invoking check_pmd(), ensuring PMVW_MIGRATION is not set and checks whether a split raced us we do for PMD THP and migration entries.
Instead of checking for a subset of the cases after taking the pmd_lock(), put device-private along with pmd_trans_huge() and pmd_is_migration_entry(). Also remove thp_migration_supported() as it is already guarded by pmd_is_migration_entry().
--- mm/page_vma_mapped.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-)
mm/page_vma_mapped.c +17 -14
@@ -242,21 +242,31 @@ restart:*/ pmde =pmdp_get_lockless (pvmw->pmd); -if (pmd_trans_huge (pmde) ||pmd_is_migration_entry (pmde)) { +if (IS_ENABLED (CONFIG_TRANSPARENT_HUGEPAGE ) && + (pmd_trans_huge (pmde) ||pmd_is_migration_entry (pmde) || +pmd_is_device_private_entry (pmde))) { pvmw->ptl =pmd_lock (mm, pvmw->pmd); pmde = *pvmw->pmd; -if (!pmd_present (pmde)) { +if (pmd_is_migration_entry (pmde)) {softleaf_t entry; -if (!thp_migration_supported () || - !(pvmw->flags &PVMW_MIGRATION )) +if (!(pvmw->flags &PVMW_MIGRATION ))return not_found (pvmw); entry =softleaf_from_pmd (pmde); +if (!check_pmd (softleaf_to_pfn (entry), pvmw)) +return not_found (pvmw); +return true; + }else if (pmd_is_device_private_entry (pmde)) { +softleaf_t entry; -if (!softleaf_is_migration (entry) || - !check_pmd (softleaf_to_pfn (entry), pvmw)) +if (pvmw->flags &PVMW_MIGRATION ) +return not_found (pvmw); + entry =softleaf_from_pmd (pmde); +if (!check_pmd (softleaf_to_pfn (entry), pvmw))return not_found (pvmw);return true; + }else if (!pmd_present (pmde)) { +return not_found (pvmw); }if (likely (pmd_trans_huge (pmde))) {if (pvmw->flags &PVMW_MIGRATION )
@@ -265,17 +275,10 @@ restart:return not_found (pvmw);return true; } -/* THP pmd was split under us: handle on pte level */ +/* THP/device-private pmd was split under us: handle on pte level */ spin_unlock (pvmw->ptl); pvmw->ptl =NULL ; }else if (!pmd_present (pmde)) { -const softleaf_t entry =softleaf_from_pmd (pmde); - -if (softleaf_is_device_private (entry)) { - pvmw->ptl =pmd_lock (mm, pvmw->pmd); -return true; - } - if ((pvmw->flags & PVMW_SYNC) && thp_vma_suitable_order(vma, pvmw->address, PMD_ORDER) &&
Greg Kroah-Hartman
maintainerPATCH 621/744 mm/huge_memory: set PG_has_hwpoisoned only after new folio head is established
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rik van Riel <[email protected]>
commit e1cd30eceb6908fc13bebce41283b885d71ee8d6 upstream.
__split_folio_to_order() copies the hwpoison state onto each new sub-folio while splitting a folio to a non-zero order. It does so via
if (handle_hwpoison && page_range_has_hwpoisoned(new_head, new_nr_pages)) folio_set_has_hwpoisoned(new_folio);
*before* clear_compound_head(new_head)/prep_compound_page(new_head, ...) turns @new_head from a tail page into a proper folio head.
PG_has_hwpoisoned is a FOLIO_SECOND_PAGE flag, so folio_set_has_hwpoisoned() resolves to folio_flags(folio, 1). With the new compound_info-based page-flags layout, folio_flags() asserts the page is not a tail:
VM_BUG_ON_PGFLAGS(page->compound_info & 1, page); VM_BUG_ON_PGFLAGS(n > 0 && !test_bit(PG_head, &page->flags.f), page);
At the current call site @new_head still has the tail marker (compound_info bit 0 set, PG_head clear), so on CONFIG_DEBUG_VM kernels this hits:
kernel BUG at include/linux/page-flags.h:354 folio_flags+0x82
folio_set_has_hwpoisoned
__split_folio_to_order
__split_unmapped_folio
__folio_split
truncate_inode_partial_folio (shmem hole-punch / MADV_REMOVE)
Reproduced by syzkaller: hwpoison-inject a few subpages of a large shmem folio, then MADV_REMOVE (fallocate punch hole) on the same range, which splits the partial folio to a non-zero order.
memory_failure() tries to split the poisoned folio to order 0 first, but that split is best-effort; when it fails the folio is left large with PG_has_hwpoisoned set, the case fa5a06170036 added this hwpoison copying for.
Move the folio_set_has_hwpoisoned() call to after clear_compound_head()/prep_compound_page(), where @new_folio is a real order-new_order head folio (handle_hwpoison implies new_order != 0, so a second page always exists). The flag still lands on the same struct page (page[1] of the new folio); only the ordering relative to compound-head setup changes, satisfying the FOLIO_SECOND_PAGE precondition.
--- mm/huge_memory.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
mm/huge_memory.c +8 -4
@@ -3649,10 +3649,6 @@ static void __split_folio_to_order(struc (1L << PG_dropbehind) | LRU_GEN_MASK | LRU_REFS_MASK)); -if (handle_hwpoison && -page_range_has_hwpoisoned (new_head, new_nr_pages)) -folio_set_has_hwpoisoned (new_folio); - new_folio->mapping = folio->mapping; new_folio->index = folio->index + i;
@@ -3674,6 +3670,14 @@ static void __split_folio_to_order(strucfolio_set_large_rmappable (new_folio); } +/* +* PG_has_hwpoisoned is on the 2nd page, so set it after +* the compound head is prepped. +*/ +if (handle_hwpoison && +page_range_has_hwpoisoned (new_head, new_nr_pages)) +folio_set_has_hwpoisoned (new_folio); +if (folio_test_young (folio))folio_set_young (new_folio);if (folio_test_idle (folio))
Greg Kroah-Hartman
maintainerPATCH 622/744 sctp: dont free the ASCONFs own transport in DEL-IP processing
In reply to Greg Kroah-Hartman7.1-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
@@ -3153,6 +3153,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 623/744 sctp: avoid auth_enable sysctl UAF during netns teardown
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit f8d5e7846025f4ab15a461235f8ebae9094a361a upstream.
proc_sctp_do_auth() updates the SCTP control socket after changing net.sctp.auth_enable. The handler gets the per-net SCTP state from ctl->data, so an already opened sysctl file can still target a network namespace while that namespace is being torn down.
SCTP previously registered its per-net sysctls from sctp_defaults_init(), while the control socket is created later from sctp_ctrlsock_init(). This exposed a window during initialization where auth_enable was writable before net->sctp.ctl_sock existed, and a teardown window where auth_enable stayed writable after inet_ctl_sock_destroy() had released the control socket.
Move the per-net SCTP sysctl registration into sctp_ctrlsock_init() after sctp_ctl_sock_init() succeeds, and unregister the sysctl table before destroying the control socket in sctp_ctrlsock_exit(). If sysctl registration fails after the control socket was created, destroy the control socket in the same init path.
Make sctp_sysctl_net_unregister() tolerate a missing header and clear the saved pointer so init-error and exit paths can safely share the unregister helper.
--- net/sctp/protocol.c | 20 ++++++++++++-------- net/sctp/sysctl.c | 9 +++++++-- 2 files changed, 19 insertions(+), 10 deletions(-)
net/sctp/protocol.c +12 -8
@@ -1377,10 +1377,6 @@ static int __net_init sctp_defaults_init net->sctp.l3mdev_accept =1 ;#endif - status =sctp_sysctl_net_register (net); -if (status) - goto err_sysctl_register; -/* Allocate and initialise sctp mibs. */ status =init_sctp_mibs (net);if (status)
@@ -1414,8 +1410,6 @@ err_init_proc:cleanup_sctp_mibs (net);#endif err_init_mibs: -sctp_sysctl_net_unregister (net); -err_sysctl_register:return status; }
@@ -1430,7 +1424,6 @@ static void __net_exit sctp_defaults_exi net->sctp.proc_net_sctp =NULL ;#endif cleanup_sctp_mibs (net); -sctp_sysctl_net_unregister (net); }static struct pernet_operations sctp_defaults_ops = {
@@ -1444,16 +1437,27 @@ static int __net_init sctp_ctrlsock_init/* Initialize the control inode/socket for handling OOTB packets. */ status =sctp_ctl_sock_init (net); -if (status) +if (status) {pr_err ("Failed to initialize the SCTP control sock\n" ); +return status; + } + + status =sctp_sysctl_net_register (net); +if (status) { +inet_ctl_sock_destroy (net->sctp.ctl_sock); + net->sctp.ctl_sock =NULL ; + }return status; } static void __net_exit sctp_ctrlsock_exit(struct net *net) { +sctp_sysctl_net_unregister (net); +/* Free the control endpoint. */ inet_ctl_sock_destroy (net->sctp.ctl_sock); + net->sctp.ctl_sock =NULL ; }static struct pernet_operations sctp_ctrlsock_ops = {
net/sctp/sysctl.c +7 -2
@@ -615,11 +615,16 @@ int sctp_sysctl_net_register(struct netvoid sctp_sysctl_net_unregister (struct net *net) { +struct ctl_table_header *header = net->sctp.sysctl_header;const struct ctl_table *table; - table = net->sctp.sysctl_header->ctl_table_arg; -unregister_net_sysctl_table (net->sctp.sysctl_header); +if (!header) +return ; + + table = header->ctl_table_arg; +unregister_net_sysctl_table (header);kfree (table); + net->sctp.sysctl_header =NULL ; }static struct ctl_table_header *sctp_sysctl_header;
Greg Kroah-Hartman
maintainerPATCH 624/744 sctp: close UDP tunnel sockets during netns teardown
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit ffb2bd7ade36ec4da32c46a6eddbf4515316d08c upstream.
proc_sctp_do_udp_port() starts per-net SCTP UDP tunneling sockets when net.sctp.udp_port is set, and stops/restarts them when the sysctl value changes. The netns exit path does not stop these sockets, so a namespace can be torn down while its SCTP UDP tunnel sockets are still installed.
Close the UDP tunnel sockets from sctp_ctrlsock_exit() after unregistering the per-net sysctl table. This prevents new sysctl writes from racing in while the sockets are being released, and closes the sockets before the control socket is destroyed.
--- net/sctp/protocol.c | 1 + 1 file changed, 1 insertion(+)
net/sctp/protocol.c +1 -0
@@ -1454,6 +1454,7 @@ static int __net_init sctp_ctrlsock_init static void __net_exit sctp_ctrlsock_exit(struct net *net) {sctp_sysctl_net_unregister (net); +sctp_udp_sock_stop (net);/* Free the control endpoint. */ inet_ctl_sock_destroy (net->sctp.ctl_sock);
Greg Kroah-Hartman
maintainerPATCH 625/744 ceph: add owner/capability checks for CEPH_IOC_SET_LAYOUT*
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
commit cee38bbf5556a8e0a232ccae41649580827d7806 upstream.
These permission checks were already missing in the initial impementation of these ioctls. This Ceph allows any user who owns a file descriptor to manipulate the layout of any file, even if they don't have write permissions.
It might be a good idea to guard other ioctls with permission checks as well or even disallow regular users (even if they own the file) to manipulate layout settings completely, as this may be abused to DoS the Ceph servers, but right now, I find it most urgent to have setter checks at all.
--- fs/ceph/ioctl.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/ceph/ioctl.c +6 -0
@@ -72,6 +72,9 @@ static long ceph_ioctl_set_layout(structstruct ceph_ioctl_layout nl;int err; +if (!inode_owner_or_capable (&nop_mnt_idmap, inode)) +return -EACCES ; +if (copy_from_user (&l, arg,sizeof (l)))return -EFAULT ;
@@ -142,6 +145,9 @@ static long ceph_ioctl_set_layout_policyint err;struct ceph_mds_client *mdsc =ceph_sb_to_fs_client (inode->i_sb)->mdsc; +if (!inode_owner_or_capable (&nop_mnt_idmap, inode)) +return -EACCES ; +/* copy and validate */ if (copy_from_user (&l, arg,sizeof (l)))return -EFAULT ;
Re: [PATCH 7.1 625/744] ceph: add owner/capability checks for CEPH_IOC_SET_LAYOUT*
Quoted 45 lines · Greg Kroah-Hartman
7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
commit
cee38bbf5556a8e0a232ccae41649580827d7806upstream.These permission checks were already missing in the initial impementation of these ioctls. This Ceph allows any user who owns a file descriptor to manipulate the layout of any file, even if they don't have write permissions.
It might be a good idea to guard other ioctls with permission checks as well or even disallow regular users (even if they own the file) to manipulate layout settings completely, as this may be abused to DoS the Ceph servers, but right now, I find it most urgent to have setter checks at all.
Fixes 8f4e91dee2a2 ("ceph: ioctls")Signed-off-by Max Kellermann <[email protected]>Reviewed-by Xiubo Li <[email protected]>Signed-off-by Ilya Dryomov <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- fs/ceph/ioctl.c | 6 ++++++ 1 file changed, 6 insertions(+)fs/ceph/ioctl.c +3
-0@@ -72,6 +72,9 @@ static long ceph_ioctl_set_layout(structstruct ceph_ioctl_layout nl;int err; +if (!inode_owner_or_capable (&nop_mnt_idmap, inode)) +return -EACCES ; +if (copy_from_user (&l, arg,sizeof (l)))return -EFAULT ;
fs/ceph/ioctl.c static long ceph_ioctl_set_layout_policy · line 153
Quoted 9 lines
fs/ceph/ioctl.c +3
-0@@ -142,6 +145,9 @@ static long ceph_ioctl_set_layout_policyint err;struct ceph_mds_client *mdsc =ceph_sb_to_fs_client (inode->i_sb)->mdsc; +if (!inode_owner_or_capable (&nop_mnt_idmap, inode)) +return -EACCES ; +/* copy and validate */ if (copy_from_user (&l, arg,sizeof (l)))return -EFAULT ;
Hi Greg,
There is a concern about the correctness of this patch, please drop it for now.
Thanks,
Ilya
Greg Kroah-Hartman
maintainerRe: [PATCH 7.1 625/744] ceph: add owner/capability checks for CEPH_IOC_SET_LAYOUT*
Quoted 59 lines · Ilya Dryomov
Quoted 45 lines · Greg Kroah-Hartman
7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
commit
cee38bbf5556a8e0a232ccae41649580827d7806upstream.These permission checks were already missing in the initial impementation of these ioctls. This Ceph allows any user who owns a file descriptor to manipulate the layout of any file, even if they don't have write permissions.
It might be a good idea to guard other ioctls with permission checks as well or even disallow regular users (even if they own the file) to manipulate layout settings completely, as this may be abused to DoS the Ceph servers, but right now, I find it most urgent to have setter checks at all.
Fixes 8f4e91dee2a2 ("ceph: ioctls")Signed-off-by Max Kellermann <[email protected]>Reviewed-by Xiubo Li <[email protected]>Signed-off-by Ilya Dryomov <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- fs/ceph/ioctl.c | 6 ++++++ 1 file changed, 6 insertions(+)fs/ceph/ioctl.c +3
-0@@ -72,6 +72,9 @@ static long ceph_ioctl_set_layout(structstruct ceph_ioctl_layout nl;int err; +if (!inode_owner_or_capable (&nop_mnt_idmap, inode)) +return -EACCES ; +if (copy_from_user (&l, arg,sizeof (l)))return -EFAULT ;fs/ceph/ioctl.c static long ceph_ioctl_set_layout_policy · line 153
Quoted 9 lines
fs/ceph/ioctl.c +3
-0@@ -142,6 +145,9 @@ static long ceph_ioctl_set_layout_policyint err;struct ceph_mds_client *mdsc =ceph_sb_to_fs_client (inode->i_sb)->mdsc; +if (!inode_owner_or_capable (&nop_mnt_idmap, inode)) +return -EACCES ; +/* copy and validate */ if (copy_from_user (&l, arg,sizeof (l)))return -EFAULT ;Hi Greg,
Quoted 2 lines
There is a concern about the correctness of this patch, please drop it for now.
Ok, dropped now from all branches. If you want it back, please let us know in the future.
thanks,
greg k-h
Greg Kroah-Hartman
maintainerPATCH 626/744 ceph: fix pre-auth out-of-bounds read on snaptrace in ceph_handle_caps()
In reply to Greg Kroah-Hartman7.1-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
@@ -4365,6 +4365,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 627/744 ceph: fix refcount leak in ceph_readdir()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: WenTao Liang <[email protected]>
commit c3e64079d8b9663e3998d0caac9aba915b6b93ae upstream.
The ceph_readdir() function allocates a ceph_mds_request via ceph_mdsc_create_request() and stores it in dfi->last_readdir. In the directory entry processing loop, if the entry's offset is less than ctx->pos or if the inode pointer is unexpectedly NULL, the function returns -EIO without releasing the reference held by dfi->last_readdir, causing a refcount leak.
Fix this by adding ceph_mdsc_put_request(dfi->last_readdir) before returning on these error paths. Also set dfi->last_readdir to NULL for safety, matching the cleanup done at the normal exit.
--- fs/ceph/dir.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/ceph/dir.c +6 -1
@@ -546,11 +546,16 @@ more:pr_warn_client (cl,"%p %llx.%llx rde->offset 0x%llx ctx->pos 0x%llx\n" , inode,ceph_vinop (inode), rde->offset, ctx->pos); +ceph_mdsc_put_request (dfi->last_readdir); + dfi->last_readdir =NULL ;return -EIO ; } -if (WARN_ON_ONCE (!rde->inode.in)) +if (WARN_ON_ONCE (!rde->inode.in)) { +ceph_mdsc_put_request (dfi->last_readdir); + dfi->last_readdir =NULL ;return -EIO ; + } ctx->pos = rde->offset; doutc(cl, "%p %llx.%llx (%d/%d) -> %llx '%.*s' %p\n", inode,
Greg Kroah-Hartman
maintainerPATCH 628/744 ceph: fix writeback_count leak in write_folio_nounlock()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit cbf59617cd715219e84c50d106a3d0e1e8ba054e upstream.
write_folio_nounlock() increments fsc->writeback_count to track in-flight writeback operations. On several error paths where the function returns early (folio lookup failure, snapshot context allocation failure, and writepages submission failure), the function returns without calling atomic_long_dec_return() to decrement the counter.
Each leaked increment keeps the counter above zero, which can prevent the filesystem from cleanly unmounting or suspending writes.
Add atomic_long_dec_return() calls on all error paths that currently return without decrementing the counter.
--- fs/ceph/addr.c | 9 +++++++++ 1 file changed, 9 insertions(+)
fs/ceph/addr.c +9 -0
@@ -790,6 +790,9 @@ static int write_folio_nounlock(struct f ceph_wbc.truncate_size, true);if (IS_ERR (req)) {folio_redirty_for_writepage (wbc, folio); +if (atomic_long_dec_return (&fsc->writeback_count) < +CONGESTION_OFF_THRESH (fsc->mount_options->congestion_kb)) + fsc->write_congested = false;return PTR_ERR (req); }
@@ -809,6 +812,9 @@ static int write_folio_nounlock(struct ffolio_redirty_for_writepage (wbc, folio);folio_end_writeback (folio);ceph_osdc_put_request (req); +if (atomic_long_dec_return (&fsc->writeback_count) < +CONGESTION_OFF_THRESH (fsc->mount_options->congestion_kb)) + fsc->write_congested = false;return PTR_ERR (bounce_page); } }
@@ -847,6 +853,9 @@ static int write_folio_nounlock(struct f ceph_vinop(inode), folio);folio_redirty_for_writepage (wbc, folio);folio_end_writeback (folio); +if (atomic_long_dec_return (&fsc->writeback_count) < +CONGESTION_OFF_THRESH (fsc->mount_options->congestion_kb)) + fsc->write_congested = false;return err; }if (err == -EBLOCKLISTED )
Greg Kroah-Hartman
maintainerPATCH 629/744 libceph: bound get_version reply decode to front len
In reply to Greg Kroah-Hartman7.1-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
@@ -821,7 +821,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 630/744 libceph: bound pg_{temp,upmap,upmap_items} length to CEPH_PG_MAX_SIZE
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
commit 9f00f9cf2be293efe899db67dc5272e3a9c62717 upstream.
__decode_pg_temp() decodes an user-controlled length but only rejects values large enough to overflow the allocation; it does not bound it to CEPH_PG_MAX_SIZE. The helper backs both pg_temp and pg_upmap decoding, and apply_upmap()/get_temp_osds() later copy the decoded list into the fixed-size on-stack array struct ceph_osds.osds[CEPH_PG_MAX_SIZE]. A monitor that sends an OSDMap with a pg_temp/pg_upmap entry longer than 32 thus causes a stack out-of-bounds write.
An OSD set for a single PG can never exceed CEPH_PG_MAX_SIZE, so reject longer entries at decode time. The bound is well below the old overflow threshold, so it also covers the allocation-size overflow the previous check guarded against.
BUG: KASAN: stack-out-of-bounds in ceph_pg_to_up_acting_osds Write of size 4 ... by task exploit kasan_report (mm/kasan/report.c:595) ceph_pg_to_up_acting_osds (net/ceph/osdmap.c:2617 net/ceph/osdmap.c:2833) calc_target (net/ceph/osd_client.c:1638) __submit_request (net/ceph/osd_client.c:2394) ceph_osdc_start_request (net/ceph/osd_client.c:2490) ceph_osdc_call (net/ceph/osd_client.c:5164) rbd_dev_image_probe (drivers/block/rbd.c:6899) do_rbd_add (drivers/block/rbd.c:7138) ... kernel BUG at net/ceph/osdmap.c:2670!
[ idryomov: do the same in __decode_pg_upmap_items() ]
--- net/ceph/osdmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/ceph/osdmap.c +2 -2
@@ -1436,7 +1436,7 @@ static struct ceph_pg_mapping *__decode_ceph_decode_32_safe (p, end, len, e_inval);if (len ==0 && incremental)return NULL ;/* new_pg_temp: [] to remove */ -if ((size_t )len > (SIZE_MAX -sizeof (*pg)) /sizeof (u32)) +if (len >CEPH_PG_MAX_SIZE )return ERR_PTR (-EINVAL );ceph_decode_need (p, end, len *sizeof (u32), e_inval);
@@ -1617,7 +1617,7 @@ static struct ceph_pg_mapping *__decode_u32 len, i;ceph_decode_32_safe (p, end, len, e_inval); -if ((size_t )len > (SIZE_MAX -sizeof (*pg)) / (2 *sizeof (u32))) +if (len >CEPH_PG_MAX_SIZE )return ERR_PTR (-EINVAL );ceph_decode_need (p, end,2 * len *sizeof (u32), e_inval);
Greg Kroah-Hartman
maintainerPATCH 631/744 libceph: Fix multiplication overflow in decode_new_up_state_weight()
In reply to Greg Kroah-Hartman7.1-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
@@ -1842,6 +1842,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 ret;int i;
@@ -1862,7 +1864,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 632/744 libceph: fix two unsafe bare decodes in decode_lockers()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavitra Jha <[email protected]>
commit a109a556115271ca7896dcda7b4b7e45e156c227 upstream.
decode_lockers() in cls_lock_client.c contains two bare decode operations that allow a malicious or compromised OSD to trigger slab-out-of-bounds reads:
1. ceph_decode_32(p) at the num_lockers field has no preceding bounds check. ceph_start_decoding() accepts struct_len=0 as valid -- the internal ceph_decode_need(p, end, 0, bad) always passes -- so when an OSD sends struct_len=0, ceph_start_decoding() returns success with p == end. The immediately following bare ceph_decode_32(p) then reads 4 bytes past the validated buffer boundary. The garbage value is passed directly to kzalloc_objs() as the locker count.
The sibling function decode_watchers() in osd_client.c already uses ceph_decode_32_safe() after its own ceph_start_decoding() call. decode_lockers() was the only site using the bare variant.
2. ceph_decode_8(p) after the decode_locker() loop has no preceding bounds check. If an OSD crafts num_lockers such that the loop advances p exactly to end, the subsequent bare ceph_decode_8(p) reads one byte past the validated buffer boundary. The result is passed directly into *type, which is used as a lock type discriminator by callers, giving an OSD-controlled one-byte OOB read with direct influence over the lock type field.
Fix both by replacing bare operations with their safe variants:
ceph_decode_32(p) -> ceph_decode_32_safe(p, end, *num_lockers,
err_inval)
ceph_decode_8(p) -> ceph_decode_8_safe(p, end, *type,
err_free_lockers)
The goto targets differ intentionally:
err_inval: is a new label returning -EINVAL directly. It is used for the pre-allocation failure path where *lockers is not yet allocated and must not be passed to ceph_free_lockers().
err_free_lockers: is the existing label. It is used for the post-allocation failure path where *lockers is allocated and must be freed.
ret is set to -EINVAL before ceph_decode_8_safe() so that err_free_lockers returns the correct error code on bounds violation. Without this, err_free_lockers would return a stale ret value (0 from the successful decode_locker() loop), silently swallowing the error.
-EINVAL is correct for both failure paths. The data received from the OSD is structurally malformed. -ENOMEM would misrepresent the failure class to callers and to stable@ backporters triaging error paths.
Attacker model: a malicious or compromised OSD in a multi-tenant Ceph deployment can trigger this against any kernel client that issues the lock.get_info class method (e.g. during RBD exclusive lock acquisition).
[ idryomov: trim changelog, formatting ]
--- net/ceph/cls_lock_client.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/ceph/cls_lock_client.c +6 -2
@@ -299,7 +299,7 @@ static int decode_lockers(void **p, voidif (ret)return ret; - *num_lockers =ceph_decode_32 (p); +ceph_decode_32_safe (p, end, *num_lockers, err_inval); *lockers =kzalloc_objs (**lockers, *num_lockers,GFP_NOIO );if (!*lockers)return -ENOMEM ;
@@ -310,7 +310,8 @@ static int decode_lockers(void **p, void goto err_free_lockers; } - *type =ceph_decode_8 (p); + ret = -EINVAL ; +ceph_decode_8_safe (p, end, *type, err_free_lockers); s =ceph_extract_encoded_string (p, end,NULL ,GFP_NOIO );if (IS_ERR (s)) { ret =PTR_ERR (s);
@@ -320,6 +321,9 @@ static int decode_lockers(void **p, void *tag = s;return 0 ; +err_inval: +return -EINVAL ; + err_free_lockers:ceph_free_lockers (*lockers, *num_lockers);return ret;
Greg Kroah-Hartman
maintainerPATCH 633/744 libceph: guard missing CRUSH type name lookup
In reply to Greg Kroah-Hartman7.1-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
@@ -3058,8 +3058,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 634/744 libceph: refresh auth->authorizer_buf{,_len} after authorizer update
In reply to Greg Kroah-Hartman7.1-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
@@ -849,9 +849,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 635/744 libceph: Reject monmaps advertising zero monitors
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit 40480eee361ed9676b3f844d532ac28b47251634 upstream.
A message of type CEPH_MSG_MON_MAP contains a monmap that is sent from a monitor to the client. This monmap contains information about the existing monitors in the cluster. Currently, a monmap indicating that there are zero monitors in the cluster is treated as valid. However, it is impossible to have zero monitors in the cluster and still receive a valid monmap from a monitor. Therefore, such a monmap must be corrupted and should be treated as invalid. Furthermore, a monmap with a monitor count of zero can subsequently crash the client when attempting to open a session with a monitor in __open_session(). This happens because the "BUG_ON(monc->monmap->num_mon < 1)" assertion in pick_new_mon() is triggered.
This patch extends a check in ceph_monmap_decode() to also reject arriving mon_maps with num_mon == 0 rather than only with num_mon > CEPH_MAX_MON.
[ idryomov: drop "log output for unusual values of num_mon" part ]
--- net/ceph/mon_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ceph/mon_client.c +1 -1
@@ -114,7 +114,7 @@ static struct ceph_monmap *ceph_monmap_ddout ("%s fsid %pU epoch %u num_mon %u\n" , __func__, &fsid, epoch, num_mon); -if (num_mon >CEPH_MAX_MON ) +if (num_mon ==0 || num_mon >CEPH_MAX_MON ) goto e_inval; monmap =kmalloc_flex (*monmap, mon_inst, num_mon,GFP_NOIO );
Greg Kroah-Hartman
maintainerPATCH 636/744 libceph: reject zero bucket types in crush_decode
In reply to Greg Kroah-Hartman7.1-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
@@ -518,6 +518,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 637/744 libceph: remove debugfs files before client teardown
In reply to Greg Kroah-Hartman7.1-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
@@ -762,13 +762,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 638/744 amt: fix use-after-free in AMT delayed works
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shihuang Liu <[email protected]>
commit ea20c44935d6142daecfa9b39d635033a7553e1b upstream.
When an AMT device is removed, pending delayed works can still access the freed amt_dev structure, which may result in kernel crashes or memory corruption.
amt_dev_stop() cancels req_wq and discovery_wq with cancel_delayed_work_sync(), but these works can be scheduled again from event_wq after the cancellation. This allows delayed works to access the freed amt_dev structure after the netdev has been released.
The following is a simple race scenario:
CPU0 CPU1
amt_dev_stop()cancel_delayed_work_sync()
amt_event_work() mod_delayed_work(req_wq)
free netdev
req_wq accesses freed amt_dev
Use disable_delayed_work_sync() in amt_dev_stop() to prevent req_wq and discovery_wq from being queued again and wait for running work items to complete.
The delayed works are disabled after initialization in amt_newlink() and enabled only when the device is successfully opened. This keeps the delayed work lifecycle synchronized with the lifetime of the AMT device.
--- drivers/net/amt.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
drivers/net/amt.c +11 -3
@@ -3034,9 +3034,15 @@ static int amt_dev_open(struct net_devic amt->event_idx =0 ; amt->nr_events =0 ; +enable_delayed_work (&amt->discovery_wq); +enable_delayed_work (&amt->req_wq); + err =amt_socket_create (amt); -if (err) +if (err) { +disable_delayed_work (&amt->req_wq); +disable_delayed_work (&amt->discovery_wq);return err; + } amt->req_cnt =0 ; amt->remote_ip =0 ;
@@ -3062,8 +3068,8 @@ static int amt_dev_stop(struct net_devicstruct sk_buff *skb;int i; -cancel_delayed_work_sync (&amt->req_wq); -cancel_delayed_work_sync (&amt->discovery_wq); +disable_delayed_work_sync (&amt->req_wq); +disable_delayed_work_sync (&amt->discovery_wq);cancel_delayed_work_sync (&amt->secret_wq);/* shutdown */
@@ -3317,6 +3323,8 @@ static int amt_newlink(struct net_deviceINIT_DELAYED_WORK (&amt->req_wq, amt_req_work);INIT_DELAYED_WORK (&amt->secret_wq, amt_secret_work);INIT_WORK (&amt->event_wq, amt_event_work); +disable_delayed_work (&amt->req_wq); +disable_delayed_work (&amt->discovery_wq);INIT_LIST_HEAD (&amt->tunnel_list);return 0 ; err:
Greg Kroah-Hartman
maintainerPATCH 639/744 ASoC: fsl: imx-card: Skip sysclk reset for active DAIs in shutdown
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chancel Liu <[email protected]>
commit 9f86aea992568c2b4db78c80ff9508af9e050ff7 upstream.
In a full-duplex setup, when one direction (playback or capture) is closed while the other is still running, imx_aif_shutdown() was unconditionally calling snd_soc_dai_set_sysclk() with rate=0 for all cpu/codec DAIs, which would disable the clock still needed by the active stream.
Add snd_soc_dai_active() checks before clearing sysclk so that only truly inactive DAIs have their clocks reset.
--- sound/soc/fsl/imx-card.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
sound/soc/fsl/imx-card.c +8 -4
@@ -496,11 +496,15 @@ static void imx_aif_shutdown(struct snd_struct snd_soc_dai *codec_dai;int i; -for_each_rtd_cpu_dais (rtd, i, cpu_dai) -snd_soc_dai_set_sysclk (cpu_dai,0 ,0 ,SND_SOC_CLOCK_OUT ); +for_each_rtd_cpu_dais (rtd, i, cpu_dai) { +if (!snd_soc_dai_active (cpu_dai)) +snd_soc_dai_set_sysclk (cpu_dai,0 ,0 ,SND_SOC_CLOCK_OUT ); + } -for_each_rtd_codec_dais (rtd, i, codec_dai) -snd_soc_dai_set_sysclk (codec_dai,0 ,0 ,SND_SOC_CLOCK_IN ); +for_each_rtd_codec_dais (rtd, i, codec_dai) { +if (!snd_soc_dai_active (codec_dai)) +snd_soc_dai_set_sysclk (codec_dai,0 ,0 ,SND_SOC_CLOCK_IN ); + } }static const struct snd_soc_ops imx_aif_ops = {