6.1.191-rc1 review
Subsystems (12)
Greg Kroah-Hartman
maintainerPATCH 1619/1887 drm/sched: Use struct for drm_sched_init() params
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Philipp Stanner <[email protected]>
[ Upstream commit 796a9f55a8d1d85387b973df9a06cbf4bc2d6327 ]
drm_sched_init() has a great many parameters and upcoming new functionality for the scheduler might add even more. Generally, the great number of parameters reduces readability and has already caused one missnaming, addressed in:
commit 6f1cacf4eba7 ("drm/nouveau: Improve variable name in nouveau_sched_init()").
Introduce a new struct for the scheduler init parameters and port all users.
[ Adapted to this tree: drm_sched_init() here still takes the older
parameter set, so the new struct drm_sched_init_args carries only the fields that exist (no submit_wq or num_rqs). Only the drivers present in this tree are converted. ]
Stable-dep-of: e2332abed2a4 ("drm/msm: Only fini scheduler after successful init")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 17 +++++--- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 13 ++++-- drivers/gpu/drm/lima/lima_sched.c | 13 ++++-- drivers/gpu/drm/msm/msm_ringbuffer.c | 15 +++---- drivers/gpu/drm/panfrost/panfrost_job.c | 16 +++++--- drivers/gpu/drm/scheduler/sched_main.c | 33 ++++++---------- drivers/gpu/drm/v3d/v3d_sched.c | 46 ++++++++++------------ include/drm/gpu_scheduler.h | 29 ++++++++++++-- 8 files changed, 105 insertions(+), 77 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +12 -5
@@ -2403,6 +2403,12 @@ static int amdgpu_device_fw_loading(struct amdgpu_device *adev)static int amdgpu_device_init_schedulers (struct amdgpu_device *adev) { +struct drm_sched_init_args args = { + .ops = &amdgpu_sched_ops, + .hang_limit = amdgpu_job_hang_limit, + .timeout_wq = adev->reset_domain->wq, + .dev = adev->dev, + };long timeout;int r, i;
@@ -2428,11 +2434,12 @@ static int amdgpu_device_init_schedulers(struct amdgpu_device *adev)break ; } - r =drm_sched_init (&ring->sched, &amdgpu_sched_ops, - ring->num_hw_submission, amdgpu_job_hang_limit, - timeout, adev->reset_domain->wq, - ring->sched_score, ring->name, - adev->dev); + args.timeout = timeout; + args.credit_limit = ring->num_hw_submission; + args.score = ring->sched_score; + args.name = ring->name; + + r =drm_sched_init (&ring->sched, &args);if (r) {DRM_ERROR ("Failed to create scheduler on ring %s.\n" , ring->name);
drivers/gpu/drm/etnaviv/etnaviv_sched.c +9 -4
@@ -133,12 +133,17 @@ int etnaviv_sched_push_job(struct etnaviv_gem_submit *submit)int etnaviv_sched_init (struct etnaviv_gpu *gpu) { +struct drm_sched_init_args args = { + .ops = &etnaviv_sched_ops, + .credit_limit = etnaviv_hw_jobs_limit, + .hang_limit = etnaviv_job_hang_limit, + .timeout =msecs_to_jiffies (500 ), + .name =dev_name (gpu->dev), + .dev = gpu->dev, + };int ret; - ret =drm_sched_init (&gpu->sched, &etnaviv_sched_ops, - etnaviv_hw_jobs_limit, etnaviv_job_hang_limit, -msecs_to_jiffies (500 ),NULL ,NULL , -dev_name (gpu->dev), gpu->dev); + ret =drm_sched_init (&gpu->sched, &args);if (ret)return ret;
drivers/gpu/drm/lima/lima_sched.c +9 -4
@@ -489,16 +489,21 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) {unsigned int timeout = lima_sched_timeout_ms >0 ? lima_sched_timeout_ms :500 ; +struct drm_sched_init_args args = { + .ops = &lima_sched_ops, + .credit_limit =1 , + .hang_limit = lima_job_hang_limit, + .timeout =msecs_to_jiffies (timeout), + .name = name, + .dev = pipe->ldev->dev, + }; pipe->fence_context =dma_fence_context_alloc (1 );spin_lock_init (&pipe->fence_lock);INIT_WORK (&pipe->recover_work, lima_sched_recover_work); -return drm_sched_init (&pipe->base, &lima_sched_ops,1 , - lima_job_hang_limit, -msecs_to_jiffies (timeout),NULL , -NULL , name, pipe->ldev->dev); +return drm_sched_init (&pipe->base, &args); }void lima_sched_pipe_fini (struct lima_sched_pipe *pipe)
drivers/gpu/drm/msm/msm_ringbuffer.c +8 -7
@@ -56,8 +56,13 @@ static const struct drm_sched_backend_ops msm_sched_ops = {struct msm_ringbuffer *msm_ringbuffer_new (struct msm_gpu *gpu,int id,void *memptrs,uint64_t memptrs_iova) { +struct drm_sched_init_args args = { + .ops = &msm_sched_ops, + .credit_limit = num_hw_submissions, + .timeout =MAX_SCHEDULE_TIMEOUT , + .dev = gpu->dev->dev, + };struct msm_ringbuffer *ring; -long sched_timeout;char name[32 ];int ret;
@@ -84,6 +89,7 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id, }msm_gem_object_set_name (ring->bo,"ring%d" , id); + args.name =to_msm_bo (ring->bo)->name; ring->end = ring->start + (MSM_GPU_RINGBUFFER_SZ >>2 ); ring->next = ring->start;
@@ -92,12 +98,7 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id, ring->memptrs = memptrs; ring->memptrs_iova = memptrs_iova; -/* currently managing hangcheck ourselves: */ - sched_timeout =MAX_SCHEDULE_TIMEOUT ; - - ret =drm_sched_init (&ring->sched, &msm_sched_ops, - num_hw_submissions,0 , sched_timeout, -NULL ,NULL ,to_msm_bo (ring->bo)->name, gpu->dev->dev); + ret =drm_sched_init (&ring->sched, &args);if (ret) { goto fail; }
drivers/gpu/drm/panfrost/panfrost_job.c +10 -6
@@ -777,6 +777,12 @@ int panfrost_job_init(struct panfrost_device *pfdev) {struct panfrost_job_slot *js;unsigned int nentries =2 ; +struct drm_sched_init_args args = { + .ops = &panfrost_sched_ops, + .timeout =msecs_to_jiffies (JOB_TIMEOUT_MS ), + .name ="pan_js" , + .dev = pfdev->dev, + };int ret, j;/* All GPUs have two entries per queue, but without jobchain
@@ -811,15 +817,13 @@ int panfrost_job_init(struct panfrost_device *pfdev)if (!pfdev->reset.wq)return -ENOMEM ; + args.credit_limit = nentries; + args.timeout_wq = pfdev->reset.wq; +for (j =0 ; j <NUM_JOB_SLOTS ; j++) { js->queue[j].fence_context =dma_fence_context_alloc (1 ); - ret =drm_sched_init (&js->queue[j].sched, - &panfrost_sched_ops, - nentries,0 , -msecs_to_jiffies (JOB_TIMEOUT_MS ), - pfdev->reset.wq, -NULL ,"pan_js" , pfdev->dev); + ret =drm_sched_init (&js->queue[j].sched, &args);if (ret) {dev_err (pfdev->dev,"Failed to create scheduler: %d." , ret); goto err_sched;
drivers/gpu/drm/scheduler/sched_main.c +11 -22
@@ -994,33 +994,22 @@ static int drm_sched_main(void *param)* drm_sched_init - Init a gpu scheduler instance * * @sched: scheduler instance -* @ops: backend operations for this scheduler -* @hw_submission: number of hw submissions that can be in flight -* @hang_limit: number of times to allow a job to hang before dropping it -* @timeout: timeout value in jiffies for the scheduler -* @timeout_wq: workqueue to use for timeout work. If NULL, the system_wq is -* used -* @score: optional score atomic shared with other schedulers -* @name: name used for debugging -* @dev: target &struct device +* @args: scheduler initialization arguments * * Return 0 on success, otherwise error code. */ int drm_sched_init (struct drm_gpu_scheduler *sched, -const struct drm_sched_backend_ops *ops, -unsigned hw_submission,unsigned hang_limit, -long timeout,struct workqueue_struct *timeout_wq, -atomic_t *score,const char *name,struct device *dev) +const struct drm_sched_init_args *args) {int i, ret; - sched->ops = ops; - sched->hw_submission_limit = hw_submission; - sched->name = name; - sched->timeout = timeout; - sched->timeout_wq = timeout_wq ? : system_wq; - sched->hang_limit = hang_limit; - sched->score = score ? score : &sched->_score; - sched->dev = dev; + sched->ops = args->ops; + sched->hw_submission_limit = args->credit_limit; + sched->name = args->name; + sched->timeout = args->timeout; + sched->timeout_wq = args->timeout_wq ? : system_wq; + sched->hang_limit = args->hang_limit; + sched->score = args->score ? args->score : &sched->_score; + sched->dev = args->dev;for (i =DRM_SCHED_PRIORITY_MIN ; i <DRM_SCHED_PRIORITY_COUNT ; i++)drm_sched_rq_init (sched, &sched->sched_rq[i]);
@@ -1038,7 +1027,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,if (IS_ERR (sched->thread)) { ret =PTR_ERR (sched->thread); sched->thread =NULL ; -DRM_DEV_ERROR (sched->dev,"Failed to create scheduler for %s.\n" , name); +DRM_DEV_ERROR (sched->dev,"Failed to create scheduler for %s.\n" , sched->name);return ret; }
drivers/gpu/drm/v3d/v3d_sched.c +21 -25
67 lines not on this page · raw message
include/drm/gpu_scheduler.h +25 -4
@@ -470,11 +470,32 @@ struct drm_gpu_scheduler {struct device *dev; }; +/** +* struct drm_sched_init_args - parameters for initializing a DRM GPU scheduler +* +* @ops: backend operations provided by the driver +* @credit_limit: the number of credits this scheduler can hold from all jobs +* @hang_limit: number of times to allow a job to hang before dropping it. +* This mechanism is DEPRECATED. Set it to 0. +* @timeout: timeout value in jiffies for submitted jobs. +* @timeout_wq: workqueue to use for timeout work. If NULL, the system_wq is used. +* @score: score atomic shared with other schedulers. May be NULL. +* @name: name (typically the driver's name). Used for debugging +* @dev: associated device. Used for debugging +*/ +struct drm_sched_init_args { +const struct drm_sched_backend_ops *ops; +struct workqueue_struct *timeout_wq; +u32 credit_limit; +unsigned int hang_limit; +long timeout; +atomic_t *score; +const char *name; +struct device *dev; +}; +int drm_sched_init (struct drm_gpu_scheduler *sched, -const struct drm_sched_backend_ops *ops, -uint32_t hw_submission,unsigned hang_limit, -long timeout,struct workqueue_struct *timeout_wq, -atomic_t *score,const char *name,struct device *dev); +const struct drm_sched_init_args *args);void drm_sched_fini (struct drm_gpu_scheduler *sched); int drm_sched_job_init(struct drm_sched_job *job,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1620/1887 drm/msm: Only fini scheduler after successful init
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit e2332abed2a4d3caa59052095dc16e4ce44791ea ]
msm_ringbuffer_new() destroys a partially initialized ring through msm_ringbuffer_destroy() when an allocation or scheduler setup step fails.
If drm_sched_init() fails before it finishes initializing the scheduler, the failure path still calls drm_sched_fini(). That teardown path assumes the scheduler work items, lists, and workqueue state were initialized.
Track successful scheduler initialization and call drm_sched_fini() only after drm_sched_init() returned 0.
This issue was found by a static analysis checker and confirmed by manual source review.
Patchwork: https://patchwork.freedesktop.org/patch/738905/
Message-ID: <[email protected]>
--- drivers/gpu/drm/msm/msm_ringbuffer.c | 7 ++++--- drivers/gpu/drm/msm/msm_ringbuffer.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-)
drivers/gpu/drm/msm/msm_ringbuffer.c +4 -3
@@ -99,9 +99,9 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id, ring->memptrs_iova = memptrs_iova; ret =drm_sched_init (&ring->sched, &args); -if (ret) { +if (ret) goto fail; - } + ring->sched_initialized = true;INIT_LIST_HEAD (&ring->submits);spin_lock_init (&ring->submit_lock);
@@ -123,7 +123,8 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring)if (IS_ERR_OR_NULL (ring))return ; -drm_sched_fini (&ring->sched); +if (ring->sched_initialized) +drm_sched_fini (&ring->sched);msm_fence_context_free (ring->fctx);
drivers/gpu/drm/msm/msm_ringbuffer.h +1 -0
@@ -50,6 +50,7 @@ struct msm_ringbuffer {* The job scheduler for this ring. */ struct drm_gpu_scheduler sched; +bool sched_initialized;/* * List of in-flight submits on this ring. Protected by submit_lock.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1621/1887 wifi: iwlwifi: guard against division by zero in iwl_dbg_tlv_alloc_fragments
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit 9318bc0c41b24705690cf80d1596cf6b711e7027 ]
Make sure we don't end-up with a num_frags = 0 situation. For that, check that the required size is not 0 and put a checker on num_frags as well.
--- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +7 -1
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* -* Copyright (C) 2018-2025 Intel Corporation +* Copyright (C) 2018-2026 Intel Corporation */ #include <linux/firmware.h> #include "iwl-drv.h"
@@ -597,6 +597,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt, cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH))return 0 ; +if (!fw_mon_cfg->req_size) +return -EIO ; + num_frags =le32_to_cpu (fw_mon_cfg->max_frags_num);if (fwrt->trans->trans_cfg->device_family <IWL_DEVICE_FAMILY_AX210 ) {if (alloc_id !=IWL_FW_INI_ALLOCATION_ID_DBGC1 )
@@ -604,6 +607,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt, num_frags =1 ; } +if (!num_frags) +return -EIO ; + remain_pages =DIV_ROUND_UP (le32_to_cpu (fw_mon_cfg->req_size),PAGE_SIZE ); num_frags =min_t (u32, num_frags,BUF_ALLOC_MAX_NUM_FRAGS );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1622/1887 firmware: arm_scmi: Fix SCMI device destroy lifetimes
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit 6abe8fe36b29ff51d1a42c2f338972883f4751a5 ]
scmi_child_dev_find() drops the reference returned by device_find_child() before returning the scmi_device pointer. A concurrent unregister can then release the device while the destroy path is still using the returned pointer.
Make the lookup helper return the device_find_child() reference and keep it until scmi_device_destroy() has finished unregistering the child.
Also split device_unregister() in __scmi_device_destroy() so the SCMI bus ID is not made reusable until after device_del() has removed the old scmi_dev.N name from sysfs. This avoids a new SCMI device reusing the same ID while the old device is still registered.
The final device release callback is also a possible cleanup path when SCMI children are deleted by driver core recursion rather than __scmi_device_destroy(). Release the SCMI bus ID from a common helper used by destroy, register-failure and final-release paths, and clear scmi_dev->id after freeing it so the final release cannot free the same ID again.
--- drivers/firmware/arm_scmi/bus.c | 36 ++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-)
drivers/firmware/arm_scmi/bus.c +24 -12
@@ -220,8 +220,9 @@ static int scmi_match_by_id_table(struct device *dev, void *data) (id_table->name && !strcmp (sdev->name, id_table->name)); } -static struct scmi_device *scmi_child_dev_find (struct device *parent, -int prot_id,const char *name) +/* Returns a device_find_child() reference which must be dropped by caller. */ +static struct scmi_device * +scmi_child_dev_find_get (struct device *parent,int prot_id,const char *name) {struct scmi_device_id id_table;struct device *dev;
@@ -233,9 +234,6 @@ static struct scmi_device *scmi_child_dev_find(struct device *parent,if (!dev)return NULL ; -/* Drop the refcnt bumped implicitly by device_find_child */ -put_device (dev); -return to_scmi_dev (dev); }
@@ -299,10 +297,19 @@ void scmi_driver_unregister(struct scmi_driver *driver) }EXPORT_SYMBOL_GPL (scmi_driver_unregister); +static void scmi_device_release_resources (struct scmi_device *scmi_dev) +{ +if (scmi_dev->id) { +ida_free (&scmi_bus_id, scmi_dev->id); + scmi_dev->id =0 ; + } +} +static void scmi_device_release (struct device *dev) {struct scmi_device *scmi_dev =to_scmi_dev (dev); +scmi_device_release_resources (scmi_dev);kfree_const (scmi_dev->name);kfree (scmi_dev); }
@@ -317,8 +324,9 @@ static void __scmi_device_destroy(struct scmi_device *scmi_dev)if (scmi_dev->protocol_id ==SCMI_PROTOCOL_SYSTEM )atomic_set (&scmi_syspower_registered,0 ); -ida_free (&scmi_bus_id, scmi_dev->id); -device_unregister (&scmi_dev->dev); +device_del (&scmi_dev->dev); +scmi_device_release_resources (scmi_dev); +put_device (&scmi_dev->dev); } static struct scmi_device *
@@ -335,9 +343,11 @@ __scmi_device_create(struct device_node *np, struct device *parent,* each DT defined protocol at probe time, and the concurrent * registration of SCMI drivers. */ - scmi_dev =scmi_child_dev_find (parent, protocol, name); -if (scmi_dev) + scmi_dev =scmi_child_dev_find_get (parent, protocol, name); +if (scmi_dev) { +put_device (&scmi_dev->dev);return scmi_dev; + }/* * Ignore any possible subsequent failures while creating the device
@@ -388,8 +398,8 @@ __scmi_device_create(struct device_node *np, struct device *parent,return scmi_dev; put_dev: +scmi_device_release_resources (scmi_dev);put_device (&scmi_dev->dev); -ida_free (&scmi_bus_id, id);return NULL ; }
@@ -461,9 +471,11 @@ void scmi_device_destroy(struct device *parent, int protocol, const char *name) {struct scmi_device *scmi_dev; - scmi_dev =scmi_child_dev_find (parent, protocol, name); -if (scmi_dev) + scmi_dev =scmi_child_dev_find_get (parent, protocol, name); +if (scmi_dev) {__scmi_device_destroy (scmi_dev); +put_device (&scmi_dev->dev); + } }EXPORT_SYMBOL_GPL (scmi_device_destroy);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1623/1887 firmware: arm_scmi: Publish channel state before callbacks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit 0314900dcdde044af0208fed212035dbfaa55843 ]
Transport setup can enable callbacks before the setup routine returns. mailbox_chan_setup() registers the mailbox client with mbox_request_channel(), and the mailbox controller startup path can enable interrupt delivery before SCMI mailbox channel state has been published. Similarly, smc_chan_setup() requests the optional A2P completion IRQ before the SMC transport has made its cinfo pointer visible.
If a pending or spurious callback fires in those windows, the transport RX callback can dereference a NULL transport cinfo pointer. Publishing only the transport-private pointer is not sufficient either: an early callback can enter the SCMI core before scmi_chan_setup() has assigned cinfo->handle.
The core derives scmi_info from cinfo->handle in the RX path, so a NULL handle can still fault even when the transport-private cinfo is valid.
Assign cinfo->handle before invoking the transport setup callback. Publish the mailbox and SMC transport-private channel state before requesting the mailbox channels or IRQ, and clear the early-published pointers again on setup failure. Also unwind mailbox setup devres resources on failure so an optional RX setup error that is ignored by the core does not leave stale transport state behind.
--- drivers/firmware/arm_scmi/driver.c | 2 +- drivers/firmware/arm_scmi/mailbox.c | 16 ++++++++++++---- drivers/firmware/arm_scmi/smc.c | 12 +++++++----- 3 files changed, 20 insertions(+), 10 deletions(-)
drivers/firmware/arm_scmi/driver.c +1 -1
@@ -2143,6 +2143,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,of_node_get (of_node); cinfo->dev = &tdev->dev; + cinfo->handle = &info->handle; ret = info->desc->ops->chan_setup (cinfo, info->dev, tx);if (ret) {of_node_put (of_node);
@@ -2175,7 +2176,6 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,return ret; } - cinfo->handle = &info->handle;return 0 ; }
drivers/firmware/arm_scmi/mailbox.c +12 -4
@@ -146,19 +146,27 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, cl->tx_block = false; cl->knows_txdone = tx; + cinfo->transport_info = smbox; + smbox->cinfo = cinfo; + smbox->chan =mbox_request_channel (cl, tx ?0 :1 );if (IS_ERR (smbox->chan)) { ret =PTR_ERR (smbox->chan); + smbox->chan =NULL ;if (ret != -EPROBE_DEFER )dev_err (cdev,"failed to request SCMI %s mailbox\n" , tx ?"Tx" :"Rx" ); -return ret; + goto err_clear_cinfo; } - cinfo->transport_info = smbox; - smbox->cinfo = cinfo; -return 0 ; + +err_clear_cinfo: + cinfo->transport_info =NULL ; + smbox->cinfo =NULL ; +devm_iounmap (dev, smbox->shmem); +devm_kfree (dev, smbox); +return ret; }static int mailbox_chan_free (int id,void *p,void *data)
drivers/firmware/arm_scmi/smc.c +7 -5
@@ -141,6 +141,11 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,if (ret <0 )return ret; + scmi_info->func_id = func_id; + scmi_info->cinfo = cinfo; +smc_channel_lock_init (scmi_info); + cinfo->transport_info = scmi_info; +/* * If there is an interrupt named "a2p", then the service and * completion of a message is signaled by an interrupt rather than by
@@ -152,17 +157,14 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, IRQF_NO_SUSPEND, dev_name(dev), scmi_info);if (ret) {dev_err (dev,"failed to setup SCMI smc irq\n" ); + cinfo->transport_info =NULL ; + scmi_info->cinfo =NULL ;return ret; } }else { cinfo->no_completion_irq = true; } - scmi_info->func_id = func_id; - scmi_info->cinfo = cinfo; -smc_channel_lock_init (scmi_info); - cinfo->transport_info = scmi_info; -return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1624/1887 fs/resctrl: Prevent use-after-free in rdtgroup_kn_put()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Reinette Chatre <[email protected]>
[ Upstream commit f5bcf539484d2d604c2f2330e09487ea090b21c7 ]
A struct rdtgroup is reference counted via rdtgroup::waitcount. Callers that need the structure to remain valid across a sleep (while waiting on acquiring rdtgroup_mutex) take a reference with rdtgroup_kn_get() and release it with rdtgroup_kn_put().
The release path is intended to serve as the fallback freer: if the count drops to zero and the group has already been marked RDT_DELETED, rdtgroup_kn_put() frees the structure.
The bulk teardown paths free_all_child_rdtgrp() and rmdir_all_sub() resulting from a resctrl directory remove or resctrl fs unmount act as the primary
freer: they hold rdtgroup_mutex and free each rdtgroup whose waitcount is zero, otherwise they set RDT_DELETED and leave the freeing to the last waiter.
These two freers race. rdtgroup_kn_put() commits waitcount == 0 with atomic_dec_and_test() outside rdtgroup_mutex, then reads rdtgroup::flags. Between those two operations a concurrent caller of free_all_child_rdtgrp() or rmdir_all_sub() (which holds the mutex) can observe waitcount == 0 via atomic_read(), call rdtgroup_remove(), and kfree() the structure.
The subsequent read of rdtgroup::flags in rdtgroup_kn_put() is then a use-after-free, and the structure may even be freed twice if the freed memory happens to satisfy the RDT_DELETED flag check.
Replace the bare atomic_dec_and_test() with atomic_dec_and_mutex_lock() so that the decrement-to-zero takes rdtgroup_mutex before the count becomes globally visible. The inspection of rdtgroup::flags then runs under the same mutex held by the bulk freers, making the two paths mutually exclusive.
The common case where the count does not reach zero remains lock-free. Defer kernfs_unbreak_active_protection() until after the mutex is dropped since kernfs active protections functionally wrap rdtgroup_mutex. Remove resource group, which in turn drops its kernfs reference, after kernfs protection is restored.
[ bp: Split the commit messsages into smaller, easier-parseable paragraphs. ]
--- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/resctrl/rdtgroup.c +8 -5
@@ -2068,20 +2068,23 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn) {struct rdtgroup *rdtgrp =kernfs_to_rdtgroup (kn); +bool needs_free; +if (!rdtgrp)return ; + needs_free =atomic_dec_and_test (&rdtgrp->waitcount) && + (rdtgrp->flags &RDT_DELETED ); +mutex_unlock (&rdtgroup_mutex); -if (atomic_dec_and_test (&rdtgrp->waitcount) && - (rdtgrp->flags &RDT_DELETED )) { +kernfs_unbreak_active_protection (kn); + +if (needs_free) {if (rdtgrp->mode ==RDT_MODE_PSEUDO_LOCKSETUP || rdtgrp->mode ==RDT_MODE_PSEUDO_LOCKED )rdtgroup_pseudo_lock_remove (rdtgrp); -kernfs_unbreak_active_protection (kn);rdtgroup_remove (rdtgrp); - }else { -kernfs_unbreak_active_protection (kn); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1625/1887 RDMA/rvt: Return NULL after port allocation failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit 2982eaf3b9d2d953318c74cd6f1b7576ea6d7b1f ]
rvt_alloc_device() deallocates the IB device when its port array cannot be allocated but then returns the pointer to the released allocation. Callers treat any non-NULL value as valid and dereference it, resulting in a use-after-free.
Return NULL immediately after deallocation so callers can propagate the allocation failure.
--- drivers/infiniband/sw/rdmavt/vt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/infiniband/sw/rdmavt/vt.c +3 -1
@@ -54,8 +54,10 @@ struct rvt_dev_info *rvt_alloc_device(size_t size, int nports)return rdi; rdi->ports =kcalloc (nports,sizeof (*rdi->ports),GFP_KERNEL ); -if (!rdi->ports) +if (!rdi->ports) {ib_dealloc_device (&rdi->ibdev); +return NULL ; + }return rdi; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1626/1887 esp: do not unref managed frag pages in esp_ssg_unref()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maher Azzouzi <[email protected]>
[ Upstream commit 21697720ff43b8dfa25b8e8d9ca7f56f4597fc80 ]
esp_ssg_unref() releases the page references held on the source scatterlist after the AEAD operation completes. It calls skb_page_unref() on every frag page for an out-of-place transform (req->src != req->dst), and in the error path of esp_output_tail() (already_unref == true) on the request's own scatterlist.
This is wrong when the skb carries managed frags (SKBFL_MANAGED_FRAG_REFS). Managed frags are owned by a zerocopy ubuf and the skb does not hold a per-frag page reference; io_uring SEND_ZC with a registered buffer attaches the bvec pages this way via io_sg_from_iter(). The rest of the stack honours this invariant:skb_release_data() skips the per-frag unref when SKBFL_MANAGED_FRAG_REFS is set, and skb_zcopy_managed() is the guard used at the other unref sites.
esp_ssg_unref() is missing that guard, so for a managed-frag skb it drops a page reference the skb never acquired. This can underflow the page reference count and free a page that is still in use.
Guard the function with skb_zcopy_managed() so both unref paths are skipped for managed-frag skbs, matching skb_release_data().
--- net/ipv4/esp4.c | 7 +++++++ net/ipv6/esp6.c | 7 +++++++ 2 files changed, 14 insertions(+)
net/ipv4/esp4.c +7 -0
@@ -103,6 +103,13 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)struct aead_request *req;struct scatterlist *sg; +/* Managed frags are owned by the zerocopy ubuf; the skb holds no +* per-frag page reference, so we must not drop one here. Mirrors +* the SKBFL_MANAGED_FRAG_REFS handling in skb_release_data(). +*/ +if (skb_zcopy_managed (skb)) +return ; +if (x->props.flags &XFRM_STATE_ESN ) extralen +=sizeof (struct esp_output_extra );
net/ipv6/esp6.c +7 -0
@@ -120,6 +120,13 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)struct aead_request *req;struct scatterlist *sg; +/* Managed frags are owned by the zerocopy ubuf; the skb holds no +* per-frag page reference, so we must not drop one here. Mirrors +* the SKBFL_MANAGED_FRAG_REFS handling in skb_release_data(). +*/ +if (skb_zcopy_managed (skb)) +return ; +if (x->props.flags &XFRM_STATE_ESN ) extralen +=sizeof (struct esp_output_extra );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1627/1887 platform/x86: asus-wmi: fix resource leaks on probe failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Scardovi <[email protected]>
[ Upstream commit ef3daa2b84a2b8499ce9e2ce1c865dca36d39f95 ]
During driver initialization in asus_wmi_add(), various subsystems are registered sequentially. However, the error path labels are out of order relative to the registration sequence.
Specifically:
1. If asus_wmi_custom_fan_curve_init() fails, the driver jumps to fail_custom_fan_curve. Because this label is placed below fail_sysfs, it bypasses the cleanup calls for the input device and sysfs groups, which were successfully registered before, leaking those resources.
2. If asus_screenpad_init() fails, the driver jumps to fail_screenpad. Because fail_screenpad is placed below fail_backlight, it bypasses the cleanup calls for backlight and rfkill, leaking those resources.
Fix these resource leaks by reordering the error path labels in asus_wmi_add() to match the exact reverse order of the resource allocations.
--- drivers/platform/x86/asus-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/platform/x86/asus-wmi.c +1 -1
@@ -3859,13 +3859,13 @@ static int asus_wmi_add(struct platform_device *pdev) fail_rfkill:asus_wmi_led_exit (asus); fail_leds: +fail_custom_fan_curve: fail_hwmon:asus_wmi_input_exit (asus); fail_input:asus_wmi_sysfs_exit (asus->platform_device); fail_sysfs: fail_throttle_thermal_policy: -fail_custom_fan_curve: fail_platform_profile_setup:if (asus->platform_profile_support)platform_profile_remove ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1628/1887 usb: gadget: uac: validate rate list length before storing
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qing Ming <[email protected]>
[ Upstream commit 844d83d5964b87919b958ff48405188c6ddae9cc ]
UAC1 and UAC2 configfs rate-list attributes parse a comma-separated list of sampling rates and store each parsed value in fixed-size arrays. The arrays have UAC_MAX_RATES entries, but the store paths do not check that the input contains at most that many tokens before writing through opts->name##s[i++].
Writing more than ten rates therefore writes past the end of the p_srates[] or c_srates[] array in struct f_uac1_opts or struct f_uac2_opts.
With CONFIG_UBSAN_BOUNDS enabled, writing an 11-entry rate list to the UAC1 p_srate attribute reports:
UBSAN: array-index-out-of-bounds drivers/usb/gadget/function/f_uac1.c:1669:1 index 10 is out of range for type 'int [10]' __ubsan_handle_out_of_bounds.cold f_uac1_opts_p_srate_store configfs_write_iter vfs_write ksys_write do_syscall_64
The same reproducer against the UAC2 p_srate attribute reports:
UBSAN: array-index-out-of-bounds drivers/usb/gadget/function/f_uac2.c:2087:1 index 10 is out of range for type 'int [10]' __ubsan_handle_out_of_bounds.cold f_uac2_opts_p_srate_store configfs_write_iter vfs_write ksys_write do_syscall_64
Reject additional tokens once UAC_MAX_RATES entries have been parsed. Also keep the original kstrdup() pointer for kfree(), because strsep() advances the parsing cursor. Freeing the advanced cursor leaks the original buffer on successful parses and can free an interior pointer on some error paths.
--- drivers/usb/gadget/function/f_uac1.c | 13 +++++++++---- drivers/usb/gadget/function/f_uac2.c | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-)
drivers/usb/gadget/function/f_uac1.c +9 -4
@@ -1521,7 +1521,8 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \ const char *page, size_t len) \ { \struct f_uac1_opts *opts =to_f_uac1_opts (item); \ -char *split_page =NULL ; \ +char *buf =NULL ; \ +char *split_page; \int ret = -EINVAL ; \char *token; \u32 num; \
@@ -1535,18 +1536,22 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \ \ i =0 ; \ memset(opts->name##s, 0x00, sizeof(opts->name##s)); \ - split_page = kstrdup(page, GFP_KERNEL); \ + buf = kstrdup(page, GFP_KERNEL); \ + split_page = buf; \ while ((token = strsep(&split_page, ",")) != NULL) { \ ret = kstrtou32(token, 0, &num); \ if (ret) \ goto end; \ - \ + if (i >= UAC_MAX_RATES) { \ + ret = -EINVAL; \ + goto end; \ + } \ opts->name##s[i++] = num; \ ret = len; \ }; \ \ end: \ - kfree(split_page); \ + kfree(buf); \ mutex_unlock(&opts->lock); \ return ret; \ } \
drivers/usb/gadget/function/f_uac2.c +9 -4
@@ -2003,7 +2003,8 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ const char *page, size_t len) \ { \struct f_uac2_opts *opts =to_f_uac2_opts (item); \ -char *split_page =NULL ; \ +char *buf =NULL ; \ +char *split_page; \int ret = -EINVAL ; \char *token; \u32 num; \
@@ -2017,18 +2018,22 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ \ i =0 ; \ memset(opts->name##s, 0x00, sizeof(opts->name##s)); \ - split_page = kstrdup(page, GFP_KERNEL); \ + buf = kstrdup(page, GFP_KERNEL); \ + split_page = buf; \ while ((token = strsep(&split_page, ",")) != NULL) { \ ret = kstrtou32(token, 0, &num); \ if (ret) \ goto end; \ - \ + if (i >= UAC_MAX_RATES) { \ + ret = -EINVAL; \ + goto end; \ + } \ opts->name##s[i++] = num; \ ret = len; \ }; \ \ end: \ - kfree(split_page); \ + kfree(buf); \ mutex_unlock(&opts->lock); \ return ret; \ } \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1629/1887 bpf: Reject rdonly/rdwr_buf_size kfunc arguments that exceed u32 max
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Dudar <[email protected]>
[ Upstream commit 2aaf67f0516fde29620d0edfc29c01b9ea7ad430 ]
check_kfunc_args() detects a kfunc argument named rdonly_buf_size or rdwr_buf_size and stores reg->var_off.value into meta->r0_size, a u64, and does not bound it. check_kfunc_call() later copies that value into the returned register's mem_size field:
meta->r0_size = reg->var_off.value; ... regs[BPF_REG_0].mem_size = meta.r0_size;
regs[BPF_REG_0].mem_size is u32. A constant whose upper 32 bits are set gets truncated instead of causing a load-time rejection, so the verifier records a PTR_TO_MEM register with an approximately 4 GiB mem_size for whatever allocation the kfunc returned. A later access check against that register uses the truncated, wrong bound.
Reject rdonly_buf_size/rdwr_buf_size values that exceed U32_MAX at the point meta->r0_size is set.
--- kernel/bpf/btf.c | 5 +++++ 1 file changed, 5 insertions(+)
kernel/bpf/btf.c +5 -0
@@ -6345,6 +6345,11 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, } kfunc_meta->r0_size = reg->var_off.value; +if (kfunc_meta->r0_size >U32_MAX ) { +bpf_log (log,"R%d rdonly/rdwr_buf_size exceeds u32 max\n" , + regno); +return -EINVAL ; + } ret =mark_chain_precision (env, regno);if (ret)return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1630/1887 platform/x86: lg-laptop: Fix LED resource handling
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Armin Wolf <[email protected]>
[ Upstream commit 3e91964aa74ab261aa15d9d96318eded2fd9d22a ]
The event notification callback might access kbd_backlight even when it was not successfully registered with the LED subsystem. The same happens inside acpi_remove(), where the LED devices are unregistered unconditionally.
Fix this by tracking the availability of the kbd_backlight LED device and use devm_led_classdev_register() to let devres take care of unregistering the LED devices during removal. For this the parent device of the LED devices is changed to the native platform device.
--- drivers/platform/x86/lg-laptop.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
drivers/platform/x86/lg-laptop.c +17 -5
@@ -71,6 +71,7 @@ static u32 inited;#define INIT_SPARSE_KEYMAP 0x80static int battery_limit_use_wmbb; +static bool kbd_backlight_available;static struct led_classdev kbd_backlight;static enum led_brightness get_kbd_backlight_level (struct device *dev);
@@ -188,6 +189,7 @@ static void wmi_notify(u32 value, void *context)union acpi_object *obj;acpi_status status;long data = (long )context; +unsigned int brightness;pr_debug ("event guid %li\n" , data); status =wmi_get_event_data (value, &response);
@@ -205,8 +207,11 @@ static void wmi_notify(u32 value, void *context)struct key_entry *key;if (eventcode ==0x10000000 ) { -led_classdev_notify_brightness_hw_changed ( - &kbd_backlight,get_kbd_backlight_level (kbd_backlight.dev->parent)); +if (kbd_backlight_available) { + brightness =get_kbd_backlight_level (kbd_backlight.dev->parent); +led_classdev_notify_brightness_hw_changed (&kbd_backlight, + brightness); + } }else { key =sparse_keymap_entry_from_scancode ( wmi_input_dev, eventcode);
@@ -725,7 +730,12 @@ static int acpi_add(struct acpi_device *device) goto out_platform_device;/* LEDs are optional */ -led_classdev_register (&pf_device->dev, &kbd_backlight); + ret =led_classdev_register (&pf_device->dev, &kbd_backlight); +if (ret <0 ) + kbd_backlight_available = false; +else + kbd_backlight_available = true; +led_classdev_register (&pf_device->dev, &tpad_led);wmi_input_setup ();
@@ -744,11 +754,13 @@ static int acpi_remove(struct acpi_device *device) {sysfs_remove_group (&pf_device->dev.kobj, &dev_attribute_group); +battery_hook_unregister (&battery_hook); +wmi_input_destroy (); + + kbd_backlight_available = false;led_classdev_unregister (&tpad_led);led_classdev_unregister (&kbd_backlight); -battery_hook_unregister (&battery_hook); -wmi_input_destroy ();platform_device_unregister (pf_device); pf_device =NULL ;platform_driver_unregister (&pf_driver);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1631/1887 platform/x86: dell-wmi-base: Fix handling of ultra performance key
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Armin Wolf <[email protected]>
[ Upstream commit adfd6846bea13667ff28f8aaf00c32fbd69825ab ]
The commit message of commit 5fbd827eb9c2 ("platform/x86: dell-wmi: Recognise or support new switches") states that the ultra performance key contains additional data
after the type and code fields. The event data passed todell_wmi_process_key() is already parsed, so "buffer" already
starts after those two fields.
Use the correct index for accessing the first data field to avoid a potential buffer overread.
--- drivers/platform/x86/dell/dell-wmi-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/platform/x86/dell/dell-wmi-base.c +1 -1
@@ -442,7 +442,7 @@ static int dell_wmi_process_key(struct wmi_device *wdev, int type, int code, u16 SW_TABLET_MODE, !buffer[0]);return 1 ; }else if (type ==0x0012 && code ==0x000d && remaining >0 ) { - value = (buffer[2 ] ==2 ); + value = (buffer[0 ] ==2 ); used =1 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1632/1887 time/namespace: Validate nanosecond field in proc_timens_set_offset()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Malaya Kumar Rout <[email protected]>
[ Upstream commit 06aba58e58492d2b8eae059274caed29025ea96e ]
The function validates tv_sec to be within [-KTIME_SEC_MAX, KTIME_SEC_MAX] but never validates that tv_nsec is within the valid range of [0, NSEC_PER_SEC-1] before using it in timespec64_add().
timespec64_add() expects both timespec64 structures to have normalized values with tv_nsec in the range [0, 999999999]. If off->val.tv_nsec contains invalid values (negative or >= NSEC_PER_SEC), it could lead to incorrect calculations or unexpected behavior.
Add validation to ensure tv_nsec is within the valid range before performing the addition.
--- kernel/time/namespace.c | 5 +++++ 1 file changed, 5 insertions(+)
kernel/time/namespace.c +5 -0
@@ -398,6 +398,11 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p, off->val.tv_sec < -KTIME_SEC_MAX) goto out; +if (off->val.tv_nsec <0 || off->val.tv_nsec >=NSEC_PER_SEC ) { + err = -EINVAL ; + goto out; + } + tp =timespec64_add (tp, off->val);/* * KTIME_SEC_MAX is divided by 2 to be sure that KTIME_MAX is
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1633/1887 cgroup/cpuset: introduce cpuset-v1.c
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Ridong <[email protected]>
[ Upstream commit 71e934a80863c2a9f4d27ee3360dc17e0a609aa6 ]
This patch introduces the cgroup/cpuset-v1.c source file which will be used for all legacy (cgroup v1) cpuset cgroup code. It also introduces cgroup/cpuset-internal.h to keep declarations shared between cgroup/cpuset.c and cpuset/cpuset-v1.c.
As of now, let's compile it if CONFIG_CPUSET is set. Later on it can be switched to use a separate config option, so that the legacy code won't be compiled if not required.
Stable-dep-of: 95220e1f18f6 ("cgroup/cpuset: Make nr_deadline_tasks an atomic_t")
--- MAINTAINERS | 2 ++ kernel/cgroup/Makefile | 2 +- kernel/cgroup/cpuset-internal.h | 6 ++++++ kernel/cgroup/cpuset-v1.c | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 kernel/cgroup/cpuset-internal.h create mode 100644 kernel/cgroup/cpuset-v1.c
MAINTAINERS +2 -0
@@ -5293,6 +5293,8 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git F: Documentation/admin-guide/cgroup-v1/cpusets.rst F: include/linux/cpuset.h +F: kernel/cgroup/cpuset-internal.h +F: kernel/cgroup/cpuset-v1.c F: kernel/cgroup/cpuset.c CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG)
kernel/cgroup/Makefile +1 -1
@@ -4,6 +4,6 @@ obj-y := cgroup.o rstat.o namespace.o cgroup-v1.o freezer.o obj-$(CONFIG_CGROUP_FREEZER) += legacy_freezer.o obj-$(CONFIG_CGROUP_PIDS) += pids.o obj-$(CONFIG_CGROUP_RDMA) += rdma.o -obj-$(CONFIG_CPUSETS) += cpuset.o +obj-$(CONFIG_CPUSETS) += cpuset.o cpuset-v1.o obj-$(CONFIG_CGROUP_MISC) += misc.o obj-$(CONFIG_CGROUP_DEBUG) += debug.o
kernel/cgroup/cpuset-internal.h new file +6 -0
@@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef __CPUSET_INTERNAL_H +#define __CPUSET_INTERNAL_H + +#endif /* __CPUSET_INTERNAL_H */
kernel/cgroup/cpuset-v1.c new file +3 -0
@@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "cpuset-internal.h"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1634/1887 cgroup/cpuset: move common code to cpuset-internal.h
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Ridong <[email protected]>
[ Upstream commit 619a33efa0b0cd566f928d60d128033673e478cf ]
Move some declarations that will be used for cpuset v1 and v2, including 'cpuset struct', 'cpuset_flagbits_t', cpuset_filetype_t,etc. No logical change.
Adapted to this tree: the moved cpuset struct, file type enum and error code enum follow the definitions already present here, and the include removals in cpuset.c are skipped.
Stable-dep-of: 95220e1f18f6 ("cgroup/cpuset: Make nr_deadline_tasks an atomic_t")
--- kernel/cgroup/cpuset-internal.h | 216 ++++++++++++++++++++++++++++++++ kernel/cgroup/cpuset.c | 212 +------------------------------ 2 files changed, 217 insertions(+), 211 deletions(-)
kernel/cgroup/cpuset-internal.h +216 -0
@@ -3,4 +3,220 @@#ifndef __CPUSET_INTERNAL_H#define __CPUSET_INTERNAL_H +#include <linux/cpumask.h> +#include <linux/spinlock.h> +#include <linux/cpuset.h> +#include <linux/cgroup.h> + +/* See "Frequency meter" comments, below. */ + +struct fmeter { +int cnt;/* unprocessed events count */ +int val;/* most recent output value */ +time64_t time;/* clock (secs) when val computed */ +spinlock_t lock;/* guards read or write of above */ +}; + +/* +* Invalid partition error code +*/ +enum prs_errcode { +PERR_NONE =0 , +PERR_INVCPUS , +PERR_INVPARENT , +PERR_NOTPART , +PERR_NOTEXCL , +PERR_NOCPUS , +PERR_HOTPLUG , +PERR_CPUSEMPTY , +}; + +/* bits in struct cpuset flags field */ +typedef enum { +CS_ONLINE , +CS_CPU_EXCLUSIVE , +CS_MEM_EXCLUSIVE , +CS_MEM_HARDWALL , +CS_MEMORY_MIGRATE , +CS_SCHED_LOAD_BALANCE , +CS_SPREAD_PAGE , +CS_SPREAD_SLAB , +}cpuset_flagbits_t ; + +/* The various types of files and directories in a cpuset file system */ + +typedef enum { +FILE_MEMORY_MIGRATE , +FILE_CPULIST , +FILE_MEMLIST , +FILE_EFFECTIVE_CPULIST , +FILE_EFFECTIVE_MEMLIST , +FILE_SUBPARTS_CPULIST , +FILE_CPU_EXCLUSIVE , +FILE_MEM_EXCLUSIVE , +FILE_MEM_HARDWALL , +FILE_SCHED_LOAD_BALANCE , +FILE_PARTITION_ROOT , +FILE_SCHED_RELAX_DOMAIN_LEVEL , +FILE_MEMORY_PRESSURE_ENABLED , +FILE_MEMORY_PRESSURE , +FILE_SPREAD_PAGE , +FILE_SPREAD_SLAB , +}cpuset_filetype_t ; + +struct cpuset { +struct cgroup_subsys_state css; + +unsigned long flags;/* "unsigned long" so bitops work */ + +/* +* On default hierarchy: +* +* The user-configured masks can only be changed by writing to +* cpuset.cpus and cpuset.mems, and won't be limited by the +* parent masks. +* +* The effective masks is the real masks that apply to the tasks +* in the cpuset. They may be changed if the configured masks are +* changed or hotplug happens. +* +* effective_mask == configured_mask & parent's effective_mask, +* and if it ends up empty, it will inherit the parent's mask. +* +* +* On legacy hierarchy: +* +* The user-configured masks are always the same with effective masks. +*/ + +/* user-configured CPUs and Memory Nodes allow to tasks */ +cpumask_var_t cpus_allowed; +nodemask_t mems_allowed; + +/* effective CPUs and Memory Nodes allow to tasks */ +cpumask_var_t effective_cpus; +nodemask_t effective_mems; + +/* +* CPUs allocated to child sub-partitions (default hierarchy only) +* - CPUs granted by the parent = effective_cpus U subparts_cpus +* - effective_cpus and subparts_cpus are mutually exclusive. +* +* effective_cpus contains only onlined CPUs, but subparts_cpus +* may have offlined ones. +*/ +cpumask_var_t subparts_cpus; + +/* +* This is old Memory Nodes tasks took on. +* +* - top_cpuset.old_mems_allowed is initialized to mems_allowed. +* - A new cpuset's old_mems_allowed is initialized when some +* task is moved into it. +* - old_mems_allowed is used in cpuset_migrate_mm() when we change +* cpuset.mems_allowed and have tasks' nodemask updated, and +* then old_mems_allowed is updated to mems_allowed. +*/ +nodemask_t old_mems_allowed; + +struct fmeter fmeter;/* memory_pressure filter */ + +/* +* Tasks are being attached to this cpuset. Used to prevent +* zeroing cpus/mems_allowed between ->can_attach() and ->attach(). +*/ +int attach_in_progress; + +/* partition number for rebuild_sched_domains() */ +int pn; + +/* for custom sched domain */ +int relax_domain_level; + +/* number of CPUs in subparts_cpus */ +int nr_subparts_cpus; + +/* partition root state */ +int partition_root_state; + +/* +* Default hierarchy only: +* use_parent_ecpus - set if using parent's effective_cpus +* child_ecpus_count - # of children with use_parent_ecpus set +*/ +int use_parent_ecpus; +int child_ecpus_count; + +/* +* number of SCHED_DEADLINE tasks attached to this cpuset, so that we +* know when to rebuild associated root domain bandwidth information. +*/ +int nr_deadline_tasks; +int nr_migrate_dl_tasks; +u64 sum_migrate_dl_bw; + +/* Invalid partition error code, not lock protected */ +enum prs_errcode prs_err; + +/* Handle for cpuset.cpus.partition */ +struct cgroup_file partition_file; +}; + +static inline struct cpuset *css_cs (struct cgroup_subsys_state *css) +{ + return css ? container_of(css, struct cpuset, css) : NULL; +} + +/* Retrieve the cpuset for a task */ +static inline struct cpuset *task_cs (struct task_struct *task) +{ +return css_cs (task_css (task, cpuset_cgrp_id)); +} + +static inline struct cpuset *parent_cs (struct cpuset *cs) +{ +return css_cs (cs->css.parent); +} + +/* convenient tests for these bits */ +static inline bool is_cpuset_online (struct cpuset *cs) +{ +return test_bit (CS_ONLINE , &cs->flags) && !css_is_dying (&cs->css); +} + +static inline int is_cpu_exclusive (const struct cpuset *cs) +{ +return test_bit (CS_CPU_EXCLUSIVE , &cs->flags); +} + +static inline int is_mem_exclusive (const struct cpuset *cs) +{ +return test_bit (CS_MEM_EXCLUSIVE , &cs->flags); +} + +static inline int is_mem_hardwall (const struct cpuset *cs) +{ +return test_bit (CS_MEM_HARDWALL , &cs->flags); +} + +static inline int is_sched_load_balance (const struct cpuset *cs) +{ +return test_bit (CS_SCHED_LOAD_BALANCE , &cs->flags); +} + +static inline int is_memory_migrate (const struct cpuset *cs) +{ +return test_bit (CS_MEMORY_MIGRATE , &cs->flags); +} + +static inline int is_spread_page (const struct cpuset *cs) +{ +return test_bit (CS_SPREAD_PAGE , &cs->flags); +} + +static inline int is_spread_slab (const struct cpuset *cs) +{ +return test_bit (CS_SPREAD_SLAB , &cs->flags); +} +#endif /* __CPUSET_INTERNAL_H */
kernel/cgroup/cpuset.c +1 -211
248 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1635/1887 cgroup/cpuset: Make nr_deadline_tasks an atomic_t
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Waiman Long <[email protected]>
[ Upstream commit 95220e1f18f6321008f021abc7d6f581f64bcb82 ]
The nr_deadline_tasks variable in the cpuset structure was introduced by commit 6c24849f5515 ("sched/cpuset: Keep track of SCHED_DEADLINE task in cpusets"). It is reported by sashiko [1] that nr_deadline_tasks can currently be modified by inc_dl_tasks_cs() under rq->lock and by cpuset_attach() under cpuset_mutex. So if both updates happen simultaneously, the nr_deadline_tasks variable can be corrupted leading to incorrect operations down the road.
Fix that by changing its type to atomic_t so that nr_deadline_tasks are always atomically updated. This fix patch is a low hanging fruit. It can handle some of the races between a concurrent sched_setscheduler() and cpuset_can_attach()/cpuset_attach() calls, but not all of them like the other issue raised by sashiko [2]. This will be handled hopefully in a future follow up patch.
[1] https://sashiko.dev/#/patchset/20260626181923.133658-1-longman%40redhat.com
[2] https://sashiko.dev/#/patchset/20260630033344.352702-1-longman%40redhat.com
--- kernel/cgroup/cpuset-internal.h | 2 +- kernel/cgroup/cpuset.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-)
kernel/cgroup/cpuset-internal.h +1 -1
@@ -151,7 +151,7 @@ struct cpuset {* number of SCHED_DEADLINE tasks attached to this cpuset, so that we * know when to rebuild associated root domain bandwidth information. */ -int nr_deadline_tasks; +atomic_t nr_deadline_tasks;int nr_migrate_dl_tasks;u64 sum_migrate_dl_bw;
kernel/cgroup/cpuset.c +5 -5
@@ -122,14 +122,14 @@ void inc_dl_tasks_cs(struct task_struct *p) {struct cpuset *cs =task_cs (p); - cs->nr_deadline_tasks++; +atomic_inc (&cs->nr_deadline_tasks); }void dec_dl_tasks_cs (struct task_struct *p) {struct cpuset *cs =task_cs (p); - cs->nr_deadline_tasks--; +atomic_dec (&cs->nr_deadline_tasks); }static inline int is_partition_valid (const struct cpuset *cs)
@@ -925,7 +925,7 @@ static void dl_update_tasks_root_domain(struct cpuset *cs)struct css_task_iter it;struct task_struct *task; -if (cs->nr_deadline_tasks ==0 ) +if (atomic_read (&cs->nr_deadline_tasks) ==0 )return ;css_task_iter_start (&cs->css,0 , &it);
@@ -2515,8 +2515,8 @@ static void cpuset_attach(struct cgroup_taskset *tset) cs->old_mems_allowed = cpuset_attach_nodemask_to;if (cs->nr_migrate_dl_tasks) { - cs->nr_deadline_tasks += cs->nr_migrate_dl_tasks; - oldcs->nr_deadline_tasks -= cs->nr_migrate_dl_tasks; +atomic_add (cs->nr_migrate_dl_tasks, &cs->nr_deadline_tasks); +atomic_sub (cs->nr_migrate_dl_tasks, &oldcs->nr_deadline_tasks);reset_migrate_dl_data (cs); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1636/1887 crypto: keembay - Fix AEAD unregister count in error path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit e264401ce4776a288524e5b87593d4d864147115 ]
register_aes_algs() registers the AEAD algorithms before registering the skcipher algorithms. If skcipher registration fails, the function unwinds the earlier AEAD registration with crypto_engine_unregister_aeads(), but it passes ARRAY_SIZE(algs), which is the skcipher table size.
Use ARRAY_SIZE(algs_aead) for the AEAD unwind path so the unregister helper iterates over the same table that was registered. Also clarify the nearby
comment: the crypto registration helpers clean up algorithms registered within the same call, while this function must still unwind earlier successful registration steps.
--- drivers/crypto/keembay/keembay-ocs-aes-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/keembay/keembay-ocs-aes-core.c +2 -2
@@ -1554,7 +1554,7 @@ static int register_aes_algs(struct ocs_aes_dev *aes_dev)/* * If any algorithm fails to register, all preceding algorithms that -* were successfully registered will be automatically unregistered. +* were registered in the same call are automatically unregistered. */ ret =crypto_register_aeads (algs_aead,ARRAY_SIZE (algs_aead));if (ret)
@@ -1562,7 +1562,7 @@ static int register_aes_algs(struct ocs_aes_dev *aes_dev) ret =crypto_register_skciphers (algs,ARRAY_SIZE (algs));if (ret) -crypto_unregister_aeads (algs_aead,ARRAY_SIZE (algs)); +crypto_unregister_aeads (algs_aead,ARRAY_SIZE (algs_aead));return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1637/1887 hwrng: core - fix rng list on registration error
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manos Pitsidianakis <[email protected]>
[ Upstream commit 3a5834db2b1ce25649f330e78efe1ccde78967fd ]
hwrng_register(rng) does the following:
1. Checks if rng has name and read methods set
2. Checks if the name already exists
3. Adds rng to global rng_list
4. May try to set rng to current_rng
If step 4 fails, it returns an error. However, it does not remove the rng from rng_list, causing a dangling reference which can result in use-after-free if the caller frees rng, since registration failed.
Add a list_del_init() cleanup step.
--- drivers/char/hw_random/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/char/hw_random/core.c +3 -1
@@ -622,7 +622,7 @@ int hwrng_register(struct hwrng *rng)*/ err =set_current_rng (rng);if (err) - goto out_unlock; + goto out_list_del;/* to use current_rng in add_early_randomness() we need * to take a ref */
@@ -643,6 +643,8 @@ int hwrng_register(struct hwrng *rng)if (is_new_current)put_rng (rng);return 0 ; +out_list_del: +list_del_init (&rng->list); out_unlock:mutex_unlock (&rng_mutex); out:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1638/1887 dmaengine: xilinx_dma: Fix CPU stall in xilinx_dma_poll_timeout
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Bereza <[email protected]>
[ Upstream commit aa99c4d1d63bbc26a5fc4c667d89b2595743c19d ]
Currently when calling xilinx_dma_poll_timeout with delay_us=0 and a condition that is never fulfilled, the CPU busy-waits for prolonged time and the timeout triggers only with a massive delay causing a CPU stall.
This happens due to a huge underestimation of wall clock time in poll_timeout_us_atomic. Commit 7349a69cf312 ("iopoll: Do not use timekeeping in read_poll_timeout_atomic()") changed the behavior to no longer use ktime_get at the expense of underestimation of wall clock time which appears to be very large for delay_us=0. Instead of timing out after approximately XILINX_DMA_LOOP_COUNT microseconds, the timeout takes XILINX_DMA_LOOP_COUNT * 1000 * (time that the overhead of the for loop in poll_timeout_us_atomic takes) which is in the range of several minutes for XILINX_DMA_LOOP_COUNT=1000000. Fix this by using a non-zero value for delay_us. Use delay_us=10 to keep the delay in the hot path of starting DMA transfers minimal but still avoid CPU stalls in case of unexpected hardware failures.
One-off measurement with delay_us=0 causes the cpu to busy wait around 7 minutes in the timeout case. After applying this patch with delay_us=10 the measured timeout was 1053428 microseconds which is roughly equivalent to the expected 1000000 microseconds specified in XILINX_DMA_LOOP_COUNT.
Add a constant XILINX_DMA_POLL_DELAY_US for delay_us value.
--- drivers/dma/xilinx/xilinx_dma.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/dma/xilinx/xilinx_dma.c +10 -4
@@ -164,6 +164,8 @@/* Delay loop counter to prevent hardware failure */ #define XILINX_DMA_LOOP_COUNT 1000000 +/* Delay between polls (avoid a delay of 0 to prevent CPU stalls) */ +#define XILINX_DMA_POLL_DELAY_US 10/* AXI DMA Specific Registers/Offsets */ #define XILINX_DMA_REG_SRCDSTADDR 0x18
@@ -1287,7 +1289,8 @@ static int xilinx_dma_stop_transfer(struct xilinx_dma_chan *chan)/* Wait for the hardware to halt */ return xilinx_dma_poll_timeout (chan,XILINX_DMA_REG_DMASR , val, - val &XILINX_DMA_DMASR_HALTED ,0 , + val &XILINX_DMA_DMASR_HALTED , +XILINX_DMA_POLL_DELAY_US ,XILINX_DMA_LOOP_COUNT ); }
@@ -1302,7 +1305,8 @@ static int xilinx_cdma_stop_transfer(struct xilinx_dma_chan *chan)u32 val;return xilinx_dma_poll_timeout (chan,XILINX_DMA_REG_DMASR , val, - val &XILINX_DMA_DMASR_IDLE ,0 , + val &XILINX_DMA_DMASR_IDLE , +XILINX_DMA_POLL_DELAY_US ,XILINX_DMA_LOOP_COUNT ); }
@@ -1319,7 +1323,8 @@ static void xilinx_dma_start(struct xilinx_dma_chan *chan)/* Wait for the hardware to start */ err =xilinx_dma_poll_timeout (chan,XILINX_DMA_REG_DMASR , val, - !(val &XILINX_DMA_DMASR_HALTED ),0 , + !(val &XILINX_DMA_DMASR_HALTED ), +XILINX_DMA_POLL_DELAY_US ,XILINX_DMA_LOOP_COUNT );if (err) {
@@ -1742,7 +1747,8 @@ static int xilinx_dma_reset(struct xilinx_dma_chan *chan)/* Wait for the hardware to finish reset */ err =xilinx_dma_poll_timeout (chan,XILINX_DMA_REG_DMACR , tmp, - !(tmp &XILINX_DMA_DMACR_RESET ),0 , + !(tmp &XILINX_DMA_DMACR_RESET ), +XILINX_DMA_POLL_DELAY_US ,XILINX_DMA_LOOP_COUNT );if (err) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1639/1887 mm/mm_init: handle alloc_percpu failure in free_area_init_core_hotplug
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gregory Price <[email protected]>
[ Upstream commit 2ebce860bdd7ae5e13002811bc9bbbf33fcfc221 ]
We miss a failed allocation check for pgdat->per_cpu_nodestats, which results in a NULL deref when we offset into the per-cpu area.
Propagate -ENOMEM up the stack and leave per_cpu_nodestats pointing at boot_nodestats so a later online can retry the allocation.
hotadd_init_pgdat() returns NULL on failure, which __try_online_node() already maps to -ENOMEM.
On failure nothing needs to be unwound:
- the node is never marked online
- per_cpu_nodestats is left pointing at boot_nodestats
- __add_memory_resource() cleans up pending memblock resources
- later online attempts retry the per_cpu_nodestats allocation
--- include/linux/memory_hotplug.h | 2 +- mm/memory_hotplug.c | 3 ++- mm/page_alloc.c | 14 +++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-)
include/linux/memory_hotplug.h +1 -1
@@ -330,7 +330,7 @@ extern void set_zone_contiguous(struct zone *zone);extern void clear_zone_contiguous (struct zone *zone);#ifdef CONFIG_MEMORY_HOTPLUG -extern void __ref free_area_init_core_hotplug (struct pglist_data *pgdat); +int __ref free_area_init_core_hotplug (struct pglist_data *pgdat);extern int __add_memory (int nid,u64 start,u64 size,mhp_t mhp_flags);extern int add_memory (int nid,u64 start,u64 size,mhp_t mhp_flags); extern int add_memory_resource(int nid, struct resource *resource,
mm/memory_hotplug.c +2 -1
@@ -1185,7 +1185,8 @@ static pg_data_t __ref *hotadd_init_pgdat(int nid) pgdat =NODE_DATA (nid);/* init node's zones as empty zones, we don't have any present pages.*/ -free_area_init_core_hotplug (pgdat); +if (free_area_init_core_hotplug (pgdat)) +return NULL ;/* * The node we allocated has no zone fallback lists. For avoiding
mm/page_alloc.c +11 -3
@@ -7730,7 +7730,7 @@ static void __meminit zone_init_internals(struct zone *zone, enum zone_type idx,* NOTE: this function is only called during memory hotplug */ #ifdef CONFIG_MEMORY_HOTPLUG -void __ref free_area_init_core_hotplug (struct pglist_data *pgdat) +int __ref free_area_init_core_hotplug (struct pglist_data *pgdat) {int nid = pgdat->node_id;enum zone_type z;
@@ -7738,8 +7738,14 @@ void __ref free_area_init_core_hotplug(struct pglist_data *pgdat)pgdat_init_internals (pgdat); -if (pgdat->per_cpu_nodestats == &boot_nodestats) - pgdat->per_cpu_nodestats = alloc_percpu(struct per_cpu_nodestat); +if (pgdat->per_cpu_nodestats == &boot_nodestats) { +struct per_cpu_nodestat __percpu *p; + + p = alloc_percpu(struct per_cpu_nodestat); +if (!p) +return -ENOMEM ; + pgdat->per_cpu_nodestats = p; + }/* * Reset the nr_zones, order and highest_zoneidx before reuse.
@@ -7767,6 +7773,8 @@ void __ref free_area_init_core_hotplug(struct pglist_data *pgdat)for (z =0 ; z <MAX_NR_ZONES ; z++)zone_init_internals (&pgdat->node_zones[z], z, nid,0 ); + + return 0; }#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1640/1887 bpf: Copy per-CPU map value padding in copy_map_value_long()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Hwang <[email protected]>
[ Upstream commit 7cf9cd98cf6f0df3befc167ca6b54c07014d71de ]
In kernel, per-CPU map elements are stored with round_up(map->value_size, 8) bytes. On UAPI lookup paths, it copies the rounded size for each CPU into a temporary buffer.
However, copy_map_value_long() passes 'map->value_size' to bpf_obj_memcpy(). When the map has special fields, bpf_obj_memcpy() copies around those fields with memcpy(), and does not copy the tail padding between 'map->value_size' and round_up(map->value_size, 8).
The temporary UAPI lookup buffers are allocated without __GFP_ZERO. As a result, when the per-CPU map's value size is not equal to round_up(map->value_size, 8), UAPI LOOKUP_ELEM and its variants can return stale heap contents from that padding to user space. The same issue applies to bpf_iter for per-CPU maps.
Pass round_up(map->value_size, 8) to bpf_obj_memcpy() from copy_map_value_long(), so per-CPU maps both with and without special fields copy the entire per-CPU slot. Remove the now redundant round_up() from bpf_obj_memcpy()'s long_memcpy path.
--- include/linux/bpf.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
include/linux/bpf.h +4 -1
@@ -354,7 +354,10 @@ static inline void __copy_map_value(struct bpf_map *map, void *dst, void *src, bmemcpy (dst + curr_off, src + curr_off, next_off - curr_off); curr_off = next_off + map->off_arr->field_sz[i]; } -memcpy (dst + curr_off, src + curr_off, map->value_size - curr_off); +if (long_memcpy) +memcpy (dst + curr_off, src + curr_off,round_up (map->value_size,8 ) - curr_off); +else +memcpy (dst + curr_off, src + curr_off, map->value_size - curr_off); }static inline void copy_map_value (struct bpf_map *map,void *dst,void *src)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1641/1887 drm/amd/display: Fix dangling pointer in CRTC reset function
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Evgenii Burenchev <[email protected]>
[ Upstream commit 0aeed866cb938943908c3ba46422128e49d2d080 ]
amdgpu_dm_crtc_reset_state() frees the old state before allocating a new one. If kzalloc() fails, the function returns without updating the state pointer, leaving a dangling pointer to already freed memory.
Fix this by allocating the new state first. On allocation failure, the old state remains untouched and the function safely returns.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +4 -4
@@ -278,13 +278,13 @@ static void dm_crtc_reset_state(struct drm_crtc *crtc) {struct dm_crtc_state *state; -if (crtc->state) -dm_crtc_destroy_state (crtc, crtc->state); - state =kzalloc (sizeof (*state),GFP_KERNEL ); -if (WARN_ON (!state)) +if (!state)return ; +if (crtc->state) +dm_crtc_destroy_state (crtc, crtc->state); +__drm_atomic_helper_crtc_reset (crtc, &state->base); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1642/1887 drm/amd/display: Fix dangling pointer in plane reset function
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Evgenii Burenchev <[email protected]>
[ Upstream commit 98cad4bd1443975d972f4c7f705980da03722a22 ]
amdgpu_dm_plane_drm_plane_reset() frees the old state before allocating a new one. If kzalloc() fails, the function returns without updating the state pointer, leaving a dangling pointer to already freed memory.
Fix this by allocating the new state first. On allocation failure, the old state remains untouched and the function safely returns.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- .../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +7 -8
@@ -1336,19 +1336,18 @@ static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {static void dm_drm_plane_reset (struct drm_plane *plane) { -struct dm_plane_state *amdgpu_state =NULL ; +struct dm_plane_state *amdgpu_state; + + amdgpu_state =kzalloc (sizeof (*amdgpu_state),GFP_KERNEL ); +if (!amdgpu_state) +return ;if (plane->state) plane->funcs->atomic_destroy_state (plane, plane->state); - amdgpu_state =kzalloc (sizeof (*amdgpu_state),GFP_KERNEL ); -WARN_ON (amdgpu_state ==NULL ); - -if (amdgpu_state) -__drm_atomic_helper_plane_reset (plane, &amdgpu_state->base); +__drm_atomic_helper_plane_reset (plane, &amdgpu_state->base);#ifdef CONFIG_DRM_AMD_DC_HDR -if (amdgpu_state) - amdgpu_state->sdr_boost =DEFAULT_SDR_BOOST ; + amdgpu_state->sdr_boost =DEFAULT_SDR_BOOST ;#endif }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1643/1887 cxl/mbox: Clamp mailbox output allocation to the payload size
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Cheng <[email protected]>
[ Upstream commit 8a13db9f899d149c3aab24abcb668121cfda5a4f ]
CXL_MEM_SEND_COMMAND bounds the user's in.size to the mailbox payload size but leaves out.size unbounded, then cxl_mbox_cmd_ctor() calls kvzalloc(out.size). A large out.size drives a huge allocation, above INT_MAX it WARNs and taints, and with panic_on_warn=1 it panics.
The transport __cxl_pci_mbox_send_cmd() already clamps the response copy to min(out.size, payload_size, device len), so the output buffer is never written beyond payload_size. Clamp the allocation to payload_size too, matching the RAW path.
--- drivers/cxl/core/mbox.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/cxl/core/mbox.c +1 -5
@@ -281,11 +281,7 @@ static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox, } } -/* Prepare to handle a full payload for variable sized output */ -if (out_size ==CXL_VARIABLE_PAYLOAD ) - mbox->size_out = cxlds->payload_size; -else - mbox->size_out = out_size; + mbox->size_out =min_t (size_t, out_size, cxlds->payload_size);if (mbox->size_out) { mbox->payload_out =kvzalloc (mbox->size_out,GFP_KERNEL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1644/1887 drm/v3d: Clear queue->active_job when v3d_fence_create() fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maíra Canal <[email protected]>
[ Upstream commit 25a1669907512e927fab9ad4d4fb74ff57f63cd9 ]
The run_job() callbacks for BIN, RENDER, TFU and CSD assign the incoming job to queue->active_job before calling v3d_fence_create(). If v3d_fence_create() fails, the callback returns NULL without clearing active_job, leaving a dangling pointer.
Create a failure path in all run_job() callbacks that clears the active job before returning NULL. The BIN path takes queue->queue_lock around the clear as it races against v3d_overflow_mem_work(); RENDER, TFU and CSD paths have no concurrent reader, so the clear is lock-free.
--- drivers/gpu/drm/v3d/v3d_sched.c | 60 +++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 26 deletions(-)
drivers/gpu/drm/v3d/v3d_sched.c +34 -26
@@ -77,15 +77,11 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)struct v3d_bin_job *job =to_bin_job (sched_job);struct v3d_dev *v3d = job->base.v3d;struct drm_device *dev = &v3d->drm; -struct dma_fence *fence; +struct dma_fence *fence =NULL ;unsigned long irqflags; -if (unlikely (job->base.base.s_fence->finished.error)) { -spin_lock_irqsave (&v3d->job_lock, irqflags); - v3d->queue[V3D_BIN ].active_job =NULL ; -spin_unlock_irqrestore (&v3d->job_lock, irqflags); -return NULL ; - } +if (unlikely (job->base.base.s_fence->finished.error)) + goto out_clean_job;/* Lock required around bin_job update vs * v3d_overflow_mem_work().
@@ -102,7 +98,7 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) fence =v3d_fence_create (v3d,V3D_BIN );if (IS_ERR (fence)) -return NULL ; + goto out_clean_job;if (job->base.irq_fence)dma_fence_put (job->base.irq_fence);
@@ -129,6 +125,12 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)V3D_CORE_WRITE (0 ,V3D_CLE_CT0QEA , job->end);return fence; + +out_clean_job: +spin_lock_irqsave (&v3d->job_lock, irqflags); + v3d->queue[V3D_BIN ].active_job =NULL ; +spin_unlock_irqrestore (&v3d->job_lock, irqflags); +return fence; }static struct dma_fence *v3d_render_job_run (struct drm_sched_job *sched_job)
@@ -136,12 +138,10 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)struct v3d_render_job *job =to_render_job (sched_job);struct v3d_dev *v3d = job->base.v3d;struct drm_device *dev = &v3d->drm; -struct dma_fence *fence; +struct dma_fence *fence =NULL ; -if (unlikely (job->base.base.s_fence->finished.error)) { - v3d->queue[V3D_RENDER ].active_job =NULL ; -return NULL ; - } +if (unlikely (job->base.base.s_fence->finished.error)) + goto out_clean_job; v3d->queue[V3D_RENDER ].active_job = &job->base;
@@ -155,7 +155,7 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job) fence =v3d_fence_create (v3d,V3D_RENDER );if (IS_ERR (fence)) -return NULL ; + goto out_clean_job;if (job->base.irq_fence)dma_fence_put (job->base.irq_fence);
@@ -175,6 +175,10 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)V3D_CORE_WRITE (0 ,V3D_CLE_CT1QEA , job->end);return fence; + +out_clean_job: + v3d->queue[V3D_RENDER ].active_job =NULL ; +return fence; } static struct dma_fence *
@@ -183,18 +187,16 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)struct v3d_tfu_job *job =to_tfu_job (sched_job);struct v3d_dev *v3d = job->base.v3d;struct drm_device *dev = &v3d->drm; -struct dma_fence *fence; +struct dma_fence *fence =NULL ; -if (unlikely (job->base.base.s_fence->finished.error)) { - v3d->queue[V3D_TFU ].active_job =NULL ; -return NULL ; - } +if (unlikely (job->base.base.s_fence->finished.error)) + goto out_clean_job; v3d->queue[V3D_TFU ].active_job = &job->base; fence =v3d_fence_create (v3d,V3D_TFU );if (IS_ERR (fence)) -return NULL ; + goto out_clean_job;if (job->base.irq_fence)dma_fence_put (job->base.irq_fence);
@@ -218,6 +220,10 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)V3D_WRITE (V3D_TFU_ICFG , job->args.icfg |V3D_TFU_ICFG_IOC );return fence; + +out_clean_job: + v3d->queue[V3D_TFU ].active_job =NULL ; +return fence; } static struct dma_fence *
@@ -226,13 +232,11 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)struct v3d_csd_job *job =to_csd_job (sched_job);struct v3d_dev *v3d = job->base.v3d;struct drm_device *dev = &v3d->drm; -struct dma_fence *fence; +struct dma_fence *fence =NULL ;int i; -if (unlikely (job->base.base.s_fence->finished.error)) { - v3d->queue[V3D_CSD ].active_job =NULL ; -return NULL ; - } +if (unlikely (job->base.base.s_fence->finished.error)) + goto out_clean_job;/* The HW interprets a workgroup size of 0 as 65536; however, the * user-space driver exposes a maximum of 65535. Therefore, a 0 in
@@ -250,7 +254,7 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) fence =v3d_fence_create (v3d,V3D_CSD );if (IS_ERR (fence)) -return NULL ; + goto out_clean_job;if (job->base.irq_fence)dma_fence_put (job->base.irq_fence);
@@ -266,6 +270,10 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)V3D_CORE_WRITE (0 ,V3D_CSD_QUEUED_CFG0 , job->args.cfg[0 ]);return fence; + +out_clean_job: + v3d->queue[V3D_CSD ].active_job =NULL ; +return fence; } static struct dma_fence *
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1645/1887 nvdimm: virtio_pmem: refcount requests for token lifetime
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Chen <[email protected]>
[ Upstream commit e57140944b5a47a7fd5a142faab29a02af040bc8 ]
KASAN reports slab-use-after-free in __wake_up_common():
BUG: KASAN: slab-use-after-free in __wake_up_common+0x114/0x160 Read of size 8 at addr ffff88810fdcb710 by task swapper/0/0 CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.19.0-next-20260220-00006-g1eae5f204ec3 #4 PREEMPT(full) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014 Call Trace: <IRQ> dump_stack_lvl+0x6d/0xb0 print_report+0x170/0x4e2 ? __pfx__raw_spin_lock_irqsave+0x10/0x10 ? __virt_addr_valid+0x1dc/0x380 kasan_report+0xbc/0xf0 ? __wake_up_common+0x114/0x160 ? __wake_up_common+0x114/0x160 __wake_up_common+0x114/0x160 ? __pfx__raw_spin_lock_irqsave+0x10/0x10 __wake_up+0x36/0x60 virtio_pmem_host_ack+0x11d/0x3b0 ? sched_balance_domains+0x29f/0xb00 ? __pfx_virtio_pmem_host_ack+0x10/0x10 ? _raw_spin_lock_irqsave+0x98/0x100 ? __pfx__raw_spin_lock_irqsave+0x10/0x10 vring_interrupt+0x1c9/0x5e0 ? __pfx_vp_interrupt+0x10/0x10 vp_vring_interrupt+0x87/0x100 ? __pfx_vp_interrupt+0x10/0x10 __handle_irq_event_percpu+0x17f/0x550 ? __pfx__raw_spin_lock+0x10/0x10 handle_irq_event+0xab/0x1c0 handle_fasteoi_irq+0x276/0xae0 __common_interrupt+0x65/0x130 common_interrupt+0x78/0xa0 </IRQ>
virtio_pmem_host_ack() wakes a request that has already been freed by the submitter.
This happens when the request token is still reachable via the virtqueue, but virtio_pmem_flush() returns and frees it.
Fix the token lifetime by refcounting struct virtio_pmem_request. virtio_pmem_flush() holds a submitter reference, and the virtqueue holds an extra reference once the request is queued. The completion path drops the virtqueue reference, and the submitter drops its reference before returning.
Message-ID: <[email protected]>
--- drivers/nvdimm/nd_virtio.c | 32 ++++++++++++++++++++++++++++---- drivers/nvdimm/virtio_pmem.h | 2 ++ 2 files changed, 30 insertions(+), 4 deletions(-)
drivers/nvdimm/nd_virtio.c +28 -4
@@ -9,6 +9,14 @@#include "virtio_pmem.h" #include "nd.h" +static void virtio_pmem_req_release (struct kref *kref) +{ +struct virtio_pmem_request *req; + + req = container_of(kref, struct virtio_pmem_request, kref); +kfree (req); +} +/* The interrupt handler */ void virtio_pmem_host_ack (struct virtqueue *vq) {
@@ -29,6 +37,7 @@ void virtio_pmem_host_ack(struct virtqueue *vq)wake_up (&req_buf->wq_buf);list_del (&req_buf->list); } +kref_put (&req_data->kref, virtio_pmem_req_release); }spin_unlock_irqrestore (&vpmem->pmem_lock, flags); }
@@ -59,6 +68,7 @@ static int virtio_pmem_flush(struct nd_region *nd_region)if (!req_data)return -ENOMEM ; +kref_init (&req_data->kref); req_data->done = false;init_waitqueue_head (&req_data->host_acked);init_waitqueue_head (&req_data->wq_buf);
@@ -76,10 +86,23 @@ static int virtio_pmem_flush(struct nd_region *nd_region)* to req_list and wait for host_ack to wake us up when free * slots are available. */ -while ((err =virtqueue_add_sgs (vpmem->req_vq, sgs,1 ,1 , req_data, -GFP_ATOMIC )) == -ENOSPC ) { +for (;;) { + err =virtqueue_add_sgs (vpmem->req_vq, sgs,1 ,1 , req_data, +GFP_ATOMIC ); +if (!err) { +/* +* Take the virtqueue reference while @pmem_lock is +* held so completion cannot run concurrently. +*/ +kref_get (&req_data->kref); +break ; + } + +if (err != -ENOSPC ) +break ; -dev_info (&vdev->dev,"failed to send command to virtio pmem device, no free slots in the virtqueue\n" ); +dev_info_ratelimited (&vdev->dev, +"failed to send command to virtio pmem device, no free slots in the virtqueue\n" ); req_data->wq_buf_avail = false;list_add_tail (&req_data->list, &vpmem->req_list);spin_unlock_irqrestore (&vpmem->pmem_lock, flags);
@@ -88,6 +111,7 @@ static int virtio_pmem_flush(struct nd_region *nd_region)wait_event (req_data->wq_buf, req_data->wq_buf_avail);spin_lock_irqsave (&vpmem->pmem_lock, flags); } + err1 =virtqueue_kick (vpmem->req_vq);spin_unlock_irqrestore (&vpmem->pmem_lock, flags);/*
@@ -103,7 +127,7 @@ static int virtio_pmem_flush(struct nd_region *nd_region) err =le32_to_cpu (req_data->resp.ret); } -kfree (req_data); +kref_put (&req_data->kref, virtio_pmem_req_release);return err; };
drivers/nvdimm/virtio_pmem.h +2 -0
@@ -12,11 +12,13 @@#include <linux/module.h> #include <uapi/linux/virtio_pmem.h> +#include <linux/kref.h> #include <linux/libnvdimm.h> #include <linux/mutex.h> #include <linux/spinlock.h> struct virtio_pmem_request { +struct kref kref;struct virtio_pmem_req req;struct virtio_pmem_resp resp;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1646/1887 i3c: master: Fix recursive locking during device registration
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit 456f832e5fc26fbfd3b8200fd4553eee520cc377 ]
i3c_master_register_new_i3c_devs() registers newly discovered devices while holding i3c_bus_normaluse_lock(), a down_read(). device_register() can immediately probe the device, and probe callbacks typically invoke I3C helpers that take i3c_bus_normaluse_lock() again, leading to a recursive acquisition of the same rwsem. rwsems do not support recursive read locking and can deadlock when a writer is waiting. See the "Recursive read locks" section of Documentation/locking/lockdep-design.rst.
For example, with Intel LPSS I3C, LOCKDEP generates a WARNING like:
# echo intel-lpss-i3c.0 > /sys/bus/platform/drivers/mipi-i3c-hci/unbind
# echo intel-lpss-i3c.0 > /sys/bus/platform/drivers/mipi-i3c-hci/bind
WARNING: possible recursive locking detected
kworker/5:1/94 is trying to acquire lock:
ffff88811c810d78 (&i3cbus->lock){++++}-{4:4}, at: i3c_device_match_id+0x45/0x370
but task is already holding lock:
ffff88811c810d78 (&i3cbus->lock){++++}-{4:4}, at: i3c_master_reg_work_fn+0x21/0x5f0Fix this by separating device creation from device registration. Populate desc->dev under the maintenance lock, collect the devices that still need registration into a local list, then release the lock before calling device_register(). Finally retake the lock and clean up any devices that failed to register.
Use the maintenance lock rather than the normal-use lock while adding device objects. A write-side maintenance lock prevents readers from observing a partially initialized desc->dev during initial device population, or desc->dev disappearing if registration fails.
The local list requires a list node, so add a list node member to struct i3c_device.
--- drivers/i3c/master.c | 38 ++++++++++++++++++++++++++------------ include/linux/i3c/master.h | 3 +++ 2 files changed, 29 insertions(+), 12 deletions(-)
drivers/i3c/master.c +26 -12
@@ -1615,12 +1615,15 @@ static int i3c_master_early_i3c_dev_add(struct i3c_master_controller *master,static void i3c_master_register_new_i3c_devs (struct i3c_master_controller *master) { +struct i3c_device *i3cdev, *tmp;struct i3c_dev_desc *desc; +LIST_HEAD (i3c_unreg_devs);int ret;if (!master->init_done)return ; +i3c_bus_maintenance_lock (&master->bus);i3c_bus_for_each_i3cdev (&master->bus, desc) {if (desc->dev || !desc->info.dyn_addr || desc == master->this)continue ;
@@ -1641,15 +1644,30 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)if (desc->boardinfo) desc->dev->dev.of_node = desc->boardinfo->of_node; - ret =device_register (&desc->dev->dev); -if (ret) { -dev_err (&master->dev, -"Failed to add I3C device (err = %d)\n" , ret); - desc->dev->desc =NULL ; -put_device (&desc->dev->dev); - desc->dev =NULL ; - } +list_add_tail (&desc->dev->node, &i3c_unreg_devs); + } + +i3c_bus_maintenance_unlock (&master->bus); + +list_for_each_entry_safe (i3cdev, tmp, &i3c_unreg_devs, node) { + ret =device_register (&i3cdev->dev); +if (ret) +dev_err (&master->dev,"Failed to add I3C device (err = %d)\n" , ret); +else +list_del_init (&i3cdev->node); } + +i3c_bus_maintenance_lock (&master->bus); + +list_for_each_entry_safe (i3cdev, tmp, &i3c_unreg_devs, node) { +list_del (&i3cdev->node); + desc = i3cdev->desc; + i3cdev->desc =NULL ; +put_device (&i3cdev->dev); + desc->dev =NULL ; + } + +i3c_bus_maintenance_unlock (&master->bus); }/**
@@ -1678,9 +1696,7 @@ int i3c_master_do_daa(struct i3c_master_controller *master)if (ret)return ret; -i3c_bus_normaluse_lock (&master->bus);i3c_master_register_new_i3c_devs (master); -i3c_bus_normaluse_unlock (&master->bus);return 0 ; }
@@ -2852,9 +2868,7 @@ int i3c_master_register(struct i3c_master_controller *master,* register I3C devices discovered during the initial DAA. */ master->init_done = true; -i3c_bus_normaluse_lock (&master->bus);i3c_master_register_new_i3c_devs (master); -i3c_bus_normaluse_unlock (&master->bus);return 0 ;
include/linux/i3c/master.h +3 -0
@@ -219,6 +219,8 @@ struct i3c_dev_desc {* every time the I3C device is rediscovered with a different dynamic * address assigned * @bus: I3C bus this device is attached to +* @node: unregistered device list node, only for use by +* i3c_master_register_new_i3c_devs(), it is not protected by a lock * * I3C device object exposed to I3C device drivers. The takes care of linking * this object to the relevant &struct_i3c_dev_desc one.
@@ -229,6 +231,7 @@ struct i3c_device {struct device dev;struct i3c_dev_desc *desc;struct i3c_bus *bus; +struct list_head node; };/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1647/1887 iommu/arm-smmu-v3: Manage teardown with devm
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shameer Kolothum <[email protected]>
[ Upstream commit 2bd22a0d40503a65d243b011de146603c8ce1cbc ]
arm_smmu_device_remove() manually frees the IOPF queue, destroys the vmid_map and disables the device, while the IRQs and queues are devm managed. devm unwinds only after remove() returns, so the cleanup runs in the wrong order. The IOPF queue is freed before the event-queue IRQ whose handler uses it.
Manage all of it with devm so the unwind order is correct. Free the IOPF queue and vmid_map via devm actions, and disable the device from one registered after arm_smmu_device_reset().
This is also a prerequisite for fixing a Tegra241 CMDQV CMD_SYNC use-after-free in the subsequent patch.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 45 ++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +31 -14
@@ -2968,6 +2968,13 @@ static int arm_smmu_cmdq_init(struct arm_smmu_device *smmu)return 0 ; } +static void arm_smmu_free_iopf_action (void *data) +{ +struct iopf_queue *queue = data; + +iopf_queue_free (queue); +} +static int arm_smmu_init_queues (struct arm_smmu_device *smmu) {int ret;
@@ -2995,6 +3002,11 @@ static int arm_smmu_init_queues(struct arm_smmu_device *smmu) smmu->evtq.iopf =iopf_queue_alloc (dev_name (smmu->dev));if (!smmu->evtq.iopf)return -ENOMEM ; + ret =devm_add_action_or_reset (smmu->dev, + arm_smmu_free_iopf_action, + smmu->evtq.iopf); +if (ret) +return ret; }/* priq */
@@ -3317,6 +3329,13 @@ static int arm_smmu_device_disable(struct arm_smmu_device *smmu)return ret; } +static void arm_smmu_disable_action (void *data) +{ +struct arm_smmu_device *smmu = data; + +arm_smmu_device_disable (smmu); +} +static int arm_smmu_device_reset (struct arm_smmu_device *smmu,bool bypass) {int ret;
@@ -3898,7 +3917,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)/* Initialise in-memory data structures */ ret =arm_smmu_init_structures (smmu);if (ret) - goto err_free_iopf; +return ret;/* Record our private device structure */ platform_set_drvdata (pdev, smmu);
@@ -3908,30 +3927,30 @@ static int arm_smmu_device_probe(struct platform_device *pdev)/* Reset the device */ ret =arm_smmu_device_reset (smmu, bypass); +if (ret) { +arm_smmu_device_disable (smmu); +return ret; + } + +/* Register last so it unwinds first, while the CMDQ is still up. */ + ret =devm_add_action_or_reset (smmu->dev, arm_smmu_disable_action, smmu);if (ret) - goto err_disable; +return ret;/* And we're up. Go go go! */ ret =iommu_device_sysfs_add (&smmu->iommu, dev,NULL ,"smmu3.%pa" , &ioaddr);if (ret) - goto err_disable; +return ret; ret =iommu_device_register (&smmu->iommu, &arm_smmu_ops, dev);if (ret) {dev_err (dev,"Failed to register iommu\n" ); - goto err_free_sysfs; +iommu_device_sysfs_remove (&smmu->iommu); +return ret; }return 0 ; - -err_free_sysfs: -iommu_device_sysfs_remove (&smmu->iommu); -err_disable: -arm_smmu_device_disable (smmu); -err_free_iopf: -iopf_queue_free (smmu->evtq.iopf); -return ret; }static int arm_smmu_device_remove (struct platform_device *pdev)
@@ -3940,8 +3959,6 @@ static int arm_smmu_device_remove(struct platform_device *pdev)iommu_device_unregister (&smmu->iommu);iommu_device_sysfs_remove (&smmu->iommu); -arm_smmu_device_disable (smmu); -iopf_queue_free (smmu->evtq.iopf);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1648/1887 svcrdma: Reject Write/Reply chunks with segcount 0
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <[email protected]>
[ Upstream commit 9808eb7656666acc7291bae9ab6b987bd16e47e0 ]
A peer can send a Write or Reply chunk whose segcount field is zero. xdr_check_write_chunk() only rejects segcount > rc_maxpages, so zero passes the range check, and xdr_inline_decode(stream, 0) returns the current (non-NULL) cursor without advancing. The function returns true and pcl_alloc_write() then links a struct svc_rdma_chunk with ch_segcount == 0 onto rc_write_pcl or rc_reply_pcl.
An earlier patch in this series made pcl_for_each_segment() safe for ch_segcount == 0, so this no longer drives the memory walk it used to. Rejecting the malformed frame at the decode boundary is still worthwhile as defense in depth: it keeps degenerate zero-segment chunks off the parsed chunk lists entirely, so any future consumer that walks ch_segments directly cannot observe one, and it makes the zero-floor easy to backport to trees where the macro change is more intrusive. RFC 8166 has no meaning for a Write/Reply chunk that describes no remote buffer, so no legitimate client is affected.
xdr_check_reply_chunk() funnels Reply chunks through xdr_check_write_chunk() and inherits the same rejection.
pcl_alloc_write() also links each chunk onto the parsed chunk list before filling its segment array. If a future change weakens the segcount-0 rejection, an incomplete chunk is visible to consumers during the fill loop. Reorder so that list_add_tail() follows the segment fill loop, ensuring only fully-populated chunks appear on the list.
--- net/sunrpc/xprtrdma/svc_rdma_pcl.c | 2 +- net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-)
net/sunrpc/xprtrdma/svc_rdma_pcl.c +1 -1
@@ -213,7 +213,6 @@ bool pcl_alloc_write(struct svc_rdma_recv_ctxt *rctxt, chunk =pcl_alloc_chunk (segcount,0 );if (!chunk)return false; -list_add_tail (&chunk->ch_list, &pcl->cl_chunks);for (j =0 ; j < segcount; j++) { segment = &chunk->ch_segments[j];
@@ -225,6 +224,7 @@ bool pcl_alloc_write(struct svc_rdma_recv_ctxt *rctxt, chunk->ch_length += segment->rs_length; chunk->ch_segcount++; } +list_add_tail (&chunk->ch_list, &pcl->cl_chunks); }return true; }
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +6 -3
@@ -491,10 +491,13 @@ static bool xdr_check_write_chunk(struct svc_rdma_recv_ctxt *rctxt)return false;/* Before trusting the segcount value enough to use it in -* a computation, perform a simple range check. This is an -* arbitrary but sensible limit (ie, not architectural). +* a computation, perform a simple range check. A zero +* segcount describes no remote buffer and is rejected so +* downstream consumers never see a degenerate ch_segcount==0 +* chunk. The upper bound is an arbitrary but sensible limit +* (ie, not architectural). */ -if (unlikely (segcount >RPCSVC_MAXPAGES )) +if (segcount ==0 ||unlikely (segcount >RPCSVC_MAXPAGES ))return false; p = xdr_inline_decode(&rctxt->rc_stream,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1649/1887 ACPI: bus: Introduce acpi_bus_get_primary_device()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <[email protected]>
[ Upstream commit 72530e1f72b0515a73fd88292254d04fecf03649 ]
The function used for obtaining the first "physical" device for which the given ACPI one is the ACPI companion, acpi_get_first_physical_node(), may return a stale device pointer (mostly in theory) because acpi_unbind_one() may run as a whole after dropping the ACPI device's physical_node_lock in acpi_get_first_physical_node() and before it returns. The last reference to the "physical" device may be dropped then before the pointer to it is returned to the caller.
If that happens and the acpi_get_first_physical_node() caller invokes get_device() on the pointer obtained from it, which is done by the majority of its callers, a use-after-free will occur.
To prepare for addressing this problem, introduce a new function for getting the first "physical" device associated with the given ACPI one (the "primary physical device") that will also reference count the device in question before returning a pointer to it.
Make that new function and acpi_get_first_physical_node() share the physical node list lookup code.
No intentional functional impact.
--- drivers/acpi/bus.c | 54 +++++++++++++++++++++++++++++------------ include/acpi/acpi_bus.h | 6 +++++ 2 files changed, 44 insertions(+), 16 deletions(-)
drivers/acpi/bus.c +38 -16
@@ -643,30 +643,52 @@ static int __init acpi_setup_sb_notify_handler(void)Device Matching -------------------------------------------------------------------------- */ + +static struct device *primary_physical_device (struct acpi_device *adev) +{ +struct acpi_device_physical_node *pn; + + pn =list_first_entry_or_null (&adev->physical_node_list, + struct acpi_device_physical_node, node); +if (pn) +return pn->dev; + +return NULL ; +} +/** -* acpi_get_first_physical_node - Get first physical node of an ACPI device +* acpi_bus_get_primary_device - Get first physical device for a given ACPI one +* @adev: ACPI device to get the first physical device for. +* +* Find the first physical device for which @adev is the ACPI companion and +* reference count it if present. +* +* Return: Pointer to the first physical counterpart of @adev or NULL if there +* are none. Callers are responsible for invoking put_device() on the returned +* device. +*/ +struct device *acpi_bus_get_primary_device (struct acpi_device *adev) +{ +if (!adev) +return NULL ; + +guard (mutex)(&adev->physical_node_lock); + +return get_device (primary_physical_device (adev)); +} +EXPORT_SYMBOL_GPL (acpi_bus_get_primary_device); + +/** +* acpi_get_first_physical_node - Find first physical node of an ACPI device * @adev: ACPI device in question * * Return: First physical node of ACPI device @adev */ struct device *acpi_get_first_physical_node (struct acpi_device *adev) { -struct mutex *physical_node_lock = &adev->physical_node_lock; -struct device *phys_dev; - -mutex_lock (physical_node_lock); -if (list_empty (&adev->physical_node_list)) { - phys_dev =NULL ; - }else { -const struct acpi_device_physical_node *node; +guard (mutex)(&adev->physical_node_lock); - node =list_first_entry (&adev->physical_node_list, - struct acpi_device_physical_node, node); - - phys_dev = node->dev; - } -mutex_unlock (physical_node_lock); -return phys_dev; +return primary_physical_device (adev); }EXPORT_SYMBOL_GPL (acpi_get_first_physical_node);
include/acpi/acpi_bus.h +6 -0
@@ -556,6 +556,7 @@ void acpi_bus_unregister_driver(struct acpi_driver *driver);int acpi_bus_scan (acpi_handle handle);void acpi_bus_trim (struct acpi_device *start);acpi_status acpi_bus_get_ejd (acpi_handle handle,acpi_handle * ejd); +struct device *acpi_bus_get_primary_device (struct acpi_device *adev);int acpi_match_device_ids (struct acpi_device *device,const struct acpi_device_id *ids); void acpi_set_modalias(struct acpi_device *adev, const char *default_id,
@@ -797,6 +798,11 @@ static inline void acpi_put_acpi_dev(struct acpi_device *adev) }#else /* CONFIG_ACPI */ +static inline struct device *acpi_bus_get_primary_device (struct acpi_device *adev) +{ +return NULL ; +} +static inline int register_acpi_bus_type (void *bus) {return 0 ; }static inline int unregister_acpi_bus_type (void *bus) {return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1650/1887 powerpc/xive: add error return value to xive_smp_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gou Hao <[email protected]>
[ Upstream commit ab5ae5dceb86614f6c9e7488f91b652000edfdc5 ]
xive_smp_probe() calls xive_init_ipis() which can fail, but its return value is currently ignored. Change xive_smp_probe() to return int so that errors can be propagated to callers.
This is a preparatory patch for the next one.
No functional change yet; the return value is always 0 at this point.
Stable-dep-of: 411a3c016e7a ("powerpc/xive: propagate IPI init errors to prevent use-after-free")
--- arch/powerpc/include/asm/xive.h | 4 ++-- arch/powerpc/sysdev/xive/common.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-)
arch/powerpc/include/asm/xive.h +2 -2
@@ -91,7 +91,7 @@ static inline bool xive_enabled(void) { return __xive_enabled; }bool xive_spapr_init (void );bool xive_native_init (void ); -void xive_smp_probe (void ); +int xive_smp_probe (void );int xive_smp_prepare_cpu (unsigned int cpu);void xive_smp_setup_cpu (void );void xive_smp_disable_cpu (void );
@@ -154,7 +154,7 @@ static inline bool xive_enabled(void) { return false; }static inline bool xive_spapr_init (void ) {return false; }static inline bool xive_native_init (void ) {return false; } -static inline void xive_smp_probe (void ) { } +static inline int xive_smp_probe (void ) {return -EINVAL ; }static inline int xive_smp_prepare_cpu (unsigned int cpu) {return -EINVAL ; }static inline void xive_smp_setup_cpu (void ) { }static inline void xive_smp_disable_cpu (void ) { }
arch/powerpc/sysdev/xive/common.c +3 -1
@@ -1270,7 +1270,7 @@ noinstr static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc) xive_ops->put_ipi (cpu, xc); } -void __init xive_smp_probe (void ) +int __init xive_smp_probe (void ) { smp_ops->cause_ipi = xive_cause_ipi;
@@ -1279,6 +1279,8 @@ void __init xive_smp_probe(void)/* Allocate and setup IPI for the boot CPU */ xive_setup_cpu_ipi (smp_processor_id ()); + + return 0; }#endif /* CONFIG_SMP */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1651/1887 powerpc/xive: propagate IPI init errors to prevent use-after-free
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gou Hao <[email protected]>
[ Upstream commit 411a3c016e7a95f5fa105a0587e07d0647a77727 ]
When xive_init_ipis() fails (e.g. irq_domain_alloc_irqs() fails), the error path frees the global xive_ipis array. However, xive_smp_probe() previously ignored this failure and proceeded to call xive_setup_cpu_ipi(), which dereferences the already-freed xive_ipis pointer -- a use-after-free.
Now that xive_smp_probe() returns int (previous patch), propagate the error from xive_init_ipis() and xive_setup_cpu_ipi() through xive_smp_probe(). Check the return value in both pnv_smp_probe() and pSeries_smp_probe() so that IPI setup is aborted cleanly on failure, avoiding the use-after-free.
--- arch/powerpc/platforms/powernv/smp.c | 8 +++++--- arch/powerpc/platforms/pseries/smp.c | 8 +++++--- arch/powerpc/sysdev/xive/common.c | 10 ++++++---- 3 files changed, 16 insertions(+), 10 deletions(-)
arch/powerpc/platforms/powernv/smp.c +5 -3
@@ -329,10 +329,12 @@ static void pnv_cause_ipi(int cpu)static void __init pnv_smp_probe (void ) { -if (xive_enabled ()) -xive_smp_probe (); -else +if (xive_enabled ()) { +if (xive_smp_probe () <0 ) +return ; + }else {xics_smp_probe (); + }if (cpu_has_feature (CPU_FTR_DBELL )) { ic_cause_ipi = smp_ops->cause_ipi;
arch/powerpc/platforms/pseries/smp.c +5 -3
@@ -194,10 +194,12 @@ static int pseries_cause_nmi_ipi(int cpu)static __init void pSeries_smp_probe (void ) { -if (xive_enabled ()) -xive_smp_probe (); -else +if (xive_enabled ()) { +if (xive_smp_probe () <0 ) +return ; + }else {xics_smp_probe (); + }/* No doorbell facility, must use the interrupt controller for IPIs */ if (!cpu_has_feature (CPU_FTR_DBELL ))
arch/powerpc/sysdev/xive/common.c +6 -4
@@ -1272,15 +1272,17 @@ noinstr static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)int __init xive_smp_probe (void ) { +int ret; + smp_ops->cause_ipi = xive_cause_ipi;/* Register the IPI */ -xive_init_ipis (); + ret =xive_init_ipis (); +if (ret <0 ) +return ret;/* Allocate and setup IPI for the boot CPU */ -xive_setup_cpu_ipi (smp_processor_id ()); - -return 0 ; +return xive_setup_cpu_ipi (smp_processor_id ()); }#endif /* CONFIG_SMP */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1652/1887 ext4: fix circular lock dependency in ext4_ext_migrate
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <[email protected]>
[ Upstream commit a897682793eba5de51ee6f3152760374afa629cf ]
Move iput(tmp_inode) after ext4_writepages_up_write() to avoid a circular lock dependency between s_writepages_rwsem and sb_internal (freeze protection).
The deadlock scenario:
CPU0 (EXT4_IOC_MIGRATE) CPU1 (orphan cleanup during mount)
---- ----
ext4_ext_migrate()
ext4_writepages_down_write()
s_writepages_rwsem (write)
ext4_evict_inode()
sb_start_intwrite() [sb_internal]
...
ext4_writepages()
s_writepages_rwsem (read) [BLOCKED]
iput(tmp_inode)
ext4_evict_inode()
sb_start_intwrite() [BLOCKED]The tmp_inode is a temporary inode with nlink=0 created solely for building the extent tree. Its eviction does not require s_writepages_rwsem protection, so deferring iput() until after releasing the rwsem is safe.
--- fs/ext4/migrate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/ext4/migrate.c +2 -1
@@ -457,6 +457,7 @@ int ext4_ext_migrate(struct inode *inode)if (IS_ERR (tmp_inode)) { retval =PTR_ERR (tmp_inode);ext4_journal_stop (handle); + tmp_inode =NULL ; goto out_unlock; }/*
@@ -584,9 +585,9 @@ int ext4_ext_migrate(struct inode *inode)ext4_journal_stop (handle); out_tmp_inode:unlock_new_inode (tmp_inode); -iput (tmp_inode); out_unlock:ext4_writepages_up_write (inode->i_sb, alloc_ctx); +iput (tmp_inode);return retval; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1653/1887 remoteproc: qcom_wcnss: Fix handling the lack of PD regulators in v3
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Val Packett <[email protected]>
[ Upstream commit 3dbc90b9c22ea96e37bf55f6011e63b5123ec668 ]
The changes introduced to handle single power domain platforms have swapped the info pointer increment from num_pd_vregs to num_pds, which would shift the info pointer past the end of the array for pronto-v3, which does not list power domain regulators in vregs.
This showed up as a difference between GCC- and LLVM-compiled kernels on SDM632 devices, where only with LLVM one would get the "regulator request with no identifier" error, because the out-of-bounds memory ended up being zeroed. Fix by skipping the increment when there are more power domains than regulators.
--- drivers/remoteproc/qcom_wcnss.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
drivers/remoteproc/qcom_wcnss.c +14 -9
@@ -430,25 +430,31 @@ static void wcnss_release_pds(struct qcom_wcnss *wcnss) }static int wcnss_init_regulators (struct qcom_wcnss *wcnss, -const struct wcnss_vreg_info *info, -int num_vregs,int num_pd_vregs) +const struct wcnss_data *data) { +const struct wcnss_vreg_info *info = data->vregs;struct regulator_bulk_data *bulk; +size_t i, possible_pds =0 , num_vregs = data->num_vregs;int ret; -int i; + +for (i =0 ; i <WCNSS_MAX_PDS ; i++) +if (data->pd_names[i]) + possible_pds++;/* * If attaching the power domains suceeded we can skip requesting * the regulators for the power domains. For old device trees we need to * reserve extra space to manage them through the regulator interface. */ -if (wcnss->num_pds) { +if (possible_pds >= num_vregs) { +/* Do nothing if vregs do not include PD regulators (pronto-v3) */ + }else if (wcnss->num_pds) { info += wcnss->num_pds;/* Handle single power domain case */ -if (wcnss->num_pds < num_pd_vregs) - num_vregs += num_pd_vregs - wcnss->num_pds; +if (wcnss->num_pds < data->num_pd_vregs) + num_vregs += data->num_pd_vregs - wcnss->num_pds; }else { - num_vregs += num_pd_vregs; + num_vregs += data->num_pd_vregs; } bulk = devm_kcalloc(wcnss->dev,
@@ -607,8 +613,7 @@ static int wcnss_probe(struct platform_device *pdev)if (ret && (ret != -ENODATA || !data->num_pd_vregs)) goto free_rproc; - ret =wcnss_init_regulators (wcnss, data->vregs, data->num_vregs, - data->num_pd_vregs); + ret =wcnss_init_regulators (wcnss, data);if (ret) goto detach_pds;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1654/1887 ksmbd: fix maximum allowed access checks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit cc2f133e80eb2c4a04bfa77a2f207749fe2f516a ]
The DACL permission check looks for an ACE matching the current user and falls back to the Everyone ACE. It does not consider an Authenticated Users ACE, even though an authenticated session is a member of that well-known group.
As a result, opening a file whose access is granted through S-1-5-11 can incorrectly fail with STATUS_ACCESS_DENIED. Treat an Authenticated Users ACE as a fallback entry alongside Everyone.
The maximal access calculation also combines access masks from every ACE, regardless of whether its SID applies to the current user. This can grant rights belonging to an unrelated principal. Process only ACEs applying to the user, Everyone, or Authenticated Users, and accumulate allowed and denied masks in ACL order. Preserve explicitly requested access bits so they are validated against the resulting maximal mask.
When ACCESS_SYSTEM_SECURITY is denied, report STATUS_PRIVILEGE_NOT_HELD instead of the generic STATUS_ACCESS_DENIED. Access to the system ACL requires a security privilege that ksmbd does not grant.
For regular files, include FILE_EXECUTE in maximal access when the client requested GENERIC_EXECUTE and the DACL grants the complete file-read set. Keep a direct FILE_EXECUTE request subject to the explicit DACL bit. This matches the POSIX file ACL mapping without broadening specific execute requests.
Do not replace rights from an applicable NT ACE with a POSIX ACL entry. The POSIX ACL is only a fallback when no user, Everyone, or Authenticated Users ACE applies; otherwise it can incorrectly broaden the stored DACL.
This fixes smb2.maximum_allowed.maximum_allowed.
--- fs/smb/server/smb2pdu.c | 9 ++++- fs/smb/server/smbacl.c | 86 +++++++++++++++++++++++++---------------- fs/smb/server/smbacl.h | 2 +- 3 files changed, 61 insertions(+), 36 deletions(-)
fs/smb/server/smb2pdu.c +7 -2
@@ -3030,6 +3030,7 @@ int smb2_open(struct ksmbd_work *work)if (file_present && !(req->CreateOptions &FILE_DELETE_ON_CLOSE_LE )) { rc =smb_check_perm_dacl (conn, &path, &daccess, + req->DesiredAccess, sess->user->uid);if (rc) goto err_out;
@@ -3514,8 +3515,12 @@ int smb2_open(struct ksmbd_work *work) rsp->hdr.Status =STATUS_INVALID_PARAMETER ; else if (rc == -EOPNOTSUPP) rsp->hdr.Status = STATUS_NOT_SUPPORTED; - else if (rc == -EACCES || rc == -ESTALE || rc == -EXDEV) - rsp->hdr.Status =STATUS_ACCESS_DENIED ; + else if (rc == -EACCES || rc == -ESTALE || rc == -EXDEV) { +if (req->DesiredAccess &FILE_ACCESS_SYSTEM_SECURITY_LE ) + rsp->hdr.Status =STATUS_PRIVILEGE_NOT_HELD ; +else + rsp->hdr.Status =STATUS_ACCESS_DENIED ; + } else if (rc == -ENOENT) rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID; else if (rc == -EPERM)
fs/smb/server/smbacl.c +53 -33
137 lines not on this page · raw message
fs/smb/server/smbacl.h +1 -1
@@ -204,7 +204,7 @@ bool smb_inherit_flags(int flags, bool is_dir);int smb_inherit_dacl (struct ksmbd_conn *conn,const struct path *path,unsigned int uid,unsigned int gid);int smb_check_perm_dacl (struct ksmbd_conn *conn,const struct path *path, -__le32 *pdaccess,int uid); +__le32 *pdaccess,__le32 raw_daccess,int uid);int set_info_sec (struct ksmbd_conn *conn,struct ksmbd_tree_connect *tcon,const struct path *path,struct smb_ntsd *pntsd,int ntsd_len,bool type_check,bool get_write);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1655/1887 ksmbd: preserve VFS inherited POSIX ACL mask
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit e148e567a9252643baa125cb65d7ae9c2c6cf68a ]
The VFS initializes a child's POSIX ACL from the parent's default ACL and the requested creation mode. Do not mutate the parent ACL or overwrite the child's VFS-computed access and default ACLs afterwards.
This preserves restrictive ACL_MASK entries and prevents SMB object creation from widening effective permissions.
--- fs/smb/server/vfs.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-)
fs/smb/server/vfs.c +1 -24
@@ -1953,9 +1953,6 @@ int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns, struct path *path, struct inode *parent_inode) { struct posix_acl *acls; -struct posix_acl_entry *pace; -struct inode *inode =d_inode (path->dentry); -int rc, i;if (!IS_ENABLED (CONFIG_FS_POSIX_ACL ))return -EOPNOTSUPP ;
@@ -1963,27 +1960,7 @@ int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns, acls =get_acl (parent_inode,ACL_TYPE_DEFAULT );if (IS_ERR_OR_NULL (acls))return -ENOENT ; - pace = acls->a_entries; - -for (i =0 ; i < acls->a_count; i++, pace++) { -if (pace->e_tag ==ACL_MASK ) { - pace->e_perm =0x07 ; -break ; - } - } - - rc =set_posix_acl (user_ns, inode,ACL_TYPE_ACCESS , acls); -if (rc <0 ) -ksmbd_debug (SMB ,"Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n" , - rc); -if (S_ISDIR (inode->i_mode)) { - rc =set_posix_acl (user_ns, inode,ACL_TYPE_DEFAULT , - acls); -if (rc <0 ) -ksmbd_debug (SMB ,"Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n" , - rc); - }posix_acl_release (acls); -return rc; +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1656/1887 wifi: iwlwifi: mvm: fix out-of-bounds tid_data access in BA notif
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit 94d3982806c7f194b23484befde12934dda23064 ]
mvmsta->tid_data was indexed by the TFD loop counter 'i' instead of the actual TID value 'tid'. This writes lq_color into a random tid_data slot unrelated to the BA entry.
Since multi-TID blockack is not really in use, 'i' was always 0 and no harm was done.
Add a out-of-bound check before accessing the array.
--- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/mvm/tx.c +7 -1
@@ -2094,8 +2094,14 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)if (tid ==IWL_MGMT_TID ) tid =IWL_MAX_TID_COUNT ; +if (tid >=ARRAY_SIZE (mvmsta->tid_data)) { +IWL_WARN (mvm,"invalid TID %d in compressed BA\n" , + tid); +continue ; + } +if (mvmsta) - mvmsta->tid_data[i].lq_color = lq_color; + mvmsta->tid_data[tid].lq_color = lq_color; iwl_mvm_tx_reclaim(mvm, sta_id, tid, (int)(le16_to_cpu(ba_tfd->q_num)),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1657/1887 wifi: iwlwifi: mvm: add a check on the tid coming from the firmware
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit 0e4c0d83267261cf67ec9690856edf4a56bb7dfc ]
ba_notif->tid is a firmware-controlled u8 that is used directly as an array index into tid_data[] without any validation. Add a bounds check against IWL_MAX_TID_COUNT before dereferencing the array.
--- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/wireless/intel/iwlwifi/mvm/tx.c +4 -0
@@ -2126,6 +2126,10 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) ba_notif = (void *)pkt->data; sta_id = ba_notif->sta_id; tid = ba_notif->tid; +if (tid >=IWL_MAX_TID_COUNT ) { +IWL_WARN (mvm,"invalid TID %d in BA notif\n" , tid); +return ; + }/* "flow" corresponds to Tx queue */ txq =le16_to_cpu (ba_notif->scd_flow);/* "ssn" is start of block-ack Tx window, corresponds to index
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1658/1887 wifi: iwlwifi: mvm: fix a possible underflow
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit 0cb5260a1027a43f8cdb961e128f2ddd42e46832 ]
We shouldn't trust the firmware about the length of the wowlan packet.
--- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/net/wireless/intel/iwlwifi/mvm/d3.c +14 -4
@@ -1508,6 +1508,10 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,if (WARN_ON_ONCE (truncated <0 )) truncated =0 ; +/* this would be a firmware bug */ +if (WARN_ON_ONCE (pktsize <sizeof (*hdr))) +return ; +if (ieee80211_is_data (hdr->frame_control)) {int hdrlen =ieee80211_hdrlen (hdr->frame_control);int ivlen =0 , icvlen =4 ;/* also FCS */
@@ -1516,10 +1520,6 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,if (!pkt) goto report; -skb_put_data (pkt, pktdata, hdrlen); - pktdata += hdrlen; - pktsize -= hdrlen; -if (ieee80211_has_protected (hdr->frame_control)) {/* * This is unlocked and using gtk_i(c)vlen,
@@ -1545,6 +1545,16 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, truncated =0 ; } +if (pktsize <= hdrlen + ivlen + icvlen) { +IWL_WARN (mvm,"pktsize is too small %d\n" , + pktsize); +kfree_skb (pkt); +return ; + } + +skb_put_data (pkt, pktdata, hdrlen); + pktdata += hdrlen; + pktsize -= hdrlen; pktsize -= ivlen + icvlen; pktdata += ivlen;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1659/1887 wifi: iwlwifi: mvm: validate TX_CMD response layout
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit 8d70881707b47353359df57df12f6de67fdacdd2 ]
TX_CMD parsing uses frame_count to walk status entries and then read the trailing SCD SSN. Make the minimum-length check follow that exact runtime layout calculation before parsing the payload.
For new TX API, reject TX_CMD responses with frame_count != 1 and warn/return in the aggregation handler to document that aggregated accounting is expected via BA notifications.
--- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+)
drivers/net/wireless/intel/iwlwifi/mvm/tx.c +35 -0
@@ -1550,6 +1550,17 @@ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm *mvm, tx_resp->frame_count) & 0xfff; } +static inline size_t iwl_mvm_tx_resp_min_len (struct iwl_mvm *mvm, +struct iwl_mvm_tx_resp *tx_resp) +{ +struct agg_tx_status *agg_status = +iwl_mvm_get_agg_status (mvm, tx_resp); + +/* The aggregate response ends with a trailing SCD SSN __le32 word. */ +return (u8 *)(agg_status + tx_resp->frame_count) - (u8 *)tx_resp + +sizeof (__le32); +} +static void iwl_mvm_rx_tx_cmd_single (struct iwl_mvm *mvm,struct iwl_rx_packet *pkt) {
@@ -1854,6 +1865,9 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,int queue =SEQ_TO_QUEUE (sequence);struct ieee80211_sta *sta; +if (WARN_ON_ONCE (iwl_mvm_has_new_tx_api (mvm))) +return ; +if (WARN_ON_ONCE (queue <IWL_MVM_DQA_MIN_DATA_QUEUE && (queue !=IWL_MVM_DQA_BSS_CLIENT_QUEUE )))return ;
@@ -1888,6 +1902,27 @@ void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) {struct iwl_rx_packet *pkt =rxb_addr (rxb);struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; +size_t min_len; + +if (!tx_resp->frame_count) { +IWL_WARN (mvm,"invalid TX_CMD frame_count %u\n" , + tx_resp->frame_count); +return ; + } + +if (iwl_mvm_has_new_tx_api (mvm) && tx_resp->frame_count !=1 ) { +IWL_WARN (mvm,"invalid TX_CMD frame_count %u for new TX API\n" , + tx_resp->frame_count); +return ; + } + + min_len =iwl_mvm_tx_resp_min_len (mvm, tx_resp); +if (iwl_rx_packet_payload_len (pkt) < min_len) { +IWL_WARN (mvm,"invalid TX_CMD len %u (frame_count %u, min %zu)\n" , +iwl_rx_packet_payload_len (pkt), tx_resp->frame_count, + min_len); +return ; + }if (tx_resp->frame_count ==1 )iwl_mvm_rx_tx_cmd_single (mvm, pkt);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1660/1887 smb/client: flush dirty data before punching a hole
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huiwen He <[email protected]>
[ Upstream commit d7d2adcd022baade5cab65ca492ce63421ce3a6e ]
Punching a hole after a large buffered write may leave the range reported as data. Reproduce it with:
xfs_io -f \
-c "pwrite -b 3m -S 0x61 0 3m" \
-c "fpunch 1m 1m" \
-c "seek -h 0" \
-c "seek -d 1m" \
/mnt/test/reproPunching 1 MiB at offset 1 MiB should produce:
0 1 MiB 2 MiB 3 MiB | DATA | HOLE | DATA | EOF
Instead, the entire file is reported as data. SEEK_HOLE(0) returns EOF, and SEEK_DATA(1M) returns 1M.
This happens because a dirty folio spanning the punched range can be written back after the punch and refill the hole.
Fix this by flushing and waiting for dirty data in the punched range before invalidating the page cache and issuing FSCTL_SET_ZERO_DATA.
The xfstests generic/539 pass against Samba/ksmbd with this change.
--- fs/smb/client/smb2ops.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
fs/smb/client/smb2ops.c +10 -0
@@ -3599,6 +3599,15 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, goto out;filemap_invalidate_lock (inode->i_mapping); +/* +* Flush dirty data first, otherwise a dirty folio spanning the punched +* range may be written back after the ioctl and refill the hole. +*/ + rc =filemap_write_and_wait_range (inode->i_mapping, offset, + offset + len -1 ); +if (rc <0 ) + goto unlock; +/* * We implement the punch hole through ioctl, so we need remove the page * caches first, otherwise the data may be inconsistent with the server.
@@ -3615,6 +3624,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, (char *)&fsctl_buf,sizeof (struct file_zero_data_information ), CIFSMaxBufSize, NULL, NULL); +unlock:filemap_invalidate_unlock (inode->i_mapping); out:inode_unlock (inode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1661/1887 wifi: iwlwifi: pcie: null RX pointers after free
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit 2c79d7a7b583050c9f58041465cb46fe3483ab5d ]
When iwl_pcie_tx_init() fails after RX init, nic init unwinds via iwl_pcie_rx_free().
The freed RX members stayed non-NULL on the live transport object, so later teardown or retry could touch stale RX state. Set rx_pool, global_table, rxq, and alloc_page to NULL after free to make repeated cleanup and retry paths safe.
--- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/net/wireless/intel/iwlwifi/pcie/rx.c +7 -2
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* -* Copyright (C) 2003-2014, 2018-2023 Intel Corporation +* Copyright (C) 2003-2014, 2018-2023, 2026 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */
@@ -1232,11 +1232,16 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) } }kfree (trans_pcie->rx_pool); + trans_pcie->rx_pool =NULL ;kfree (trans_pcie->global_table); + trans_pcie->global_table =NULL ;kfree (trans_pcie->rxq); + trans_pcie->rxq =NULL ; -if (trans_pcie->alloc_page) +if (trans_pcie->alloc_page) {__free_pages (trans_pcie->alloc_page, trans_pcie->rx_page_order); + trans_pcie->alloc_page =NULL ; + } } static void iwl_pcie_rx_move_to_allocator(struct iwl_rxq *rxq,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1662/1887 wifi: mac80211: ibss: wait for in-flight TX on disconnect
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pagadala Yesu Anjaneyulu <[email protected]>
[ Upstream commit d0e69d9afa59b93c30294eba89b1f15f69e91105 ]
While leaving an IBSS in ieee80211_ibss_disconnect() mac80211 flushes stations, turns the carrier off and immediately tells the driver to leave as well. While there may be synchronize_net() in station flush and in this code later, packets can still be transmitted due to cross-CPU race conditions after carrier off is set. Therefore, it's possible for a race to happen where a TX to the driver occurs while or after telling it to leave the IBSS. This can be confusing to drivers, and in the case of iwlwifi leads to an attempt to use invalid queues.
Move netif_carrier_off() to occur before sta_info_flush() during IBSS disconnect, and add synchronize_net() if flushing didn't, so that the synchronize_net() always happens between turning the carrier off and telling the driver, avoiding this race.
--- net/mac80211/ibss.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
net/mac80211/ibss.c +3 -6
@@ -692,7 +692,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) ifibss->state =IEEE80211_IBSS_MLME_SEARCH ; -sta_info_flush (sdata); +netif_carrier_off (sdata->dev); +if (!sta_info_flush (sdata)) +synchronize_net ();spin_lock_bh (&ifibss->incomplete_lock);while (!list_empty (&ifibss->incomplete_stations)) {
@@ -706,8 +708,6 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) }spin_unlock_bh (&ifibss->incomplete_lock); -netif_carrier_off (sdata->dev); - sdata->vif.cfg.ibss_joined = false; sdata->vif.cfg.ibss_creator = false; sdata->vif.bss_conf.enable_beacon = false;
@@ -737,7 +737,6 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work)sdata_lock (sdata);ieee80211_ibss_disconnect (sdata); -synchronize_rcu ();skb_queue_purge (&sdata->skb_queue);/* trigger a scan to find another IBSS network to join */
@@ -1878,8 +1877,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)memset (&ifibss->ht_capa,0 ,sizeof (ifibss->ht_capa));memset (&ifibss->ht_capa_mask,0 ,sizeof (ifibss->ht_capa_mask)); -synchronize_rcu (); -skb_queue_purge (&sdata->skb_queue);del_timer_sync (&sdata->u.ibss.timer);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1663/1887 perf: Fix addr_filter_ranges lifetime
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Zijlstra <[email protected]>
[ Upstream commit e62d4192e593630f355094adc467058a05bdc935 ]
Lee Jia Jie reported that since event::addr_filter_ranges is used under RCU, it should be RCU freed.
--- kernel/events/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
kernel/events/core.c +1 -3
@@ -4802,6 +4802,7 @@ static void free_event_rcu(struct rcu_head *head)if (event->ns)put_pid_ns (event->ns);perf_event_free_filter (event); +kfree (event->addr_filter_ranges);kmem_cache_free (perf_event_cache, event); }
@@ -5048,7 +5049,6 @@ static void _free_event(struct perf_event *event)perf_event_free_bpf_prog (event);perf_addr_filters_splice (event,NULL ); -kfree (event->addr_filter_ranges);if (event->destroy) event->destroy (event);
@@ -12058,8 +12058,6 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,put_callchain_buffers (); } err_addr_filters: -kfree (event->addr_filter_ranges); - err_per_task:exclusive_event_destroy (event);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1664/1887 drm/amdkfd: Let driver decide buffer size at AMDKFD_IOC_GET_DMABUF_INFO ioctl
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaogang Chen <[email protected]>
[ Upstream commit 8242a8d9d7194d5ef8a8b38a5621ca0966a3ec15 ]
amdkfd driver needs allocate buffer to return bo metadata to user space. The buffer size is controlled by user currently. It is a potential security issue that hostile value (e.g. 2 GiB) lets any render-group user trigger order-MAX allocation/OOM in kernel context.
This patch first finds bo metadata size. If the size is smaller than user provided value drive can safely allocate buffer in kernel space and copy to user space buffer. If not, driver will let user know, not allocate and copy. User will redo with new buffer in user space.
This patch lets driver decide buffer allocation size to avoid potential hostile size from user space.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 25 ++++++++++++++++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 10 ++------- 3 files changed, 24 insertions(+), 13 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +21 -4
@@ -495,7 +495,7 @@ void amdgpu_amdkfd_get_cu_info(struct amdgpu_device *adev, struct kfd_cu_info *cint amdgpu_amdkfd_get_dmabuf_info (struct amdgpu_device *adev,int dma_buf_fd,struct amdgpu_device **dmabuf_adev, -uint64_t *bo_size,void *metadata_buffer, +uint64_t *bo_size,void **metadata_buffer,size_t buffer_size,uint32_t *metadata_size,uint32_t *flags) {
@@ -530,9 +530,26 @@ int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd, *dmabuf_adev = adev;if (bo_size) *bo_size =amdgpu_bo_size (bo); -if (metadata_buffer) - r =amdgpu_bo_get_metadata (bo, metadata_buffer, buffer_size, - metadata_size, &metadata_flags); +if (metadata_buffer) { +/* first get metadata_size by buffer = NULL */ + r =amdgpu_bo_get_metadata (bo,NULL ,0 , + metadata_size,NULL ); + +/* user buf_size is bigger than bo metadata_size +* allocate a buf at kernel space and copy */ +if (*metadata_size <= buffer_size) { + *metadata_buffer =kzalloc (*metadata_size,GFP_KERNEL ); + +if (!*metadata_buffer) { + r = -ENOMEM ; + goto out_put; + } + + r =amdgpu_bo_get_metadata (bo, *metadata_buffer, *metadata_size, +NULL , &metadata_flags); + }else + r = -EINVAL ; + }if (flags) { *flags = (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) ? KFD_IOC_ALLOC_MEM_FLAGS_VRAM
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +1 -1
@@ -227,7 +227,7 @@ void amdgpu_amdkfd_get_cu_info(struct amdgpu_device *adev, struct kfd_cu_info *cu_info);int amdgpu_amdkfd_get_dmabuf_info (struct amdgpu_device *adev,int dma_buf_fd,struct amdgpu_device **dmabuf_adev, -uint64_t *bo_size,void *metadata_buffer, +uint64_t *bo_size,void **metadata_buffer,size_t buffer_size,uint32_t *metadata_size,uint32_t *flags); uint8_t amdgpu_amdkfd_get_xgmi_hops_count(struct amdgpu_device *dst,
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +2 -8
@@ -1507,16 +1507,10 @@ static int kfd_ioctl_get_dmabuf_info(struct file *filep,if (!dev)return -EINVAL ; -if (args->metadata_ptr) { - metadata_buffer =kzalloc (args->metadata_size,GFP_KERNEL ); -if (!metadata_buffer) -return -ENOMEM ; - } -/* Get dmabuf info from KGD */ r =amdgpu_amdkfd_get_dmabuf_info (dev->adev, args->dmabuf_fd, &dmabuf_adev, &args->size, - metadata_buffer, args->metadata_size, + &metadata_buffer, args->metadata_size, &args->metadata_size, &flags);if (r) goto exit;
@@ -1531,7 +1525,7 @@ static int kfd_ioctl_get_dmabuf_info(struct file *filep, args->flags = flags;/* Copy metadata buffer to user mode */ -if (metadata_buffer) { +if (metadata_buffer && args->metadata_ptr) { r =copy_to_user ((void __user *)args->metadata_ptr, metadata_buffer, args->metadata_size);if (r !=0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1665/1887 exfat: resolve memory leak from exfat_create_upcase_table()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Yang <[email protected]>
[ Upstream commit c290fe508eee36df1640c3cb35dc8f89e073c8a8 ]
If exfat_load_upcase_table reaches end and returns -EINVAL, allocated memory doesn't get freed and while exfat_load_default_upcase_table allocates more memory, leading to a memory leak.
Here's link to syzkaller crash report illustrating this issue:
https://syzkaller.appspot.com/text?tag=CrashReport&x=1406c201980000
Stable-dep-of: 20dd3185d138 ("exfat: fix handling of damaged volume in exfat_create_upcase_table()")
--- fs/exfat/nls.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/exfat/nls.c +4 -1
@@ -785,8 +785,11 @@ int exfat_create_upcase_table(struct super_block *sb) le32_to_cpu(ep->dentry.upcase.checksum));brelse (bh); -if (ret && ret != -EIO ) +if (ret && ret != -EIO ) { +/* free memory from exfat_load_upcase_table call */ +exfat_free_upcase_table (sbi); goto load_default; + }/* load successfully */ return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1666/1887 exfat: fix handling of damaged volume in exfat_create_upcase_table()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Timber <[email protected]>
[ Upstream commit 20dd3185d13865214ff25b0bf7b931e8d73be1ac ]
When the size of the upcase table is set to zero in the dentry for any reason(e.g. corrupted media or misbehaving device), an integer overflow causes the module to loop indefinitely.
If the size of the upcase table is read zero, do not attempt to load the table. Instead, fallback to loading the default upcase table. If the size of the upcase table is zero or no upcase table is found, raise exfat_fs_error() to mark the volume read-only.
--- fs/exfat/nls.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
fs/exfat/nls.c +13 -6
@@ -778,13 +778,18 @@ int exfat_create_upcase_table(struct super_block *sb) tbl_clu =le32_to_cpu (ep->dentry.upcase.start_clu); tbl_size =le64_to_cpu (ep->dentry.upcase.size); - - sector =exfat_cluster_to_sector (sbi, tbl_clu); - num_sectors = ((tbl_size -1 ) >> blksize_bits) +1 ; - ret =exfat_load_upcase_table (sb, sector, num_sectors, -le32_to_cpu (ep->dentry.upcase.checksum)); - +if (tbl_size) { + sector =exfat_cluster_to_sector (sbi, tbl_clu); + num_sectors = ((tbl_size -1 ) >> blksize_bits) +1 ; + ret =exfat_load_upcase_table (sb, sector, num_sectors, +le32_to_cpu (ep->dentry.upcase.checksum)); + }else { +exfat_fs_error (sb, +"bad upcase table size (0 bytes). Please run fsck" ); + ret = -EINVAL ; + }brelse (bh); +if (ret && ret != -EIO ) {/* free memory from exfat_load_upcase_table call */ exfat_free_upcase_table (sbi);
@@ -799,6 +804,8 @@ int exfat_create_upcase_table(struct super_block *sb)return -EIO ; } +exfat_fs_error (sb,"no upcase table entry. Please run fsck" ); + load_default:/* load default upcase table */ return exfat_load_default_upcase_table (sb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1667/1887 cifs: get rid of dns resolve worker
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
[ Upstream commit 0e9bd27b2a635d54665fcc1d6398a5f6aeb6b0cb ]
We already upcall to resolve hostnames during reconnect by calling reconn_set_ipaddr_from_hostname(), so there is no point in having a worker to periodically call it.
Reviewed-by <[email protected]>
Stable-dep-of: e8a5cf2ff5a1 ("smb: client: fix races in cifsd thread creation")
--- fs/smb/client/cifsglob.h | 5 ---- fs/smb/client/connect.c | 50 ++-------------------------------------- 2 files changed, 2 insertions(+), 53 deletions(-)
fs/smb/client/cifsglob.h +0 -5
@@ -80,10 +80,6 @@#define SMB_ECHO_INTERVAL_MAX 600#define SMB_ECHO_INTERVAL_DEFAULT 60 -/* dns resolution intervals in seconds */ -#define SMB_DNS_RESOLVE_INTERVAL_MIN 120 -#define SMB_DNS_RESOLVE_INTERVAL_DEFAULT 600 -/* smb multichannel query server interfaces interval in seconds */ #define SMB_INTERFACE_POLL_INTERVAL 600
@@ -672,7 +668,6 @@ struct TCP_Server_Info {/* point to the SMBD connection if RDMA is used instead of socket */ struct smbd_connection *smbd_conn;struct delayed_work echo;/* echo ping workqueue job */ -struct delayed_work resolve;/* dns resolution workqueue job */ char *smallbuf;/* pointer to current "small" buffer */ char *bigbuf;/* pointer to current "big" buffer */ /* Total size of this PDU. Only valid from cifs_demultiplex_thread */
fs/smb/client/connect.c +2 -48
105 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1668/1887 smb: client: fix races in cifsd thread creation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fredric Cover <[email protected]>
[ Upstream commit e8a5cf2ff5a13fefb228f2069e29dd7d8e37185d ]
The cifsd demultiplex thread can run and access tcp_ses before the parent thread has finished populating tcp_ses, which the worker thread accesses locklessly.
Also, the kthread_run macro may start the thread before returning the thread pointer. Because the pointer is part of the structure that the thread can access, if the kernel is preempted after the thread is spawned, but before the thread pointer is populated and the thread attempts to exit, it will sleep, waiting for a SIGKILL signal.
Fix this by moving creation of the thread to after all of tcp_ses'es fields are populated, and spawning the thread last, using a split kthread_create/wake_up_process logic.
--- fs/smb/client/connect.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-)
fs/smb/client/connect.c +16 -11
@@ -1817,23 +1817,13 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,* this will succeed. No need for try_module_get(). */ __module_get (THIS_MODULE ); - tcp_ses->tsk =kthread_run (cifs_demultiplex_thread, - tcp_ses,"cifsd" ); -if (IS_ERR (tcp_ses->tsk)) { - rc =PTR_ERR (tcp_ses->tsk); -cifs_dbg (VFS ,"error %d create cifsd thread\n" , rc); -module_put (THIS_MODULE ); - goto out_err_crypto_release; - } tcp_ses->min_offload = ctx->min_offload;/* * at this point we are the only ones with the pointer * to the struct since the kernel thread not created yet * no need to spinlock this update of tcpStatus */ -spin_lock (&tcp_ses->srv_lock); tcp_ses->tcpStatus = CifsNeedNegotiate; -spin_unlock (&tcp_ses->srv_lock);if ((ctx->max_credits <20 ) || (ctx->max_credits >60000 )) tcp_ses->max_credits =SMB2_MAX_CREDITS_AVAILABLE ;
@@ -1842,7 +1832,16 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, tcp_ses->nr_targets =1 ; tcp_ses->ignore_signature = ctx->ignore_signature; -/* thread spawned, put it on the list */ + + tcp_ses->tsk =kthread_create (cifs_demultiplex_thread, + tcp_ses,"cifsd" ); +if (IS_ERR (tcp_ses->tsk)) { + rc =PTR_ERR (tcp_ses->tsk); +cifs_dbg (VFS ,"error %d create cifsd thread\n" , rc); +module_put (THIS_MODULE ); + goto out_err_crypto_release; + } +/* thread created, put it on the list */ spin_lock (&cifs_tcp_ses_lock);list_add (&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);spin_unlock (&cifs_tcp_ses_lock);
@@ -1850,6 +1849,12 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,/* queue echo request delayed work */ queue_delayed_work (cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval); +/* +* Use split create/wake logic to ensure that tcp_ses is fully populated +* and tcp_ses->tsk is valid +*/ +wake_up_process (tcp_ses->tsk); +return tcp_ses; out_err_crypto_release:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1669/1887 nvme-fc: Do not cancel requests in io target before it is initialized
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohamed Khalfella <[email protected]>
[ Upstream commit ee38469f88492df99e1d97f03aa40ecfd218934f ]
A new nvme-fc controller in CONNECTING state sees admin request timeout schedules ctrl->ioerr_work to abort inflight requests. This ends up calling __nvme_fc_abort_outstanding_ios() which aborts requests in both admin and io tagsets. In case fc_ctrl->tag_set was not initialized we see the warning below. This is because ctrl.queue_count is initialized early in nvme_fc_alloc_ctrl().
nvme nvme0: NVME-FC{0}: starting error recovery Connectivity Loss
INFO: trying to register non-static key.
The code is fine but needs lockdep annotation, or maybe lpfc 0000:ab:00.0: queue 0 connect admin queue failed (-6). you didn't initialize this object before use?
turning off the locking correctness validator.
Workqueue: nvme-reset-wq nvme_fc_ctrl_ioerr_work [nvme_fc] Call Trace: <TASK> dump_stack_lvl+0x57/0x80 register_lock_class+0x567/0x580 __lock_acquire+0x330/0xb90 lock_acquire.part.0+0xad/0x210 blk_mq_tagset_busy_iter+0xf9/0xc00 __nvme_fc_abort_outstanding_ios+0x23f/0x320 [nvme_fc] nvme_fc_ctrl_ioerr_work+0x172/0x210 [nvme_fc] process_one_work+0x82c/0x1450 worker_thread+0x5ee/0xfd0 kthread+0x3a0/0x750 ret_from_fork+0x439/0x670 ret_from_fork_asm+0x1a/0x30 </TASK>
Update the check in __nvme_fc_abort_outstanding_ios() confirm that io tagset was created before iterating over busy requests. Also make sure to cancel ctrl->ioerr_work before removing io tagset.
--- drivers/nvme/host/fc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/nvme/host/fc.c +6 -1
@@ -2492,7 +2492,7 @@ __nvme_fc_abort_outstanding_ios(struct nvme_fc_ctrl *ctrl, bool start_queues)* io requests back to the block layer as part of normal completions * (but with error status). */ -if (ctrl->ctrl.queue_count >1 ) { +if (ctrl->ctrl.queue_count >1 && ctrl->ctrl.tagset) {nvme_stop_queues (&ctrl->ctrl);nvme_sync_io_queues (&ctrl->ctrl); blk_mq_tagset_busy_iter(&ctrl->tag_set,
@@ -2925,6 +2925,11 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl) out_delete_hw_queues:nvme_fc_delete_hw_io_queues (ctrl); out_cleanup_tagset: +/* +* In CONNECTING state ctrl->ioerr_work will abort both admin +* and io tagsets. Cancel it first before removing io tagset. +*/ +cancel_work_sync (&ctrl->ioerr_work);nvme_remove_io_tag_set (&ctrl->ctrl);nvme_fc_free_io_queues (ctrl);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1670/1887 drm/amdkfd: fix SMI event cross-process information leak
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongqiang Sun <[email protected]>
[ Upstream commit 92a8dba246d371fe268280e5fd74b0955688e6df ]
kfd_smi_ev_enabled() skips the suser privilege check when pid=0. PROCESS_START, PROCESS_END, and VMFAULT events are emitted with pid=0 while carrying another process's PID and command name, so any /dev/kfd user in the render group can monitor all GPU workloads.
Pass the target process PID into kfd_smi_event_add() for these events so the existing per-client filter restricts delivery to the owning process or CAP_SYS_ADMIN subscribers.
--- drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c +3 -2
@@ -244,8 +244,9 @@ void kfd_smi_event_update_vmfault(struct kfd_dev *dev, uint16_t pasid)if (task_info) {/* Report VM faults from user applications, not retry from kernel */ if (task_info->pid) -kfd_smi_event_add (0 , dev,KFD_SMI_EVENT_VMFAULT ,"%x:%s\n" , - task_info->pid, task_info->task_name); +kfd_smi_event_add (task_info->tgid, dev, +KFD_SMI_EVENT_VMFAULT ,"%x:%s\n" , + task_info->pid, task_info->task_name);amdgpu_vm_put_task_info (task_info); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1671/1887 drm/amdgpu: Add vbios attribute only if supported
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lijo Lazar <[email protected]>
[ Upstream commit 184d83848242b2465b466a0a8e6eb58f1df10407 ]
Not all devices carry VBIOS version information. Add the device attribute only if supported.
Stable-dep-of: 6229898d46c0 ("drm/amdgpu: fix buffer overflow during vBIOS update")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 9 +++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 5 +++++ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 -- 4 files changed, 15 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +9 -0
@@ -1793,6 +1793,15 @@ const struct attribute_group amdgpu_vbios_version_attr_group = { .attrs = amdgpu_vbios_version_attrs }; +int amdgpu_atombios_sysfs_init (struct amdgpu_device *adev) +{ +if (adev->mode_info.atom_context) +return devm_device_add_group (adev->dev, + &amdgpu_vbios_version_attr_group); + +return 0 ; +} +/** * amdgpu_atombios_fini - free the driver info and callbacks for atombios *
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h +1 -0
@@ -217,5 +217,6 @@ int amdgpu_atombios_get_data_table(struct amdgpu_device *adev,void amdgpu_atombios_fini (struct amdgpu_device *adev);int amdgpu_atombios_init (struct amdgpu_device *adev); +int amdgpu_atombios_sysfs_init (struct amdgpu_device *adev);#endif
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +5 -0
@@ -3984,6 +3984,11 @@ int amdgpu_device_init(struct amdgpu_device *adev,/* Get a log2 for easy divisions. */ adev->mm_stats.log2_max_MBps =ilog2 (max (1u , max_MBps)); + r =amdgpu_atombios_sysfs_init (adev); +if (r) +drm_err (&adev->ddev, +"registering atombios sysfs failed (%d).\n" , r); + r =amdgpu_pm_sysfs_init (adev);if (r) { adev->pm_sysfs_en = false;
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +0 -2
@@ -2856,12 +2856,10 @@ static struct pci_error_handlers amdgpu_pci_err_handler = {extern const struct attribute_group amdgpu_vram_mgr_attr_group;extern const struct attribute_group amdgpu_gtt_mgr_attr_group; -extern const struct attribute_group amdgpu_vbios_version_attr_group;static const struct attribute_group *amdgpu_sysfs_groups[] = { &amdgpu_vram_mgr_attr_group, &amdgpu_gtt_mgr_attr_group, - &amdgpu_vbios_version_attr_group,NULL , };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1672/1887 drm/amd: Use attribute groups for PSP flashing attributes
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
[ Upstream commit 521289d2a279b2fbea0450d5e8e6a01cf70a80b3 ]
Individually creating attributes can be racy, instead make attributes using attribute groups and control their visibility with an is_visible callback to only show when using appropriate products.
v2: squash in fix for PSP 13.0.10
Only the relocation of the vbflash binary attribute definition ahead of the status handler is carried over; the attribute group conversion is not needed here and is dropped.
Stable-dep-of: 6229898d46c0 ("drm/amdgpu: fix buffer overflow during vBIOS update")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +7 -7
@@ -3614,6 +3614,13 @@ static ssize_t amdgpu_psp_vbflash_read(struct file *filp, struct kobject *kobj,return 0 ; } +static const struct bin_attribute psp_vbflash_bin_attr = { + .attr = {.name ="psp_vbflash" , .mode =0660 }, + .size =0 , + .write = amdgpu_psp_vbflash_write, + .read = amdgpu_psp_vbflash_read, +}; +static ssize_t amdgpu_psp_vbflash_status (struct device *dev,struct device_attribute *attr,char *buf)
@@ -3631,13 +3638,6 @@ static ssize_t amdgpu_psp_vbflash_status(struct device *dev,return sysfs_emit (buf,"0x%x\n" , vbflash_status); } -static const struct bin_attribute psp_vbflash_bin_attr = { - .attr = {.name ="psp_vbflash" , .mode =0660 }, - .size =0 , - .write = amdgpu_psp_vbflash_write, - .read = amdgpu_psp_vbflash_read, -}; - static DEVICE_ATTR(psp_vbflash_status, 0440, amdgpu_psp_vbflash_status, NULL);int amdgpu_psp_sysfs_init (struct amdgpu_device *adev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1673/1887 drm/amdgpu: fix buffer overflow during vBIOS update
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shiwu Zhang <[email protected]>
[ Upstream commit 6229898d46c0cbc238a6fe9f11c1ea12cf8bb9c5 ]
Clamp the buffer postion to write by setting the bin attribute to the maximum buffer size so that VFS layer will block the out-of-bounds accessing.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +1 -1
@@ -3616,7 +3616,7 @@ static ssize_t amdgpu_psp_vbflash_read(struct file *filp, struct kobject *kobj,static const struct bin_attribute psp_vbflash_bin_attr = { .attr = {.name ="psp_vbflash" , .mode =0660 }, - .size =0 , + .size =AMD_VBIOS_FILE_MAX_SIZE_B , .write = amdgpu_psp_vbflash_write, .read = amdgpu_psp_vbflash_read, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1674/1887 RDMA/counter: Fix num_counters leak on bind_qp failure in alloc_and_bind()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
[ Upstream commit 4fbc8230009f5b1bcd13cc74c5a6a43ddba141fd ]
When __rdma_counter_bind_qp() fails in alloc_and_bind(), the error path jumps to err_mode which frees the counter without decrementing port_counter->num_counters. The only place that decrements is rdma_counter_free(), which is unreachable since the counter was never successfully bound.
This leak accumulates across repeated failures, permanently preventing the port from switching to AUTO mode (-EBUSY in __counter_set_mode()) and blocking the MANUAL→NONE auto-revert in rdma_counter_free(). When the mode was NONE before the call, the MANUAL mode set by __counter_set_mode() also leaks since the revert logic is never reached.
Add an err_bind label between the num_counters increment and the existing err_mode label. It decrements num_counters and mirrors the MANUAL→NONE revert from rdma_counter_free(), ensuring the port state is fully restored on bind failure.
--- drivers/infiniband/core/counters.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/infiniband/core/counters.c +8 -1
@@ -190,12 +190,19 @@ static struct rdma_counter *alloc_and_bind(struct ib_device *dev, u32 port, ret =__rdma_counter_bind_qp (counter, qp);if (ret) - goto err_mode; + goto err_bind;rdma_restrack_parent_name (&counter->res, &qp->res);rdma_restrack_add (&counter->res);return counter; +err_bind: +mutex_lock (&port_counter->lock); + port_counter->num_counters--; +if (!port_counter->num_counters && + port_counter->mode.mode ==RDMA_COUNTER_MODE_MANUAL ) +__counter_set_mode (port_counter,RDMA_COUNTER_MODE_NONE ,0 ); +mutex_unlock (&port_counter->lock); err_mode:rdma_free_hw_stats_struct (counter->stats); err_stats:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1675/1887 virt: acrn: Fix irqfd use-after-free during eventfd shutdown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sicong Huang <[email protected]>
[ Upstream commit 666c7f9e07925aa0863348f960e09bb89f8f05a3 ]
acrn_irqfd_deassign() and the eventfd EPOLLHUP wakeup can race and free the same struct hsm_irqfd:
CPU0 CPU1
---- ----
eventfd_release()
wake_up_poll(EPOLLHUP)
hsm_irqfd_wakeup()
queue_work(&irqfd->shutdown)
acrn_irqfd_deassign()
hsm_irqfd_shutdown()
list_del_init()
eventfd_ctx_remove_wait_queue()
eventfd_ctx_put()
kfree(irqfd) hsm_irqfd_shutdown_work()
container_of(work, ..., shutdown)
irqfd->vm <-- use-after-free
The deassign path freed the irqfd while a shutdown work item was already queued by EPOLLHUP (or vice versa), so the work item could resurrect a dangling pointer through container_of().
Switch to the lifetime model used by KVM irqfds:
- Deassign/deinit only deactivate the irqfd: remove it from vm->irqfds under irqfds_lock and queue the cleanup work.
- hsm_irqfd_shutdown_work() becomes the sole owner that unhooks the eventfd waitqueue entry, drops the eventfd reference and frees the irqfd.
- A new HSM_IRQFD_FLAG_SHUTDOWN bit guarded by test_and_set_bit() ensures the cleanup work is queued at most once, no matter how many of {EPOLLHUP, deassign, deinit} fire concurrently. This is safe to call from the waitqueue callback, which runs with wqh->lock held and IRQs disabled and therefore cannot take irqfds_lock.
- acrn_irqfd_deassign() flushes vm->irqfd_wq before returning so the eventfd is fully detached on return. acrn_irqfd_deinit() deactivates every irqfd, flushes the workqueue and only then destroys it, so no path can queue_work() onto a torn-down workqueue.
- acrn_irqfd_assign() now installs the eventfd waitqueue entry and publishes the irqfd to vm->irqfds under irqfds_lock, so the irqfd is never visible to deassign/deinit before its waitqueue entry is in place, and any EPOLLHUP that fires in the assign window queues cleanup work that blocks on irqfds_lock until publication is done.
--- drivers/virt/acrn/irqfd.c | 71 ++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 27 deletions(-)
drivers/virt/acrn/irqfd.c +44 -27
@@ -18,6 +18,9 @@static LIST_HEAD (acrn_irqfd_clients); +/* Cleanup work has been queued; set via test_and_set_bit(). */ +#define HSM_IRQFD_FLAG_SHUTDOWN 0 +/** * struct hsm_irqfd - Properties of HSM irqfd * @vm: Associated VM pointer
@@ -27,6 +30,7 @@ static LIST_HEAD(acrn_irqfd_clients);* @list: Entry within &acrn_vm.irqfds of irqfds of a VM * @pt: Structure for select/poll on the associated eventfd * @msi: MSI data +* @flags: Internal lifecycle flags (HSM_IRQFD_FLAG_*) */ struct hsm_irqfd {struct acrn_vm *vm;
@@ -36,6 +40,7 @@ struct hsm_irqfd {struct list_head list;poll_table pt;struct acrn_msi_entry msi; +unsigned long flags; };static void acrn_irqfd_inject (struct hsm_irqfd *irqfd)
@@ -46,30 +51,29 @@ static void acrn_irqfd_inject(struct hsm_irqfd *irqfd) irqfd->msi.msi_data); } -static void hsm_irqfd_shutdown (struct hsm_irqfd *irqfd) +/* Queue the cleanup work at most once. Safe from atomic context. */ +static void hsm_irqfd_queue_shutdown (struct hsm_irqfd *irqfd) { -u64 cnt; - -lockdep_assert_held (&irqfd->vm->irqfds_lock); - -/* remove from wait queue */ -list_del_init (&irqfd->list); -eventfd_ctx_remove_wait_queue (irqfd->eventfd, &irqfd->wait, &cnt); -eventfd_ctx_put (irqfd->eventfd); -kfree (irqfd); +if (!test_and_set_bit (HSM_IRQFD_FLAG_SHUTDOWN , &irqfd->flags)) +queue_work (irqfd->vm->irqfd_wq, &irqfd->shutdown); } +/* Sole owner of @irqfd: unhook waitqueue, drop eventfd ref, free. */ static void hsm_irqfd_shutdown_work (struct work_struct *work) { -struct hsm_irqfd *irqfd; -struct acrn_vm *vm; + struct hsm_irqfd *irqfd = container_of(work, struct hsm_irqfd, + shutdown); +struct acrn_vm *vm = irqfd->vm; +u64 cnt; - irqfd = container_of(work, struct hsm_irqfd, shutdown); - vm = irqfd->vm;mutex_lock (&vm->irqfds_lock);if (!list_empty (&irqfd->list)) -hsm_irqfd_shutdown (irqfd); +list_del_init (&irqfd->list);mutex_unlock (&vm->irqfds_lock); + +eventfd_ctx_remove_wait_queue (irqfd->eventfd, &irqfd->wait, &cnt); +eventfd_ctx_put (irqfd->eventfd); +kfree (irqfd); }/* Called with wqh->lock held and interrupts disabled */
@@ -78,17 +82,16 @@ static int hsm_irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode, {unsigned long poll_bits = (unsigned long )key;struct hsm_irqfd *irqfd; -struct acrn_vm *vm; irqfd = container_of(wait, struct hsm_irqfd, wait); - vm = irqfd->vm; +if (poll_bits &POLLIN )/* An event has been signaled, inject an interrupt */ acrn_irqfd_inject (irqfd);if (poll_bits &POLLHUP ) -/* Do shutdown work in thread to hold wqh->lock */ -queue_work (vm->irqfd_wq, &irqfd->shutdown); +/* Defer teardown to the cleanup work; can't sleep here. */ +hsm_irqfd_queue_shutdown (irqfd);return 0 ; }
@@ -145,6 +148,12 @@ static int acrn_irqfd_assign(struct acrn_vm *vm, struct acrn_irqfd *args)init_waitqueue_func_entry (&irqfd->wait, hsm_irqfd_wakeup);init_poll_funcptr (&irqfd->pt, hsm_irqfd_poll_func); +/* +* Hold irqfds_lock across waitqueue install and list_add so the +* irqfd is not visible to deassign/deinit before its waitqueue +* entry is in place, and any racing EPOLLHUP cleanup work blocks +* on irqfds_lock until publication completes. +*/ mutex_lock (&vm->irqfds_lock);list_for_each_entry (tmp, &vm->irqfds, list) {if (irqfd->eventfd != tmp->eventfd)
@@ -153,14 +162,12 @@ static int acrn_irqfd_assign(struct acrn_vm *vm, struct acrn_irqfd *args)mutex_unlock (&vm->irqfds_lock); goto fail; } -list_add_tail (&irqfd->list, &vm->irqfds); -mutex_unlock (&vm->irqfds_lock); -/* Check the pending event in this stage */ events =vfs_poll (f.file, &irqfd->pt); - +list_add_tail (&irqfd->list, &vm->irqfds);if (events &EPOLLIN )acrn_irqfd_inject (irqfd); +mutex_unlock (&vm->irqfds_lock);fdput (f);return 0 ;
@@ -187,13 +194,17 @@ static int acrn_irqfd_deassign(struct acrn_vm *vm,mutex_lock (&vm->irqfds_lock);list_for_each_entry_safe (irqfd, tmp, &vm->irqfds, list) {if (irqfd->eventfd == eventfd) { -hsm_irqfd_shutdown (irqfd); +list_del_init (&irqfd->list); +hsm_irqfd_queue_shutdown (irqfd);break ; } }mutex_unlock (&vm->irqfds_lock);eventfd_ctx_put (eventfd); +/* Wait for cleanup work to finish so the eventfd is fully detached. */ +flush_workqueue (vm->irqfd_wq); +return 0 ; }
@@ -226,9 +237,15 @@ void acrn_irqfd_deinit(struct acrn_vm *vm)struct hsm_irqfd *irqfd, *next;dev_dbg (acrn_dev.this_device,"VM %u irqfd deinit.\n" , vm->vmid); -destroy_workqueue (vm->irqfd_wq); +mutex_lock (&vm->irqfds_lock); -list_for_each_entry_safe (irqfd, next, &vm->irqfds, list) -hsm_irqfd_shutdown (irqfd); +list_for_each_entry_safe (irqfd, next, &vm->irqfds, list) { +list_del_init (&irqfd->list); +hsm_irqfd_queue_shutdown (irqfd); + }mutex_unlock (&vm->irqfds_lock); + +/* Drain all cleanup work before tearing the workqueue down. */ +flush_workqueue (vm->irqfd_wq); +destroy_workqueue (vm->irqfd_wq); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1676/1887 driver core: Avoid warning when removing a device while its supplier is unbinding
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Herve Codina <[email protected]>
[ Upstream commit 36d74f17e03f7e60e1b08fbe16cfad6e69cc3aa9 ]
During driver removal, the following warning can appear:
WARNING: CPU: 1 PID: 139 at drivers/base/core.c:1497 __device_links_no_driver+0xcc/0xfc
...
Call trace:
__device_links_no_driver+0xcc/0xfc (P)
device_links_driver_cleanup+0xa8/0xf0
device_release_driver_internal+0x208/0x23c
device_links_unbind_consumers+0xe0/0x108
device_release_driver_internal+0xec/0x23c
device_links_unbind_consumers+0xe0/0x108
device_release_driver_internal+0xec/0x23c
device_links_unbind_consumers+0xe0/0x108
device_release_driver_internal+0xec/0x23c
driver_detach+0xa0/0x12c
bus_remove_driver+0x6c/0xbc
driver_unregister+0x30/0x60
pci_unregister_driver+0x20/0x9c
lan966x_pci_driver_exit+0x18/0xa90 [lan966x_pci]This warning is triggered when a consumer is removed because the links status of its supplier is not DL_DEV_DRIVER_BOUND and the link flag DL_FLAG_SYNC_STATE_ONLY is not set.
The topology in terms of consumers/suppliers used was the following (consumer ---> supplier):
i2c -----------> OIC ----> PCI device
| ^
| |
+---> pinctrl ---+When the PCI device is removed, the OIC (interrupt controller) has to be removed. In order to remove the OIC, pinctrl and i2c need to be removed and to remove pinctrl, i2c need to be removed. The removal order is:
1) i2c
2) pinctrl
3) OIC
4) PCI device
In details, the removal sequence is the following (with 0000:01:00.0 the PCI device):
driver_detach: call device_release_driver_internal(0000:01:00.0)...
device_links_busy(0000:01:00.0):
links->status = DL_DEV_UNBINDING
device_links_unbind_consumers(0000:01:00.0):
0000:01:00.0--oic link->status = DL_STATE_SUPPLIER_UNBIND
call device_release_driver_internal(oic)...
device_links_busy(oic):
links->status = DL_DEV_UNBINDING
device_links_unbind_consumers(oic):
oic--pinctrl link->status = DL_STATE_SUPPLIER_UNBIND
call device_release_driver_internal(pinctrl)...
device_links_busy(pinctrl):
links->status = DL_DEV_UNBINDING
device_links_unbind_consumers(pinctrl):
pinctrl--i2c link->status = DL_STATE_SUPPLIER_UNBIND
call device_release_driver_internal(i2c)...
device_links_busy(i2c): links->status = DL_DEV_UNBINDING
__device_links_no_driver(i2c)...
pinctrl--i2c link->status is DL_STATE_SUPPLIER_UNBIND
oic--i2c link->status is DL_STATE_ACTIVE
oic--i2c link->supplier->links.status is DL_DEV_UNBINDINGThe warning is triggered by the i2c removal because the OIC (supplier) links status is not DL_DEV_DRIVER_BOUND. Its links status is indeed set to DL_DEV_UNBINDING.
It is perfectly legit to have the links status set to DL_DEV_UNBINDING in that case. Indeed we had started to unbind the OIC which triggered the consumer unbinding and didn't finish yet when the i2c is unbound.
Avoid the warning when the supplier links status is set to DL_DEV_UNBINDING and thus support this removal sequence without any warnings.
--- drivers/base/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/base/core.c +2 -1
@@ -1501,7 +1501,8 @@ static void __device_links_no_driver(struct device *dev)if (link->supplier->links.status ==DL_DEV_DRIVER_BOUND ) {WRITE_ONCE (link->status,DL_STATE_AVAILABLE ); }else { -WARN_ON (!(link->flags &DL_FLAG_SYNC_STATE_ONLY )); +WARN_ON (link->supplier->links.status !=DL_DEV_UNBINDING && + !(link->flags &DL_FLAG_SYNC_STATE_ONLY ));WRITE_ONCE (link->status,DL_STATE_DORMANT ); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1677/1887 tty: serial: 8250: protect against NULL uart->port.dev in register
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stepan Ionichev <[email protected]>
[ Upstream commit 941c9f84c9b6310f7aaa1c8c785dcc634ee33050 ]
serial8250_register_8250_port() conditionally copies uart->port.dev from up->port.dev only when up->port.dev is non-NULL:
if (up->port.dev) {
uart->port.dev = up->port.dev;
...
}So if both the existing uart slot and up have a NULL ->dev, uart->port.dev remains NULL. The very next ACPI companion check then dereferences it unconditionally:
if (!has_acpi_companion(uart->port.dev)) {has_acpi_companion() reads dev->fwnode without a NULL guard (include/linux/acpi.h), so this NULL-derefs the kernel for the remaining no-dev case rather than just skipping the mctrl_gpio_init() initialisation as intended.
smatch flags the inconsistency:
drivers/tty/serial/8250/8250_core.c:767 serial8250_register_8250_port() error: 'uart->port.dev' could be null (see line 719)
Guard the call with a NULL check so register continues to work for callers that legitimately have no parent device (legacy non-OF/non-ACPI registrations).
No functional change for callers that pass a non-NULL ->dev.
--- drivers/tty/serial/8250/8250_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/tty/serial/8250/8250_core.c +1 -1
@@ -1038,7 +1038,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)* Only call mctrl_gpio_init(), if the device has no ACPI * companion device */ -if (!has_acpi_companion (uart->port.dev)) { +if (uart->port.dev && !has_acpi_companion (uart->port.dev)) { gpios =mctrl_gpio_init (&uart->port,0 );if (IS_ERR (gpios)) { ret =PTR_ERR (gpios);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1678/1887 drm/amdgpu: Bound GPIO I2C table entry count from VBIOS
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Candice Li <[email protected]>
[ Upstream commit a99cd231cd924b7160fecb9fb3a94b801522323b ]
Reject undersized tables and cap the derived entry count to AMDGPU_MAX_I2C_BUS so we do not overrun adev->i2c_bus[] or walk an absurd number of entries on corrupt size fields.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 21 ++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +17 -4
@@ -43,6 +43,21 @@ static void amdgpu_atombios_lookup_i2c_gpio_quirks(struct amdgpu_device *adev, } +/* VBIOS-reported table size is unchecked against the image; cap iterations and +* adev->i2c_bus[] indexing to AMDGPU_MAX_I2C_BUS. +*/ +static int amdgpu_atombios_gpio_i2c_num_entries (uint16_t size) +{ +u32 bytes; + +if (size <sizeof (ATOM_COMMON_TABLE_HEADER )) +return 0 ; + + bytes = size -sizeof (ATOM_COMMON_TABLE_HEADER ); +return (int )min_t (u32, bytes /sizeof (ATOM_GPIO_I2C_ASSIGMENT ), +AMDGPU_MAX_I2C_BUS ); +} +static struct amdgpu_i2c_bus_rec amdgpu_atombios_get_bus_rec_for_i2c_gpio (ATOM_GPIO_I2C_ASSIGMENT *gpio) {struct amdgpu_i2c_bus_rec i2c;
@@ -103,8 +118,7 @@ struct amdgpu_i2c_bus_rec amdgpu_atombios_lookup_i2c_gpio(struct amdgpu_device *if (amdgpu_atom_parse_data_header (ctx, index, &size,NULL ,NULL , &data_offset)) { i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); - num_indices = (size -sizeof (ATOM_COMMON_TABLE_HEADER )) / -sizeof (ATOM_GPIO_I2C_ASSIGMENT ); + num_indices =amdgpu_atombios_gpio_i2c_num_entries (size); gpio = &i2c_info->asGPIO_Info[0 ];for (i =0 ; i < num_indices; i++) {
@@ -137,8 +151,7 @@ void amdgpu_atombios_i2c_init(struct amdgpu_device *adev)if (amdgpu_atom_parse_data_header (ctx, index, &size,NULL ,NULL , &data_offset)) { i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); - num_indices = (size -sizeof (ATOM_COMMON_TABLE_HEADER )) / -sizeof (ATOM_GPIO_I2C_ASSIGMENT ); + num_indices =amdgpu_atombios_gpio_i2c_num_entries (size); gpio = &i2c_info->asGPIO_Info[0 ];for (i =0 ; i < num_indices; i++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1679/1887 drm/amdgpu: validate and share PSP fw_pri_buf copies via psp_copy_fw
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Candice Li <[email protected]>
[ Upstream commit d1f9f5839bd785a3a06335a01d53282e80f8e5fa ]
Change psp_copy_fw from void to int: return -ENODEV when drm_dev_enter fails, and -EINVAL when the image size is zero or larger than the 1 MiB PSP private buffer.
Replace open-coded memset/memcpy into fw_pri_buf with psp_copy_fw.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 32 ++++++++++++++++++------ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 2 +- drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 8 ++++-- drivers/gpu/drm/amd/amdgpu/psp_v12_0.c | 8 ++++-- drivers/gpu/drm/amd/amdgpu/psp_v13_0.c | 14 +++++------ drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c | 14 +++++------ drivers/gpu/drm/amd/amdgpu/psp_v3_1.c | 8 ++++-- 7 files changed, 56 insertions(+), 30 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +25 -7
@@ -737,7 +737,11 @@ static int psp_load_toc(struct psp_context *psp,struct psp_gfx_cmd_resp *cmd =acquire_psp_cmd_buf (psp);/* Copy toc to psp firmware private buffer */ -psp_copy_fw (psp, psp->toc.start_addr, psp->toc.size_bytes); + ret =psp_copy_fw (psp, psp->toc.start_addr, psp->toc.size_bytes); +if (ret) { +release_psp_cmd_buf (psp); +return ret; + }psp_prep_load_toc_cmd_buf (cmd, psp->fw_pri_mc_addr, psp->toc.size_bytes);
@@ -958,8 +962,11 @@ static int psp_rl_load(struct amdgpu_device *adev) cmd =acquire_psp_cmd_buf (psp); -memset (psp->fw_pri_buf,0 ,PSP_1_MEG ); -memcpy (psp->fw_pri_buf, psp->rl.start_addr, psp->rl.size_bytes); + ret =psp_copy_fw (psp, psp->rl.start_addr, psp->rl.size_bytes); +if (ret) { +release_psp_cmd_buf (psp); +return ret; + } cmd->cmd_id =GFX_CMD_ID_LOAD_IP_FW ; cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo =lower_32_bits (psp->fw_pri_mc_addr);
@@ -1166,8 +1173,12 @@ int psp_ta_load(struct psp_context *psp, struct ta_context *context) cmd =acquire_psp_cmd_buf (psp); -psp_copy_fw (psp, context->bin_desc.start_addr, - context->bin_desc.size_bytes); + ret =psp_copy_fw (psp, context->bin_desc.start_addr, + context->bin_desc.size_bytes); +if (ret) { +release_psp_cmd_buf (psp); +return ret; + }psp_prep_ta_load_cmd_buf (cmd, psp->fw_pri_mc_addr, context);
@@ -3508,17 +3519,24 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,return count; } -void psp_copy_fw (struct psp_context *psp,uint8_t *start_addr,uint32_t bin_size) +int psp_copy_fw (struct psp_context *psp,uint8_t *start_addr,uint32_t bin_size) {int idx;if (!drm_dev_enter (adev_to_drm (psp->adev), &idx)) -return ; +return -ENODEV ; + +if (!bin_size || bin_size >PSP_1_MEG ) { +dev_err (psp->adev->dev,"PSP firmware is invalid\n" ); +drm_dev_exit (idx); +return -EINVAL ; + }memset (psp->fw_pri_buf,0 ,PSP_1_MEG );memcpy (psp->fw_pri_buf, start_addr, bin_size);drm_dev_exit (idx); +return 0 ; } static DEVICE_ATTR(usbc_pd_fw, 0644,
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +1 -1
@@ -515,7 +515,7 @@ int psp_get_fw_attestation_records_addr(struct psp_context *psp,int psp_load_fw_list (struct psp_context *psp,struct amdgpu_firmware_info **ucode_list,int ucode_count); -void psp_copy_fw (struct psp_context *psp,uint8_t *start_addr,uint32_t bin_size); +int psp_copy_fw (struct psp_context *psp,uint8_t *start_addr,uint32_t bin_size);int is_psp_fw_valid (struct psp_bin_desc bin);
drivers/gpu/drm/amd/amdgpu/psp_v11_0.c +6 -2
@@ -296,7 +296,9 @@ static int psp_v11_0_bootloader_load_component(struct psp_context *psp,return ret;/* Copy PSP System Driver binary to memory */ -psp_copy_fw (psp, bin_desc->start_addr, bin_desc->size_bytes); + ret =psp_copy_fw (psp, bin_desc->start_addr, bin_desc->size_bytes); +if (ret) +return ret;/* Provide the sys driver to bootloader */ WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
@@ -342,7 +344,9 @@ static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)return ret;/* Copy Secure OS binary to PSP memory */ -psp_copy_fw (psp, psp->sos.start_addr, psp->sos.size_bytes); + ret =psp_copy_fw (psp, psp->sos.start_addr, psp->sos.size_bytes); +if (ret) +return ret;/* Provide the PSP secure OS to bootloader */ WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
drivers/gpu/drm/amd/amdgpu/psp_v12_0.c +6 -2
@@ -148,7 +148,9 @@ static int psp_v12_0_bootloader_load_sysdrv(struct psp_context *psp)return ret;/* Copy PSP System Driver binary to memory */ -psp_copy_fw (psp, psp->sys.start_addr, psp->sys.size_bytes); + ret =psp_copy_fw (psp, psp->sys.start_addr, psp->sys.size_bytes); +if (ret) +return ret;/* Provide the sys driver to bootloader */ WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
@@ -187,7 +189,9 @@ static int psp_v12_0_bootloader_load_sos(struct psp_context *psp)return ret;/* Copy Secure OS binary to PSP memory */ -psp_copy_fw (psp, psp->sos.start_addr, psp->sos.size_bytes); + ret =psp_copy_fw (psp, psp->sos.start_addr, psp->sos.size_bytes); +if (ret) +return ret;/* Provide the PSP secure OS to bootloader */ WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +6 -8
@@ -182,10 +182,9 @@ static int psp_v13_0_bootloader_load_component(struct psp_context *psp,if (ret)return ret; -memset (psp->fw_pri_buf,0 ,PSP_1_MEG ); - -/* Copy PSP KDB binary to memory */ -memcpy (psp->fw_pri_buf, bin_desc->start_addr, bin_desc->size_bytes); + ret =psp_copy_fw (psp, bin_desc->start_addr, bin_desc->size_bytes); +if (ret) +return ret;/* Provide the PSP KDB to bootloader */ WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_36,
@@ -251,10 +250,9 @@ static int psp_v13_0_bootloader_load_sos(struct psp_context *psp)if (ret)return ret; -memset (psp->fw_pri_buf,0 ,PSP_1_MEG ); - -/* Copy Secure OS binary to PSP memory */ -memcpy (psp->fw_pri_buf, psp->sos.start_addr, psp->sos.size_bytes); + ret =psp_copy_fw (psp, psp->sos.start_addr, psp->sos.size_bytes); +if (ret) +return ret;/* Provide the PSP secure OS to bootloader */ WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_36,
drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c +6 -8
@@ -115,10 +115,9 @@ static int psp_v13_0_4_bootloader_load_component(struct psp_context *psp,if (ret)return ret; -memset (psp->fw_pri_buf,0 ,PSP_1_MEG ); - -/* Copy PSP KDB binary to memory */ -memcpy (psp->fw_pri_buf, bin_desc->start_addr, bin_desc->size_bytes); + ret =psp_copy_fw (psp, bin_desc->start_addr, bin_desc->size_bytes); +if (ret) +return ret;/* Provide the PSP KDB to bootloader */ WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_36,
@@ -178,10 +177,9 @@ static int psp_v13_0_4_bootloader_load_sos(struct psp_context *psp)if (ret)return ret; -memset (psp->fw_pri_buf,0 ,PSP_1_MEG ); - -/* Copy Secure OS binary to PSP memory */ -memcpy (psp->fw_pri_buf, psp->sos.start_addr, psp->sos.size_bytes); + ret =psp_copy_fw (psp, psp->sos.start_addr, psp->sos.size_bytes); +if (ret) +return ret;/* Provide the PSP secure OS to bootloader */ WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_36,
drivers/gpu/drm/amd/amdgpu/psp_v3_1.c +6 -2
@@ -104,7 +104,9 @@ static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp)return ret;/* Copy PSP System Driver binary to memory */ -psp_copy_fw (psp, psp->sys.start_addr, psp->sys.size_bytes); + ret =psp_copy_fw (psp, psp->sys.start_addr, psp->sys.size_bytes); +if (ret) +return ret;/* Provide the sys driver to bootloader */ WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
@@ -143,7 +145,9 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)return ret;/* Copy Secure OS binary to PSP memory */ -psp_copy_fw (psp, psp->sos.start_addr, psp->sos.size_bytes); + ret =psp_copy_fw (psp, psp->sos.start_addr, psp->sos.size_bytes); +if (ret) +return ret;/* Provide the PSP secure OS to bootloader */ WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1680/1887 wifi: rtw89: phy: check length before parsing PHY status IE
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ping-Ke Shih <[email protected]>
[ Upstream commit 884495c39de1a02f42bd40051b921e2311d6ac91 ]
Hardware might report PHY status IE with unexpected length, and parser might access out of range. Check the length ahead.
--- drivers/net/wireless/realtek/rtw89/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/wireless/realtek/rtw89/core.c +6 -2
@@ -1258,14 +1258,18 @@ static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev, pos = (u8 *)phy_ppdu->buf +PHY_STS_HDR_LEN ; end = (u8 *)phy_ppdu->buf + phy_ppdu->len;while (pos < end) { - ie_len =rtw89_core_get_phy_status_ie_len (rtwdev, pos); -rtw89_core_process_phy_status_ie (rtwdev, pos, phy_ppdu); +u8 *iehdr = pos; + + ie_len =rtw89_core_get_phy_status_ie_len (rtwdev, iehdr); pos += ie_len;if (pos > end || ie_len ==0 ) {rtw89_debug (rtwdev,RTW89_DBG_TXRX ,"phy status parse failed\n" ); +return -EINVAL ; } + +rtw89_core_process_phy_status_ie (rtwdev, iehdr, phy_ppdu); }return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1681/1887 pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen-Yu Tsai <[email protected]>
[ Upstream commit c87c9046c4e00d599454e033a477176c4d73ac2a ]
pinctrl_gpio_direction_input() / pinctrl_gpio_direction_output() take the pinctrl mutex. This causes a gpiochip operations to need to sleep. Worse yet, the .can_sleep field in the gpiochip is not set. This causes the shared GPIO proxy to trip over, as it uses gpiod_cansleep() to check whether it can use a spinlock or needs a mutex. In this case, it ends up taking a spinlock, then calls pinctrl_gpio_direction_output(), which takes a mutex. This causes a huge warning.
While this class of Mediatek hardware does not have separate clear/set registers, the pinctrl context has a spinlock that is taken whenever a register read-modify-write is done. Also, once the GPIO function is selected / muxed in, further GPIO operations do not involve pinctrl operations or state. The GPIO direction and level values do not require toggling the pinmux or any other pin config options.
Switch to directly calling mtk_pinmux_gpio_set_direction() in the GPIO set direction callbacks to avoid taking the pinctrl mutex. Drop the .gpio_set_direction field in mtk_pmxops to signal we are no longer using the pinctrl GPIO layer for setting the direction.
--- drivers/pinctrl/mediatek/pinctrl-paris.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/pinctrl/mediatek/pinctrl-paris.c +2 -3
@@ -770,7 +770,6 @@ static const struct pinmux_ops mtk_pmxops = { .get_function_name = mtk_pmx_get_func_name, .get_function_groups = mtk_pmx_get_func_groups, .set_mux = mtk_pmx_set_mux, - .gpio_set_direction = mtk_pinmux_gpio_set_direction, .gpio_request_enable = mtk_pinmux_gpio_request_enable, };
@@ -899,7 +898,7 @@ static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)if (gpio >= hw->soc->npins)return -EINVAL ; -return pinctrl_gpio_direction_input (chip, gpio); +return mtk_pinmux_gpio_set_direction (hw->pctrl,NULL , gpio, true); } static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
@@ -912,7 +911,7 @@ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,mtk_gpio_set (chip, gpio, value); -return pinctrl_gpio_direction_output (chip, gpio); +return mtk_pinmux_gpio_set_direction (hw->pctrl,NULL , gpio, false); }static int mtk_gpio_to_irq (struct gpio_chip *chip,unsigned int offset)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1682/1887 PCI/sysfs: Demacrofy pci_dev_resource_resize_attr(n) functions
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilpo Järvinen <[email protected]>
[ Upstream commit f6c73999837820f98519bf0146df44e58f20f89c ]
pci_dev_resource_resize_attr(n) macro is invoked for six resources, creating a large footprint function for each resource.
Rework the macro to only create a function that calls a helper function so the compiler can decide if it warrants to inline the function or not.
With x86_64 defconfig, this saves roughly 2.5kB:
$ scripts/bloat-o-meter drivers/pci/pci-sysfs.o{.old,.new}
add/remove: 1/0 grow/shrink: 0/6 up/down: 512/-2934 (-2422)
Function old new delta
__resource_resize_store - 512 +512
resource5_resize_store 503 14 -489
resource4_resize_store 503 14 -489
resource3_resize_store 503 14 -489
resource2_resize_store 503 14 -489
resource1_resize_store 503 14 -489
resource0_resize_store 500 11 -489
Total: Before=13399, After=10977, chg -18.08%(The compiler seemingly chose to still inline __resource_resize_show() which is fine, those functions are not very complex/large.)
Stable-dep-of: 25ec7f57dece ("PCI/sysfs: Add CAP_SYS_ADMIN check to __resource_resize_store()")
--- drivers/pci/pci-sysfs.c | 122 ++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 56 deletions(-)
drivers/pci/pci-sysfs.c +66 -56
@@ -1433,71 +1433,81 @@ static const struct attribute_group pci_dev_reset_attr_group = { .is_visible = pci_dev_reset_attr_is_visible, }; +static ssize_t __resource_resize_show (struct device *dev,int n,char *buf) +{ +struct pci_dev *pdev =to_pci_dev (dev); +ssize_t ret; + +pci_config_pm_runtime_get (pdev); + + ret =sysfs_emit (buf,"%016llx\n" , + (u64 )pci_rebar_get_possible_sizes (pdev, n)); + +pci_config_pm_runtime_put (pdev); + +return ret; +} + +static ssize_t __resource_resize_store (struct device *dev,int n, +const char *buf,size_t count) +{ +struct pci_dev *pdev =to_pci_dev (dev); +unsigned long size; +int ret; +u16 cmd; + +if (kstrtoul (buf,0 , &size) <0 ) +return -EINVAL ; + +device_lock (dev); +if (dev->driver) { + ret = -EBUSY ; + goto unlock; + } + +pci_config_pm_runtime_get (pdev); + +if ((pdev->class >>8 ) ==PCI_CLASS_DISPLAY_VGA ) { + ret =aperture_remove_conflicting_pci_devices (pdev, +"resourceN_resize" ); +if (ret) + goto pm_put; + } + +pci_read_config_word (pdev,PCI_COMMAND , &cmd); +pci_write_config_word (pdev,PCI_COMMAND , + cmd & ~PCI_COMMAND_MEMORY ); + +pci_remove_resource_files (pdev); + + ret =pci_resize_resource (pdev, n, size,0 ); + +pci_assign_unassigned_bus_resources (pdev->bus); + +if (pci_create_resource_files (pdev)) +pci_warn (pdev,"Failed to recreate resource files after BAR resizing\n" ); + +pci_write_config_word (pdev,PCI_COMMAND , cmd); +pm_put: +pci_config_pm_runtime_put (pdev); +unlock: +device_unlock (dev); + +return ret ? ret : count; +} +#define pci_dev_resource_resize_attr (n) \ static ssize_t resource##n##_resize_show(struct device *dev, \ struct device_attribute *attr, \ - char * buf) \ + char *buf) \ { \ - struct pci_dev *pdev = to_pci_dev(dev); \ - ssize_t ret; \ - \ - pci_config_pm_runtime_get(pdev); \ - \ - ret = sysfs_emit(buf, "%016llx\n", \ - (u64)pci_rebar_get_possible_sizes(pdev, n)); \ - \ - pci_config_pm_runtime_put(pdev); \ - \ - return ret; \ + return __resource_resize_show(dev, n, buf); \ } \ - \ static ssize_t resource##n##_resize_store(struct device *dev, \ struct device_attribute *attr,\ const char *buf, size_t count)\ { \ - struct pci_dev *pdev = to_pci_dev(dev); \ - unsigned long size; \ - int ret; \ - u16 cmd; \ - \ - if (kstrtoul(buf, 0, &size) < 0) \ - return -EINVAL; \ - \ - device_lock(dev); \ - if (dev->driver) { \ - ret = -EBUSY; \ - goto unlock; \ - } \ - \ - pci_config_pm_runtime_get(pdev); \ - \ - if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { \ - ret = aperture_remove_conflicting_pci_devices(pdev, \ - "resourceN_resize"); \ - if (ret) \ - goto pm_put; \ - } \ - \ - pci_read_config_word(pdev, PCI_COMMAND, &cmd); \ - pci_write_config_word(pdev, PCI_COMMAND, \ - cmd & ~PCI_COMMAND_MEMORY); \ - \ - pci_remove_resource_files(pdev); \ - \ - ret = pci_resize_resource(pdev, n, size, 0); \ - \ - pci_assign_unassigned_bus_resources(pdev->bus); \ - \ - if (pci_create_resource_files(pdev)) \ - pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n");\ - \ - pci_write_config_word(pdev, PCI_COMMAND, cmd); \ -pm_put: \ - pci_config_pm_runtime_put(pdev); \ -unlock: \ - device_unlock(dev); \ - \ - return ret ? ret : count; \ + return __resource_resize_store(dev, n, buf, count); \ } \ static DEVICE_ATTR_RW(resource##n##_resize)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1683/1887 PCI/sysfs: Add CAP_SYS_ADMIN check to __resource_resize_store()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Wilczyński <[email protected]>
[ Upstream commit 25ec7f57deceec633f27bc93b615f951e2ade814 ]
Currently, the __resource_resize_store() allows writing to the resourceN_resize sysfs attribute to change a BAR's size without checking for capabilities, currently relying only on the file access check.
Resizing a BAR modifies PCI device configuration and can disrupt active drivers. After the upcoming conversion to static attributes, it will also trigger resource file updates via sysfs_update_groups().
Add a CAP_SYS_ADMIN check to prevent unprivileged users from performing BAR resize operations.
--- drivers/pci/pci-sysfs.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/pci/pci-sysfs.c +3 -0
@@ -1456,6 +1456,9 @@ static ssize_t __resource_resize_store(struct device *dev, int n,int ret;u16 cmd; +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; +if (kstrtoul (buf,0 , &size) <0 )return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1684/1887 spi: spi-qcom-qspi: Support pinctrl sleep states
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Douglas Anderson <[email protected]>
[ Upstream commit 0098c52745112c4387942a37559ababeaf072f0c ]
It's fairly common practice for drivers to switch to a "sleep" pinctrl state at the end of its runtime_suspend function and then back to "default" at the beginning of runtime_resume. Let's do that for spi-qcom-qspi.
Stable-dep-of: d283d5d4d9f6 ("spi: spi-qcom-qspi: Fix incomplete error handling in runtime PM")
--- drivers/spi/spi-qcom-qspi.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/spi/spi-qcom-qspi.c +5 -0
@@ -8,6 +8,7 @@#include <linux/module.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> #include <linux/pm_opp.h> #include <linux/spi/spi.h>
@@ -581,6 +582,8 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)return ret; } +pinctrl_pm_select_sleep_state (dev); +return 0 ; }
@@ -590,6 +593,8 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)struct qcom_qspi *ctrl =spi_master_get_devdata (master);int ret; +pinctrl_pm_select_default_state (dev); + ret =icc_enable (ctrl->icc_path_cpu_to_qspi);if (ret) { dev_err_ratelimited(ctrl->dev, "%s: ICC enable failed for cpu: %d\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1685/1887 spi: spi-qcom-qspi: Fix incomplete error handling in runtime PM
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viken Dadhaniya <[email protected]>
[ Upstream commit d283d5d4d9f6d081ddb65e371be26fffeb611c42 ]
The runtime PM functions had incomplete error handling that could leave the system in an inconsistent state. If any operation failed midway through suspend or resume, some resources would be left in the wrong state while others were already changed, leading to potential clock/power imbalances.
Reorder the suspend/resume sequences to avoid brownout risk by ensuring the performance state is set appropriately before clocks are enabled and clocks are disabled before dropping the performance state.
Fix by adding proper error checking for all operations and using goto-based cleanup to ensure all successfully acquired resources are properly released on any error.
--- drivers/spi/spi-qcom-qspi.c | 44 ++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-)
drivers/spi/spi-qcom-qspi.c +36 -8
@@ -571,20 +571,34 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)struct qcom_qspi *ctrl =spi_master_get_devdata (master);int ret; -/* Drop the performance state vote */ -dev_pm_opp_set_rate (dev,0 );clk_bulk_disable_unprepare (QSPI_NUM_CLKS , ctrl->clks); ret =icc_disable (ctrl->icc_path_cpu_to_qspi);if (ret) {dev_err_ratelimited (ctrl->dev,"%s: ICC disable failed for cpu: %d\n" , __func__, ret); -return ret; + goto err_enable_clk; } -pinctrl_pm_select_sleep_state (dev); + ret =pinctrl_pm_select_sleep_state (dev); +if (ret) + goto err_enable_icc; + +/* Drop the performance state vote */ + ret =dev_pm_opp_set_rate (dev,0 ); +if (ret) + goto err_select_default_state;return 0 ; + +err_select_default_state: +pinctrl_pm_select_default_state (dev); +err_enable_icc: +icc_enable (ctrl->icc_path_cpu_to_qspi); +err_enable_clk: +if (clk_bulk_prepare_enable (QSPI_NUM_CLKS , ctrl->clks)) +dev_err_ratelimited (ctrl->dev,"Failed to re-enable clocks\n" ); +return ret; }static int __maybe_unused qcom_qspi_runtime_resume (struct device *dev)
@@ -593,20 +607,34 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)struct qcom_qspi *ctrl =spi_master_get_devdata (master);int ret; -pinctrl_pm_select_default_state (dev); + ret =dev_pm_opp_set_rate (dev, ctrl->last_speed *4 ); +if (ret) +return ret; + + ret =pinctrl_pm_select_default_state (dev); +if (ret) + goto err_opp_set_rate_zero; ret =icc_enable (ctrl->icc_path_cpu_to_qspi);if (ret) {dev_err_ratelimited (ctrl->dev,"%s: ICC enable failed for cpu: %d\n" , __func__, ret); -return ret; + goto err_select_sleep_state; } ret =clk_bulk_prepare_enable (QSPI_NUM_CLKS , ctrl->clks);if (ret) -return ret; + goto err_disable_icc; -return dev_pm_opp_set_rate (dev, ctrl->last_speed *4 ); +return 0 ; + +err_disable_icc: +icc_disable (ctrl->icc_path_cpu_to_qspi); +err_select_sleep_state: +pinctrl_pm_select_sleep_state (dev); +err_opp_set_rate_zero: +dev_pm_opp_set_rate (dev,0 ); +return ret; }static int __maybe_unused qcom_qspi_suspend (struct device *dev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1686/1887 wifi: cfg80211: reject duplicate wiphy cipher suite entries
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
[ Upstream commit 7187d145d9042b037e4f10538f70cf95e380219f ]
Duplicate entries in wiphy->cipher_suites do not describe any additional capability, but cfg80211 currently accepts them and leaves individual consumers to deal with them.
One such consumer is the WEXT compatibility code, which appends a WEP key length for each WEP cipher entry it sees. Repeated WEP entries can therefore overflow the fixed iw_range::encoding_size array returned by SIOCGIWRANGE.
Reject duplicate cipher suite entries in wiphy_register() instead. This keeps the cipher suite invariant in one place and makes malformed wiphy descriptions fail early with -EINVAL, rather than relying on a single cfg80211 user to handle duplicates correctly.
--- net/wireless/core.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
net/wireless/core.c +21 -0
@@ -693,6 +693,24 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)return 0 ; } +static bool wiphy_cipher_suites_valid (const struct wiphy *wiphy) +{ +int i, j; + +if (wiphy->n_cipher_suites && !wiphy->cipher_suites) +return false; + +for (i =0 ; i < wiphy->n_cipher_suites; i++) { +for (j =0 ; j < i; j++) { +if (wiphy->cipher_suites[i] == + wiphy->cipher_suites[j]) +return false; + } + } + +return true; +} +int wiphy_register (struct wiphy *wiphy) {struct cfg80211_registered_device *rdev =wiphy_to_rdev (wiphy);
@@ -824,6 +842,9 @@ int wiphy_register(struct wiphy *wiphy)if (res)return res; +if (!wiphy_cipher_suites_valid (wiphy)) +return -EINVAL ; +/* sanity check supported bands/channels */ for (band =0 ; band <NUM_NL80211_BANDS ; band++) {u16 types =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1687/1887 scsi: qla2xxx: Skip vport under deletion in report ID acquisition
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 23582731afa35031c94fadb71a4f3b4afd094649 ]
qla24xx_report_id_acquisition() format-1 handling walks ha->vp_list under vport_slock, takes a vref_count on the matching vport and calls qla_update_host_map() to register its port id.
A vport teardown via qla24xx_vport_delete() sets VPORT_DELETE, then qla24xx_disable_vp() removes the vport from the host_map btree and zeroes vha->d_id (RESET_AL_PA). The vport is only unlinked from vp_list later, in qla24xx_deallocate_vp_id(), which clears vp_map[idx] (RESET_VP_IDX) but does not touch host_map. In the window in between, report ID acquisition can still find the vport on vp_list and call qla_update_host_map(); with d_id already zeroed it takes the btree_insert32() path and re-inserts the dying vport into host_map. Nothing cleans that entry afterwards, so once scsi_host_put() frees the vha a later host_map lookup dereferences freed memory.
Skip a vport that has VPORT_DELETE set before taking the reference, so it is neither re-registered nor scheduled for DPC re-registration. This mirrors the existing guard in qla2x00_alert_all_vps().
--- drivers/scsi/qla2xxx/qla_mbx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/qla2xxx/qla_mbx.c +2 -0
@@ -4147,6 +4147,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,spin_lock_irqsave (&ha->vport_slock, flags);list_for_each_entry (vp, &ha->vp_list, list) {if (rptid_entry->vp_idx == vp->vp_idx) { +if (test_bit (VPORT_DELETE , &vp->dpc_flags)) +break ; found =1 ;atomic_inc (&vp->vref_count);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1688/1887 f2fs: accurately adjust free_sections during free_segment_range
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daeho Jeong <[email protected]>
[ Upstream commit 8c963d1738fdca400082ff5f9d99e083de4f4e70 ]
In free_segment_range(), MAIN_SECS(sbi) is temporarily reduced by secs to restrict block allocation to the safe remaining main area while valid blocks in the truncated range are evacuated by GC.
However, FREE_I(sbi)->free_sections tracks the total number of free sections across the whole filesystem. If any sections within the truncated range were already free upon entering free_segment_range(), failing to deduct them from free_sections causes the filesystem to overestimate available free sections in the active, reduced main area. This leads to inconsistent free section accounting during GC data migration and can trigger unexpected allocation failures or assertion errors when space is tight.
Fix this by calculating the number of already-free sections in the truncated range, deducting them from free_sections upon entering free_segment_range(), and restoring them on exit.
--- fs/f2fs/gc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
fs/f2fs/gc.c +14 -1
@@ -1995,8 +1995,9 @@ void f2fs_build_gc_manager(struct f2fs_sb_info *sbi)static int free_segment_range (struct f2fs_sb_info *sbi,unsigned int secs,bool gc_only) { -unsigned int segno, next_inuse, start, end; +unsigned int segno, secno, next_inuse, start, end, end_secno;struct cp_control cpc = {CP_RESIZE ,0 ,0 ,0 }; +unsigned int freed_secs =0 ;int gc_mode, gc_type;int err =0 ;int type;
@@ -2005,6 +2006,7 @@ static int free_segment_range(struct f2fs_sb_info *sbi,MAIN_SECS (sbi) -= secs; start =MAIN_SECS (sbi) * sbi->segs_per_sec; end =MAIN_SEGS (sbi) -1 ; + end_secno =GET_SEC_FROM_SEG (sbi, end);mutex_lock (&DIRTY_I (sbi)->seglist_lock);for (gc_mode =0 ; gc_mode <MAX_GC_POLICY ; gc_mode++)
@@ -2016,6 +2018,14 @@ static int free_segment_range(struct f2fs_sb_info *sbi, sbi->next_victim_seg[gc_type] =NULL_SEGNO ;mutex_unlock (&DIRTY_I (sbi)->seglist_lock); +spin_lock (&FREE_I (sbi)->segmap_lock); +for (secno =MAIN_SECS (sbi); secno <= end_secno; secno++) { +if (!test_bit (secno,FREE_I (sbi)->free_secmap)) + freed_secs++; + } +FREE_I (sbi)->free_sections -= freed_secs; +spin_unlock (&FREE_I (sbi)->segmap_lock); +/* Move out cursegs from the target range */ for (type =CURSEG_HOT_DATA ; type <NR_CURSEG_TYPE ; type++)f2fs_allocate_segment_for_resize (sbi, type, start, end);
@@ -2053,6 +2063,9 @@ static int free_segment_range(struct f2fs_sb_info *sbi,f2fs_bug_on (sbi,1 ); } out: +spin_lock (&FREE_I (sbi)->segmap_lock); +FREE_I (sbi)->free_sections += freed_secs; +spin_unlock (&FREE_I (sbi)->segmap_lock);MAIN_SECS (sbi) += secs;return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1689/1887 scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 878613ecb5a36db26859c4fd83daf9283a334fa2 ]
The VP control IOCB selects its target virtual port by setting one bit in vp_idx_map, a fixed 16-byte (128-bit) array in both vp_ctrl_entry_24xx and vp_ctrl_entry_24xx_ext. qla25xx_ctrlvp_iocb() computes map = (vp_index - 1) / 8 and writes vce->vp_idx_map[map] without checking that map stays within the array.
max_npiv_vports is taken from firmware and only sanitized to a MIN_MULTI_ID_FABRIC-aligned boundary, so it can legitimately be 191 or 255, and qla24xx_control_vp() only rejects vp_index >= max_npiv_vports. A vp_index above 128 therefore yields map >= 16 and an out-of-bounds write of up to 16 bytes past vp_idx_map, corrupting the trailing IOCB fields (or the adjacent request-ring slot on the 64-byte layout).
Reject a vp_index that cannot be represented in the IOCB bitmap in qla24xx_control_vp(), and add a defensive ARRAY_SIZE() guard in qla25xx_ctrlvp_iocb() before the write. Adapters that report the usual 63 or 127 NPIV vports are unaffected.
--- drivers/scsi/qla2xxx/qla_iocb.c | 6 ++++++ drivers/scsi/qla2xxx/qla_mid.c | 8 ++++++++ 2 files changed, 14 insertions(+)
drivers/scsi/qla2xxx/qla_iocb.c +6 -0
@@ -3826,6 +3826,12 @@ qla25xx_ctrlvp_iocb(srb_t *sp, struct vp_ctrl_entry_24xx *vce)*/ map = (sp->u.iocb_cmd.u.ctrlvp.vp_index -1 ) /8 ; pos = (sp->u.iocb_cmd.u.ctrlvp.vp_index -1 ) &7 ; +if (map >=ARRAY_SIZE (vce->vp_idx_map)) { +ql_log (ql_log_warn, sp->vha,0x307c , +"ctrlvp: vp_index %u exceeds vp_idx_map capacity\n" , + sp->u.iocb_cmd.u.ctrlvp.vp_index); +return ; + } vce->vp_idx_map[map] |=1 << pos; }
drivers/scsi/qla2xxx/qla_mid.c +8 -0
@@ -971,6 +971,14 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)if (vp_index ==0 || vp_index >= ha->max_npiv_vports)return QLA_PARAMETER_ERROR ; +/* +* The VP_CTRL IOCB selects the target VP through a fixed 128-bit +* (16-byte) vp_idx_map bitmap, so vp_index must fit within it even +* if firmware advertises more NPIV vports. +*/ + if (vp_index > sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8) +return QLA_PARAMETER_ERROR ; +/* ref: INIT */ sp =qla2x00_get_sp (base_vha,NULL ,GFP_KERNEL );if (!sp)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1690/1887 smb: client: avoid using uninitialized SIDs in cifs_posix_to_fattr()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
[ Upstream commit da6e25842431982d5a53cf00d925b98c690f4467 ]
cifs_posix_to_fattr() ignores the return value of posix_info_parse(). When a malformed POSIX directory entry is encountered (e.g. invalid SID lengths from an untrusted server), posix_info_parse() returns -1 without populating the 'parsed' struct. The uninitialized stack memory in parsed.owner and parsed.group is then passed to sid_to_id(), which processes the garbage bytes and passes them to request_key() to construct a SID string, potentially leaking kernel stack contents to the userspace idmap daemon.
Fix this by checking the return value and skipping the SID-to-id mapping when parsing fails. The remaining fattr fields (timestamps, mode, etc.) are populated directly from the 'info' pointer so they are unaffected.
--- fs/smb/client/readdir.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
fs/smb/client/readdir.c +11 -3
@@ -234,8 +234,9 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info, struct cifs_sb_info *cifs_sb) {struct smb2_posix_info_parsed parsed; +int rc; -posix_info_parse (info,NULL , &parsed); + rc =posix_info_parse (info,NULL , &parsed);memset (fattr,0 ,sizeof (*fattr)); fattr->cf_uniqueid =le64_to_cpu (info->Inode);
@@ -277,8 +278,15 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,if (reparse_file_needs_reval (fattr)) fattr->cf_flags |=CIFS_FATTR_NEED_REVAL ; -sid_to_id (cifs_sb, &parsed.owner, fattr,SIDOWNER ); -sid_to_id (cifs_sb, &parsed.group, fattr,SIDGROUP ); + fattr->cf_uid = cifs_sb->ctx->linux_uid; + fattr->cf_gid = cifs_sb->ctx->linux_gid; +if (rc <0 ) { +cifs_dbg (VFS ,"%s: failed to parse SIDs: %d\n" , + __func__, rc); + }else { +sid_to_id (cifs_sb, &parsed.owner, fattr,SIDOWNER ); +sid_to_id (cifs_sb, &parsed.group, fattr,SIDGROUP ); + } }static void __dir_info_to_fattr (struct cifs_fattr *fattr,const void *info)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1691/1887 smb: client: fail DACL rewrite when the new DACL exceeds 64K
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjoern Doebel <[email protected]>
[ Upstream commit d05045177a855386bca5e1909e08d06290e6e3b3 ]
replace_sids_and_copy_aces() and set_chmod_dacl() accumulate the size of the DACL they build in a u16. That accumulator can wrap.
validate_dacl() caps num_aces at (dacl_size - sizeof(struct smb_acl)) / 20, i.e. 3276 for a maximally sized DACL, while each rewritten ACE can grow to sizeof(struct smb_ace) (76 bytes) once its SID is replaced with one carrying SID_MAX_SUB_AUTHORITIES sub-authorities. The worst case is therefore sizeof(struct smb_acl) + 3276 * 76 = 248984 bytes, far beyond what a u16 can hold. A wraparound is reached with 863 ACEs.
After the wraparound, ndacl_ptr->size becomes meaningless and the offset will point anywhere in the ACE array. As a result, we will see corruption of the DACL, which then gets sent to the server. This is not an out-of-bounds write as the allocation now covers the worst-case expansion, so writes will always go into the buffer.
Adjust the code to use a u32 internally and return -EOVERFLOW in the overflow case. The operation must be refused, because a DACL can only hold 2^16-1 bytes on the wire and larger DACLs cannot be represented.
set_chmod_dacl() carries the same pattern and is fixed the same way. It only wraps once the source DACL comes within roughly 380 bytes of the 64K ceiling, but the failure mode is identical.
--- fs/smb/client/cifsacl.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-)
fs/smb/client/cifsacl.c +22 -9
@@ -1016,12 +1016,12 @@ unsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace)static void populate_new_aces (char *nacl_base,struct cifs_sid *pownersid,struct cifs_sid *pgrpsid, -__u64 *pnmode,u32 *pnum_aces,u16 *pnsize, +__u64 *pnmode,u32 *pnum_aces,u32 *pnsize,bool modefromsid) {__u64 nmode;u32 num_aces =0 ; -u16 nsize =0 ; +u32 nsize =0 ;__u64 user_mode;__u64 group_mode;__u64 other_mode;
@@ -1118,16 +1118,16 @@ static void populate_new_aces(char *nacl_base, *pnsize = nsize; } -static __u16 replace_sids_and_copy_aces (struct cifs_acl *pdacl,struct cifs_acl *pndacl, +static int replace_sids_and_copy_aces (struct cifs_acl *pdacl,struct cifs_acl *pndacl,struct cifs_sid *pownersid,struct cifs_sid *pgrpsid, -struct cifs_sid *pnownersid,struct cifs_sid *pngrpsid) +struct cifs_sid *pnownersid,struct cifs_sid *pngrpsid,u16 *pnsize) {int i;u16 size =0 ;struct cifs_ace *pntace =NULL ;char *acl_base =NULL ;u32 src_num_aces =0 ; -u16 nsize =0 ; +u32 nsize =0 ;struct cifs_ace *pnntace =NULL ;char *nacl_base =NULL ;u16 ace_size =0 ;
@@ -1153,9 +1153,12 @@ static __u16 replace_sids_and_copy_aces(struct cifs_acl *pdacl, struct cifs_acl size +=le16_to_cpu (pntace->size); nsize += ace_size; +if (nsize >U16_MAX ) +return -EOVERFLOW ; } -return nsize; + *pnsize = nsize; +return 0 ; } static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl,
@@ -1167,7 +1170,7 @@ static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl,struct cifs_ace *pntace =NULL ;char *acl_base =NULL ;u32 src_num_aces =0 ; -u16 nsize =0 ; +u32 nsize =0 ;struct cifs_ace *pnntace =NULL ;char *nacl_base =NULL ;u32 num_aces =0 ;
@@ -1218,6 +1221,8 @@ static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl, nsize +=cifs_copy_ace (pnntace, pntace,NULL ); num_aces++; +if (nsize >U16_MAX ) +return -EOVERFLOW ; next_ace: size +=le16_to_cpu (pntace->size);
@@ -1234,6 +1239,10 @@ static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl, } finalize_dacl: +/* The DACL size field is 16-bit on the wire, see MS-DTYP 2.4.5 */ +if (nsize >U16_MAX ) +return -EOVERFLOW ; + pndacl->num_aces =cpu_to_le32 (num_aces); pndacl->size =cpu_to_le16 (nsize);
@@ -1394,6 +1403,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, rc =set_chmod_dacl (dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr, pnmode, mode_from_sid); +if (rc) +return rc; sidsoffset = ndacloffset +le16_to_cpu (ndacl_ptr->size);/* copy the non-dacl portion of secdesc */
@@ -1469,9 +1480,11 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,if (dacloffset) {/* Replace ACEs for old owner with new one */ - size =replace_sids_and_copy_aces (dacl_ptr, ndacl_ptr, + rc =replace_sids_and_copy_aces (dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr, - nowner_sid_ptr, ngroup_sid_ptr); + nowner_sid_ptr, ngroup_sid_ptr, &size); +if (rc) + goto chown_chgrp_exit; ndacl_ptr->size =cpu_to_le16 (size); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1692/1887 smb: client: honor forceuid/forcegid when mapping SIDs to uid/gid
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
[ Upstream commit 18a72975e9f35aadecc75b031f693f2d1f49308f ]
When the administrator mounts with forceuid or forcegid (uid=/gid= mount options), they expect all files to appear owned by the specified user/group. However, several code paths unconditionally called sid_to_id() to overwrite cf_uid/cf_gid with server-provided values, ignoring the administrator's explicit override:
- smb311_posix_info_to_fattr() (stat via POSIX extensions)
- cifs_posix_to_fattr() (readdir via POSIX extensions)
- parse_sec_desc() (CIFS ACL ownership mapping)
This allowed an untrusted server to dictate local file ownership even when the mount was configured to force specific uid/gid values.
Fix all three call sites to check CIFS_MOUNT_OVERR_UID and CIFS_MOUNT_OVERR_GID before calling sid_to_id(), following the same pattern already used by cifs_unix_basic_to_fattr() for unix extensions.
--- fs/smb/client/cifsacl.c | 28 ++++++++++++++++++---------- fs/smb/client/readdir.c | 7 +++++-- 2 files changed, 23 insertions(+), 12 deletions(-)
fs/smb/client/cifsacl.c +18 -10
@@ -1300,6 +1300,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, {int rc =0 ;struct cifs_sid *owner_sid_ptr, *group_sid_ptr; +unsigned int sbflags = cifs_sb->mnt_cifs_flags;struct cifs_acl *dacl_ptr;/* no need for SACL ptr */ char *end_of_acl = ((char *)pntsd) + acl_len;__u32 dacloffset;
@@ -1316,17 +1317,22 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, pntsd->revision, pntsd->type,le32_to_cpu (pntsd->osidoffset),le32_to_cpu (pntsd->gsidoffset), le32_to_cpu(pntsd->sacloffset), dacloffset); + fattr->cf_uid = cifs_sb->ctx->linux_uid; + fattr->cf_gid = cifs_sb->ctx->linux_gid; +/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ rc =parse_sid (owner_sid_ptr, end_of_acl);if (rc) {cifs_dbg (FYI ,"%s: Error %d parsing Owner SID\n" , __func__, rc);return rc; } - rc =sid_to_id (cifs_sb, owner_sid_ptr, fattr,SIDOWNER ); -if (rc) { -cifs_dbg (FYI ,"%s: Error %d mapping Owner SID to uid\n" , - __func__, rc); -return rc; +if (!(sbflags &CIFS_MOUNT_OVERR_UID )) { + rc =sid_to_id (cifs_sb, owner_sid_ptr, fattr,SIDOWNER ); +if (rc) { +cifs_dbg (FYI ,"%s: Error %d mapping Owner SID to uid\n" , + __func__, rc); +return rc; + } } rc =parse_sid (group_sid_ptr, end_of_acl);
@@ -1335,11 +1341,13 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, __func__, rc);return rc; } - rc =sid_to_id (cifs_sb, group_sid_ptr, fattr,SIDGROUP ); -if (rc) { -cifs_dbg (FYI ,"%s: Error %d mapping Group SID to gid\n" , - __func__, rc); -return rc; +if (!(sbflags &CIFS_MOUNT_OVERR_GID )) { + rc =sid_to_id (cifs_sb, group_sid_ptr, fattr,SIDGROUP ); +if (rc) { +cifs_dbg (FYI ,"%s: Error %d mapping Group SID to gid\n" , + __func__, rc); +return rc; + } }if (dacloffset) {
fs/smb/client/readdir.c +5 -2
@@ -233,6 +233,7 @@ static void cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info, struct cifs_sb_info *cifs_sb) { + unsigned int sbflags = cifs_sb->mnt_cifs_flags;struct smb2_posix_info_parsed parsed;int rc;
@@ -284,8 +285,10 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,cifs_dbg (VFS ,"%s: failed to parse SIDs: %d\n" , __func__, rc); }else { -sid_to_id (cifs_sb, &parsed.owner, fattr,SIDOWNER ); -sid_to_id (cifs_sb, &parsed.group, fattr,SIDGROUP ); +if (!(sbflags &CIFS_MOUNT_OVERR_UID )) +sid_to_id (cifs_sb, &parsed.owner, fattr,SIDOWNER ); +if (!(sbflags &CIFS_MOUNT_OVERR_GID )) +sid_to_id (cifs_sb, &parsed.group, fattr,SIDGROUP ); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1693/1887 mptcp: pm: kernel: drop pending ADD_ADDR when removing ID0
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kalpan Jani <[email protected]>
[ Upstream commit 2ac7d6e620764f1fc79eb4edd3610a7a661981ca ]
The in-kernel MPTCP path manager can leave a stale ADD_ADDR announcement entry alive when removing the id 0 endpoint. This happens because the id 0 removal path does not tear down pending announcements, unlike the non-zero id path.
When the PM later reselects id 0 after adding another signal endpoint, it finds the stale anno_list entry and hits WARN_ON_ONCE(mptcp_pm_is_kernel()) in mptcp_pm_announced_alloc().
Root cause: asymmetry between removal paths.
- Non-zero id path: mptcp_nl_remove_subflow_and_signal_addr() calls mptcp_pm_remove_announced() to clean up.
- Id 0 path: mptcp_nl_remove_id_zero_address() skips cleanup entirely.
Fix by making the id 0 path symmetric: call mptcp_pm_announced_remove() and decrement add_addr_signaled before queuing the RM_ADDR.
Subtle detail: signal endpoints are stored in anno_list with port 0, but msk_local carries the connection's local port. In other words, entries linked to ID0 paths should have port == 0. A follow-up patch will ensure that. mptcp_pm_announced_remove() uses use_port=true for comparison. So clear the port before the lookup.
--- net/mptcp/pm_netlink.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/mptcp/pm_netlink.c +8 -0
@@ -1721,6 +1721,8 @@ static int mptcp_nl_remove_id_zero_address(struct net *net,while ((msk =mptcp_token_iter_next (net, &s_slot, &s_num)) !=NULL ) {struct sock *sk = (struct sock *)msk;struct mptcp_addr_info msk_local; +struct mptcp_addr_info anno_addr; +bool announced;if (list_empty (&msk->conn_list) ||mptcp_pm_is_userspace (msk)) goto next;
@@ -1730,7 +1732,13 @@ static int mptcp_nl_remove_id_zero_address(struct net *net, goto next;lock_sock (sk); +/* Drop a possibly pending ADD_ADDR for this address. */ + anno_addr = msk_local; + anno_addr.port =0 ; + announced =remove_anno_list_by_saddr (msk, &anno_addr);spin_lock_bh (&msk->pm.lock); +if (announced) + msk->pm.add_addr_signaled--;mptcp_pm_remove_addr (msk, &list);mptcp_pm_nl_rm_subflow_received (msk, &list);__mark_subflow_endp_available (msk,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1694/1887 perf: RISC-V: store available counter mask as bitmap
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xixin Liu <[email protected]>
[ Upstream commit 6809da6e9c08ccc9a09cb0a48c61471679274aaa ]
The available-counter mask was a single unsigned long, but iteration uses RISCV_MAX_COUNTERS, which is 64. On RV32 that reads past the object. Filling with an unsigned-long bit at index 32 and above is also wrong.
Use DECLARE_BITMAP and set_bit/bitmap helpers. Walk each bitmap word into CFG_MATCH when checking events, when allocating an index, and when stopping all counters. Set the counter base to i times BITS_PER_LONG. Share the CFG_MATCH ecall through a small helper so the 32-bit argument split is not duplicated. On qemu-system-riscv32 the probe bitmap has bits above XLEN set, so the first word alone is not enough.
--- drivers/perf/riscv_pmu_legacy.c | 5 ++- drivers/perf/riscv_pmu_sbi.c | 68 ++++++++++++++++++++++++--------- include/linux/perf/riscv_pmu.h | 2 +- 3 files changed, 53 insertions(+), 22 deletions(-)
drivers/perf/riscv_pmu_legacy.c +3 -2
@@ -82,8 +82,9 @@ static void pmu_legacy_init(struct riscv_pmu *pmu) {pr_info ("Legacy PMU implementation is available\n" ); - pmu->cmask =BIT (RISCV_PMU_LEGACY_CYCLE ) | -BIT (RISCV_PMU_LEGACY_INSTRET ); +bitmap_zero (pmu->cmask,RISCV_MAX_COUNTERS ); +set_bit (RISCV_PMU_LEGACY_CYCLE , pmu->cmask); +set_bit (RISCV_PMU_LEGACY_INSTRET , pmu->cmask); pmu->ctr_start = pmu_legacy_ctr_start; pmu->ctr_stop =NULL ; pmu->event_map = pmu_legacy_event_map;
drivers/perf/riscv_pmu_sbi.c +49 -19
135 lines not on this page · raw message
include/linux/perf/riscv_pmu.h +1 -1
@@ -45,7 +45,7 @@ struct riscv_pmu {irqreturn_t (*handle_irq)(int irq_num,void *dev); -unsigned long cmask; +DECLARE_BITMAP (cmask,RISCV_MAX_COUNTERS );u64 (*ctr_read)(struct perf_event *event);int (*ctr_get_idx)(struct perf_event *event);int (*ctr_get_width)(int idx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1695/1887 ipv6: flowlabel: cap duplicate leases per socket
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
[ Upstream commit 8d6cd188508513503805c156165de38e4e4a8615 ]
ipv6_flowlabel_get() allocates an ipv6_fl_socklist entry for every successful GET. The recheck path for a compatible existing flowlabel links another lease without applying any lease admission check. Repeated GET requests for one shareable label can therefore grow a socket's lease list without bound.
Reject a new unprivileged lease once the socket already holds FL_MAX_PER_SOCK leases. Check this on the shared recheck path so reuse of a globally interned label, including the fl_intern() collision path, is covered as well. New-label admission remains under the existing mem_check() policy.
Use capable(CAP_NET_ADMIN) rather than ns_capable(), matching mem_check(). An unprivileged user must not bypass the cap by creating a user namespace and a netns where they have CAP_NET_ADMIN, which would still consume host memory.
Check the capability only when the socket reaches the limit, so successful unprivileged GET requests below the cap do not generate a capability audit. Do the admission check before updating linger and expires so a rejected GET does not refresh the shared label, matching the existing socket-list allocation failure path.
--- net/ipv6/ip6_flowlabel.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
net/ipv6/ip6_flowlabel.c +20 -0
@@ -460,6 +460,22 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,return NULL ; } +static bool fl_sock_at_lease_limit (const struct sock *sk) +{ +const struct ipv6_pinfo *np =inet6_sk (sk); +const struct ipv6_fl_socklist *sfl; +int count =0 ; + +rcu_read_lock_bh (); +for_each_sk_fl_rcu (np, sfl) { +if (++count >=FL_MAX_PER_SOCK ) +break ; + } +rcu_read_unlock_bh (); + +return count >=FL_MAX_PER_SOCK ; +} +static int mem_check (struct sock *sk) {struct ipv6_pinfo *np =inet6_sk (sk);
@@ -670,6 +686,10 @@ static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq, err = -ENOMEM ;if (!sfl1) goto release; + err = -ENOBUFS ; +if (fl_sock_at_lease_limit (sk) && + !capable (CAP_NET_ADMIN )) + goto release;if (fl->linger > fl1->linger) fl1->linger = fl->linger;if ((long )(fl->expires - fl1->expires) >0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1696/1887 ieee802154: hwsim: serialize pib updates to fix double-free
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
[ Upstream commit 979d5b8de8ed4e1f997aef12da5694b99be7b871 ]
hwsim_update_pib() does an unserialized read-swap-free of phy->pib:
pib_old = rtnl_dereference(phy->pib); ... rcu_assign_pointer(phy->pib, pib); kfree_rcu(pib_old, rcu);
It assumes the RTNL is held, but ->set_channel is not always called under it: the mac802154 scan worker changes channels via drv_set_channel() without the RTNL. Such an update can race an RTNL-held one on the same phy; both read the same pib_old and both kfree_rcu() it, double-freeing the object. With SLUB percpu sheaves batching kfree_rcu(), this surfaces as a KASAN invalid-free in rcu_free_sheaf().
struct hwsim_phy has no lock for pib. Add one and make the swap atomic with rcu_replace_pointer() under it, dropping the misleading rtnl_dereference().
--- drivers/net/ieee802154/mac802154_hwsim.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/net/ieee802154/mac802154_hwsim.c +7 -2
@@ -69,6 +69,8 @@ struct hwsim_phy {struct ieee802154_hw *hw;u32 idx; +/* Serializes phy->pib_updates. */ +spinlock_t pib_lock;struct hwsim_pib __rcu *pib;bool suspended;
@@ -100,8 +102,10 @@ static int hwsim_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel) pib->page = page; pib->channel = channel; - pib_old =rtnl_dereference (phy->pib); -rcu_assign_pointer (phy->pib, pib); +spin_lock_bh (&phy->pib_lock); + pib_old =rcu_replace_pointer (phy->pib, pib, +lockdep_is_held (&phy->pib_lock)); +spin_unlock_bh (&phy->pib_lock);kfree_rcu (pib_old, rcu);return 0 ; }
@@ -789,6 +793,7 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev, goto err_pib; } +spin_lock_init (&phy->pib_lock); pib->channel =13 ;rcu_assign_pointer (phy->pib, pib); phy->idx = idx;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1697/1887 netfilter: cttimeout: prevent UAF during module unload
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
[ Upstream commit fec9b1de0d02de8dafa3cc344bcb91cf28660643 ]
nf_ct_set_timeout() protects the timeout hook dereference and policy lookup with rcu_read_lock(). cttimeout_exit(), however, unregisters the per-net operations before it clears the hook.
This allows the following interleaving:
CPU 0 CPU 1
cttimeout_exit() nf_ct_set_timeout()
unregister_pernet_subsys() rcu_read_lock()
kfree(pernet) h = nf_ct_timeout_hook
h->timeout_find_get()
nfct_timeout_pernet()
The hook still points to ctnl_timeout_find_get() when CPU 1 looks up the already freed per-net timeout list. KASAN reported:
BUG: KASAN: slab-use-after-free in ctnl_timeout_find_get Read of size 8 by task poc/90 Call Trace: ctnl_timeout_find_get+0x271/0x2a0 [nfnetlink_cttimeout] nf_ct_set_timeout+0x7b/0x3c0 xt_ct_tg_check+0x724/0xb20 xt_check_target+0x234/0xa90 do_ipt_set_ctl+0x570/0x1270 Allocated by task 89: __kmalloc_noprof+0x16e/0x460 ops_init+0x6d/0x420 register_pernet_operations+0x2f6/0x670 Freed by task 91: kfree+0x131/0x390 ops_undo_list+0x3d4/0x730 unregister_pernet_operations+0x232/0x490 unregister_pernet_subsys+0x1c/0x30 cttimeout_exit+0x52/0x970 [nfnetlink_cttimeout]
Clear the hook and wait for existing readers before unregistering the per-net operations. This blocks new policy lookups and ensures readers that observed the hook finish before the per-net storage is freed.
--- net/netfilter/nfnetlink_cttimeout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/nfnetlink_cttimeout.c +1 -1
@@ -660,9 +660,9 @@ static void __exit cttimeout_exit(void) {nfnetlink_subsys_unregister (&cttimeout_subsys); -unregister_pernet_subsys (&cttimeout_ops);RCU_INIT_POINTER (nf_ct_timeout_hook,NULL );synchronize_net (); +unregister_pernet_subsys (&cttimeout_ops); }module_init (cttimeout_init);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1698/1887 powerpc: Remove initialisation of readpos
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Wilcox (Oracle) <[email protected]>
[ Upstream commit 0f7f544af60a6082cfaa3ed4c8f4ca1a858807ee ]
While powerpc doesn't use the seq_buf readpos, it did explicitly initialise it for no good reason.
--- arch/powerpc/kernel/setup-common.c | 1 - 1 file changed, 1 deletion(-)
arch/powerpc/kernel/setup-common.c +0 -1
@@ -600,7 +600,6 @@ struct seq_buf ppc_hw_desc __initdata = { .buffer = ppc_hw_desc_buf, .size = sizeof(ppc_hw_desc_buf), .len = 0, - .readpos = 0, };static __init void probe_machine (void )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1699/1887 ksmbd: fix heap out-of-bounds write in krb5_authenticate()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilan Dudnik <[email protected]>
commit 23a0be6a84a38ac169eeab49017934e8e27c65f0 upstream.
In krb5_authenticate(), out_len is calculated to determine available headroom in response_buf for the incoming Kerberos AP-REP token. However, when SMB2_SESSION_SETUP is processed as a non-first element of a compounded SMB2 request, the calculation omits work->next_smb2_rsp_hdr_off.
This causes out_len to overstate remaining buffer headroom by the cumulative size of prior responses in the compound chain. Consequently, the length check in ksmbd_krb5_authenticate()
(*out_len <= resp->spnego_blob_len) passes erroneously, allowing memcpy() to write the AP-REP blob past the end of response_buf into adjacent kernel heap memory.
Fix this by subtracting work->next_smb2_rsp_hdr_off when computing out_len, ensuring it accurately reflects physical remaining buffer space.
--- fs/smb/server/smb2pdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/smb/server/smb2pdu.c +1 -1
@@ -1625,7 +1625,7 @@ static int krb5_authenticate(struct ksmb in_len =le16_to_cpu (req->SecurityBufferLength); out_blob = (char *)&rsp->hdr.ProtocolId +le16_to_cpu (rsp->SecurityBufferOffset); - out_len = work->response_sz - + out_len = work->response_sz - work->next_smb2_rsp_hdr_off - (le16_to_cpu (rsp->SecurityBufferOffset) +4 ); retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
Greg Kroah-Hartman
maintainerPATCH 1700/1887 KVM: x86: Use active memslots for the per-vCPU MMIO cache
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinu Kim <[email protected]>
commit b3e6212dea2e4328a841ceb37f377583176dc735 upstream.
KVM tags the per-vCPU MMIO cache with a memslot generation so that a memslot update invalidates cached MMIO information. Both the fill and validation paths use kvm_memslots(), which unconditionally selects address space 0, even when the vCPU is running in SMM and using address space 1.
Commit 56f17dd3fbc4 ("kvm: x86: fix stale mmio cache bug") added the memslot generation to the cache key so that a memslot update could not leave a stale entry valid. When commit 699023e23965 ("KVM: x86: add SMM to the MMU role, support SMRAM address space") added the SMM address space, these helpers were not converted to use the active memslots.
Consequently, an update to the SMM memslots can leave an entry from the old SMM address space apparently valid after the vCPU returns to the normal address space. A guest can then cause an access to valid RAM at the same GFN to be returned to userspace as KVM_EXIT_MMIO.
Completing that exit through the VMM's RAM address space writes the backing page without going through KVM's write-tracking path. If the page backs a nested EPT table, KVM can continue using shadow translations derived from the old contents. The WARN_ON_ONCE() in kvm_mmu_write_protect_fault() catches this invalid cache and memslot combination.
Use the vCPU's active memslots when caching and validating the entry. Memslot generations are unique across address spaces, so the generation also distinguishes the normal and SMM views. This matches the MMIO SPTE cache, which already uses kvm_vcpu_memslots().
On an unpatched current-mainline kernel, a regression test that fills the cache in SMM and updates only the SMM memslots fails the intended RAM write and triggers the kvm_mmu_write_protect_fault() warning. With this change, the same test completes the RAM write without a warning. The x86/smm_test, set_memory_region_test, and memslot_modification_stress_test selftests also pass.
--- arch/x86/kvm/x86.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.h +2 -2
@@ -205,7 +205,7 @@ static inline bool is_noncanonical_addrestatic inline void vcpu_cache_mmio_info (struct kvm_vcpu *vcpu,gva_t gva,gfn_t gfn,unsigned access) { -u64 gen =kvm_memslots (vcpu->kvm)->generation; +u64 gen =kvm_vcpu_memslots (vcpu)->generation;if (unlikely (gen &KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS ))return ;
@@ -222,7 +222,7 @@ static inline void vcpu_cache_mmio_info(static inline bool vcpu_match_mmio_gen (struct kvm_vcpu *vcpu) { -return vcpu->arch.mmio_gen ==kvm_memslots (vcpu->kvm)->generation; +return vcpu->arch.mmio_gen ==kvm_vcpu_memslots (vcpu)->generation; }/*
Greg Kroah-Hartman
maintainerPATCH 1701/1887 mptcp: move the OoO check back into __mptcp_try_fallback()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdul Wasey <[email protected]>
The 6.1.y backport of upstream commit 1bba3f219c5e ("mptcp: do not fallback when OoO is present") put the out-of-order queue check in __mptcp_finish_join() instead of __mptcp_try_fallback().
So the fix itself is missing, as fallback still happens with OoO data queued. Worse, the passive side now refuses every MP_JOIN while its OoO queue is not empty, which is the normal state of a connection already sending data over more than one subflow. The joining subflow is reset, so such a connection can't add a new path, and a path that comes back after an outage can't rejoin while data is in flight.
Move the check to __mptcp_try_fallback(), as upstream does. On this branch that function is in protocol.h.
Tested on 6.1.190 in netns: 6 connections (5 uploading) over two paths, then a third endpoint added mid-transfer. Without this patch only the idle connection gets a subflow on the new path and the other 5 joins are reset. With it, all 6 join. Same result in 3 of 3 runs each.
--- net/mptcp/protocol.c | 7 ------- net/mptcp/protocol.h | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-)
net/mptcp/protocol.c +0 -7
@@ -930,13 +930,6 @@ static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)if (sk->sk_state !=TCP_ESTABLISHED )return false; -/* The caller possibly is not holding the msk socket lock, but -* in the fallback case only the current subflow is touching -* the OoO queue. -*/ -if (!RB_EMPTY_ROOT (&msk->out_of_order_queue)) -return false; -spin_lock_bh (&msk->fallback_lock);if (!msk->allow_subflows) {spin_unlock_bh (&msk->fallback_lock);
net/mptcp/protocol.h +8 -0
@@ -1005,6 +1005,14 @@ static inline bool __mptcp_try_fallback(struct mptcp_sock *msk)pr_debug ("TCP fallback already done (msk=%p)\n" , msk);return true; } + +/* The caller possibly is not holding the msk socket lock, but +* in the fallback case only the current subflow is touching +* the OoO queue. +*/ +if (!RB_EMPTY_ROOT (&msk->out_of_order_queue)) +return false; +spin_lock_bh (&msk->fallback_lock);if (!msk->allow_infinite_fallback) {spin_unlock_bh (&msk->fallback_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1702/1887 power: supply: Fix maintenance charge table kernel-doc
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 45d4af4e80a25881b6b75e8e34872c555c43a41d ]
struct power_supply_maintenance_charge_table contains charge_safety_timer_minutes, but its kernel-doc describes safety_timer_minutes. This leaves the real member undescribed and adds a nonexistent member to the generated documentation.
Use the member's actual name.
--- include/linux/power_supply.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
include/linux/power_supply.h +3 -3
@@ -364,9 +364,9 @@ struct power_supply_vbat_ri_table {* @charge_voltage_max_uv: maintenance charging voltage that is usually a bit * lower than the constant_charge_voltage_max_uv. We can apply this settings * charge_current_max_ua until we get back up to this voltage. -* @safety_timer_minutes: maintenance charging safety timer, with an expiry -* time in minutes. We will only use maintenance charging in this setting -* for a certain amount of time, then we will first move to the next +* @charge_safety_timer_minutes: maintenance charging safety timer, with an +* expiry time in minutes. We will only use maintenance charging in this +* setting for a certain amount of time, then we will first move to the next * maintenance charge current and voltage pair in respective array and wait * for the next safety timer timeout, or, if we reached the last maintencance * charging setting, disable charging until we reach
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1703/1887 power: supply: ds2780: Fix ds2780_get_capacity() returning raw value
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xueqin Luo <[email protected]>
[ Upstream commit a58cbc8b36ec0cd00d2ba3de7d003de818a27523 ]
ds2780_get_capacity() returns the raw register value instead of 0 on success. The capacity is already stored in *capacity, so the function should return 0 to indicate success.
--- drivers/power/supply/ds2780_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/power/supply/ds2780_battery.c +1 -1
@@ -304,7 +304,7 @@ static int ds2780_get_capacity(struct ds2780_device_info *dev_info,return ret; *capacity = raw; -return raw; +return 0 ; }static int ds2780_get_status (struct ds2780_device_info *dev_info,int *status)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1704/1887 Drivers: hv: Avoid infinite retry loop in init_vp_index()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Waiman Long <[email protected]>
[ Upstream commit 32ea0a33e3a0fb7c10c601b43e1b2f6c06a3f5fd ]
There is a retry loop in init_vp_index() where the CPUs from a certain node are stripped out if they have already been in the allocated cpumask or not in HK_TYPE_MANAGED_IRQ housekeeping cpumask. If there is no CPU left, the allocated cpumask is ignored and the process is retried again. However, if the HK_TYPE_MANAGED_IRQ housekeeping cpumask turns out not to contain any CPU in that particular node, that will become an infinite retry loop. This particular problem was reported by sashiko [1]. This should rarely happen, but we still need to guard against this.
Fix this infinite loop problem by also skipping NUMA node that has no housekeeping CPU in the inner while loop of init_vp_index(). Also update the early abort check to check for the absence of online housekeeping CPUs instead of just the emptiness of the cpumask. As the outer for loop will only be reached if the housekeeping cpumask has at least one online CPU, a NUMA node with housekeeping CPUs will eventually be found.
--- drivers/hv/channel_mgmt.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
drivers/hv/channel_mgmt.c +9 -3
@@ -743,13 +743,14 @@ static void init_vp_index(struct vmbus_channel *channel)u32 i, ncpu =num_online_cpus ();cpumask_var_t available_mask;struct cpumask *allocated_mask; +const struct cpumask *node_mask;const struct cpumask *hk_mask =housekeeping_cpumask (HK_TYPE_MANAGED_IRQ );u32 target_cpu;int numa_node;if (!perf_chn || !alloc_cpumask_var (&available_mask,GFP_KERNEL ) || -cpumask_empty (hk_mask)) { + !cpumask_intersects (hk_mask, cpu_online_mask)) {/* * If the channel is not a performance critical * channel, bind it to VMBUS_CONNECT_CPU.
@@ -771,14 +772,19 @@ static void init_vp_index(struct vmbus_channel *channel) next_numa_node_id =0 ;continue ; } -if (cpumask_empty (cpumask_of_node (numa_node))) +/* +* Try next NUMA node if current NUMA node has no CPU +* or doesn't contain any housekeeping CPU. +*/ + node_mask =cpumask_of_node (numa_node); +if (!cpumask_intersects (node_mask, hk_mask))continue ;break ; } allocated_mask = &hv_context.hv_numa_map[numa_node]; retry: -cpumask_xor (available_mask, allocated_mask,cpumask_of_node (numa_node)); +cpumask_xor (available_mask, allocated_mask, node_mask);cpumask_and (available_mask, available_mask, hk_mask);if (cpumask_empty (available_mask)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1705/1887 Drivers: hv: Dont reset VMBus connection state on error/exit paths
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Kelley <[email protected]>
[ Upstream commit ec31dc39e835ccde0930daccece8c492d28282fc ]
In two places, current code forces vmbus_connection.conn_state to DISCONNECTED prior to calling vmbus_disconnect(). But vmbus_disconnect() calls vmbus_initiate_unload(), which unloads the VMBus connection only if the conn_state is CONNECTED. Consequently, the connection remains and the Hyper-V host might continue to send messages or post VMBus interrupts.
The problem was introduced in commit 74347a99e73ae ("x86/Hyper-V:
Unload vmbus channel in hv panic callback"), in that vmbus_initiate_unload() started checking the current connection state before doing the unload. This commit removed some occurrences where conn_state was forced to DISCONNECTED, but these two remained, apparently due to an oversight at the time.
Fix this by not forcing conn_state to DISCONNECTED during VMBus exit, or if a failure occurs when establishing the connection in the first place. Whatever value conn_state has at the time is then read by vmbus_initiate_unload() to determine if there is a connection to be unloaded.
--- drivers/hv/connection.c | 1 - drivers/hv/vmbus_drv.c | 1 - 2 files changed, 2 deletions(-)
drivers/hv/connection.c +0 -1
@@ -322,7 +322,6 @@ int vmbus_connect(void) cleanup:pr_err ("Unable to connect to host\n" ); - vmbus_connection.conn_state =DISCONNECTED ;vmbus_disconnect ();kfree (msginfo);
drivers/hv/vmbus_drv.c +0 -1
@@ -2662,7 +2662,6 @@ static void __exit vmbus_exit(void)hv_remove_kexec_handler ();hv_remove_crash_handler (); - vmbus_connection.conn_state =DISCONNECTED ;hv_stimer_global_cleanup ();vmbus_disconnect ();if (vmbus_irq ==-1 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1706/1887 vsock: treat TCP_CLOSING as once-established
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Luczaj <[email protected]>
[ Upstream commit 4f6ac74fa594a918d41255c941256e1d51592d3b ]
Handle the TCP_ESTABLISHED -> TCP_CLOSING transition on OP_RST, which can race with the connect loop. Immediately break and return 0 on ESTABLISHED/CLOSING. The return value of connect() should reflect what happened up to the point the connection was established or failed. Events that occur afterwards must not affect it. E.g. even if OP_RW has already set sk_err, connect() should still return 0, not ENOBUFS because of it. Adapt the inaccurate comment above signal_pending().
Resetting a socket that is still present in connected_table can lead to memory corruption. The reporter noted lost transports for in-flight skbs, and I have reproduced crashes caused by re-insertion into connected_table.
list_add double add: new=, prev=, next=.
kernel BUG at lib/list_debug.c:35!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI Workqueue: vsock-loopback vsock_loopback_work RIP: 0010:__list_add_valid_or_report+0x11f/0x130 Call Trace: vsock_insert_connected.cold+0xe/0x13 virtio_transport_recv_pkt+0x10e9/0x1460 vsock_loopback_work+0x305/0x480 process_one_work+0xe4c/0x1560 worker_thread+0x4f1/0xd60 kthread+0x36e/0x470 ret_from_fork+0x47b/0x6b0 ret_from_fork_asm+0x1a/0x30
This fix is supplementary to commit 002541ef650b ("vsock: Ignore signal/timeout on connect() if already established"). Details under Link.
--- net/vmw_vsock/af_vsock.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
net/vmw_vsock/af_vsock.c +8 -9
@@ -1502,23 +1502,22 @@ static int vsock_connect(struct socket *sock, struct sockaddr *addr, timeout =schedule_timeout (timeout);lock_sock (sk); -/* Connection established. Whatever happens to socket once we -* release it, that's not connect()'s concern. No need to go +/* Connection was established. Whatever happens to socket once +* we release it, that's not connect()'s concern. No need to go * into signal and timeout handling. Call it a day. * * Note that allowing to "reset" an already established socket * here is racy and insecure. */ -if (sk->sk_state ==TCP_ESTABLISHED ) -break ; +if (sk->sk_state ==TCP_ESTABLISHED || + sk->sk_state ==TCP_CLOSING ) { + err =0 ; + goto out_wait; + }/* If connection was _not_ established and a signal/timeout came * to be, we want the socket's state reset. User space may want -* to retry. -* -* sk_state != TCP_ESTABLISHED implies that socket is not on -* vsock_connected_table. We keep the binding and the transport -* assigned. +* to retry, so we keep the binding and the transport assigned. */ if (signal_pending (current) || timeout ==0 ) { err = timeout ==0 ? -ETIMEDOUT :sock_intr_errno (timeout);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1707/1887 net/rds: dont let the rdma_cm destroy an id RDS still owns on route failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Allison Henderson <[email protected]>
[ Upstream commit 98d446b7c013254a8a7b49720557676a3a851fde ]
rds_rdma_cm_event_handler_cmn() hands the return value of rdma_resolve_route() straight back to the rdma_cm on RDMA_CM_EVENT_ADDR_RESOLVED. A synchronous failure there - -ENOMEM from the route work allocation, an SA query that cannot be set up, a RoCE route with no usable device - makes addr_handler() destroy the id the event was delivered on. That id is ic->i_cm_id, and nothing clears the pointer: the connection sits in RDS_CONN_CONNECTING with a freed id until its shutdown calls rdma_disconnect() and rdma_destroy_id() on it.
The ROUTE_RESOLVED case already avoids this: rds_ib_cm_initiate_connect() forces a zero return while ic->i_cm_id == cm_id, as the comment there explains. Do the same here - drop the connection and return 0 - so the id stays RDS's to destroy from the shutdown, and the reconnect gets a fresh one.
--- net/rds/rdma_transport.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
net/rds/rdma_transport.c +11 -1
@@ -89,9 +89,19 @@ static int rds_rdma_cm_event_handler_cmn(struct rdma_cm_id *cm_id,if (conn) {rdma_set_service_type (cm_id, conn->c_tos);rdma_set_min_rnr_timer (cm_id,IB_RNR_TIMER_000_32 ); -/* XXX do we need to clean up if this fails? */ ret =rdma_resolve_route (cm_id,RDS_RDMA_RESOLVE_TIMEOUT_MS ); +if (ret) { +/* A non-zero return has the rdma_cm destroy +* the id, but it is still ic->i_cm_id, which +* the connection's shutdown would then +* disconnect and destroy again. Drop the +* connection and keep the id for that +* shutdown. +*/ +rds_conn_drop (conn); + ret =0 ; + } }break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1708/1887 ASoC: Intel: avs: Reset the stream unless it is already prepared
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergey Tiraspolsky <[email protected]>
[ Upstream commit f6be9f558a83fe30a03bd3adae461c821a0cef8c ]
Commit cfca1637bc2b ("ASoC: Intel: avs: Unprepare a stream when XRUN occurs") resets the HDA stream when ->prepare() is called in the XRUN state. User space does not always recover that way. PipeWire's ALSA backend recovers from an underrun with snd_pcm_drop(), snd_pcm_prepare() and a new start, so ->prepare() runs in the SETUP state, hdac_stream->prepared is still set and the reset is skipped. Every recovery attempt then fails the same way:
spa.alsa: hw:avsmax98927,1p: snd_pcm_avail after recover: Broken pipe
On a Google Pixelbook (Kaby Lake, max98927 speakers) this happens after an occasional underrun during normal playback and silences the speakers for one to four minutes, until the PCM is closed. It can be provoked by stopping PipeWire with SIGSTOP for 0.5 s during playback: in one run that single underrun led to 1297 failed recoveries over two minutes, until the sink was suspended. A plain alsa-lib program that recovers with snd_pcm_drop() and snd_pcm_prepare() hits the same loop, while snd_pcm_prepare() straight from XRUN recovers at once.
Skip the reset only when the stream is already PREPARED, the repeated ->prepare() case the check exists for, and reset it otherwise. With this change both kinds of recovery succeed with a single restart.
--- sound/soc/intel/avs/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/intel/avs/pcm.c +1 -1
@@ -556,7 +556,7 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so data =snd_soc_dai_get_dma_data (dai, substream); host_stream = data->host_stream; -if (runtime->state ==SNDRV_PCM_STATE_XRUN ) +if (runtime->state !=SNDRV_PCM_STATE_PREPARED )hdac_stream (host_stream)->prepared = false;if (hdac_stream (host_stream)->prepared)return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1709/1887 ASoC: stm32: spdifrx: fix synchronization state check
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Avi Weiss <[email protected]>
[ Upstream commit 0936bbd35a247665c64886135835faa3c3f4f29f ]
The interrupt handler uses a logical AND to check whether SPDIFRX was in the SYNC state before clearing errors. Since both SYNC (1) and ENABLE (3) are nonzero, this also treats ENABLE as SYNC (and any other non-zero value that might be added).
The logical && basically just converts this to check for != 0.
So errors occurring while SPDIFRX is enabled cause the driver to retry synch instead of disconnecting the PCM stream.
Fix is to change the logical && to equality (==) and only retry when exactly in sync state.
--- sound/soc/stm/stm32_spdifrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/stm/stm32_spdifrx.c +1 -1
@@ -728,7 +728,7 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)if (err) {regmap_read (spdifrx->regmap,STM32_SPDIFRX_CR , &cr); - sync_state =FIELD_GET (SPDIFRX_CR_SPDIFEN_MASK , cr) && + sync_state =FIELD_GET (SPDIFRX_CR_SPDIFEN_MASK , cr) ==SPDIFRX_SPDIFEN_SYNC ;/* SPDIFRX is in STATE_STOP. Disable SPDIFRX to clear errors */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1710/1887 ASoC: cs42l56: Put the Limiter Cushion control on the limiter register
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 203436d2aeb7093290459e344e1912a418a6ebfd ]
The Limiter Cushion control writes bits 4:2 of the ALC Thresholds register. Those bits are ALCMIN, which the ALC MIN control owns. The datasheet puts CUSH at bits 4:2 of the Limit Thresholds Control register, next to LMAX, which the Limiter MAX control already uses.
So setting the limiter cushion changes the ALC minimum threshold, and the cushion itself cannot be set.
Use CS42L56_LIM_THRESHOLD_CTL.
--- sound/soc/codecs/cs42l56.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/cs42l56.c +1 -1
@@ -449,7 +449,7 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = { 0, 0x3f, 0, 0),SOC_SINGLE_TLV ("Limiter MAX" ,CS42L56_LIM_THRESHOLD_CTL ,5 ,0x07 ,1 , alc_tlv), -SOC_SINGLE_TLV ("Limiter Cushion" ,CS42L56_ALC_THRESHOLD , +SOC_SINGLE_TLV ("Limiter Cushion" ,CS42L56_LIM_THRESHOLD_CTL ,2 ,0x07 ,1 , alc_tlv), SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1711/1887 ASoC: cs42l52: Fix the NG Type Switch bit
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 8b08b98796d2da103f2432550c14a7c687e72080 ]
The NG Type Switch enum selects between "Apply Specific" and "Apply All", which is the NGALL bit. The datasheet puts NGALL at bit 7 of the Noise Gate Control register. The enum uses bit 6, which is NG, the noise gate enable owned by the NG Enable Switch. cs42l52.h names it CS42L52_NG_ENABLE_SHIFT. cs42l56 has the same Noise Gate register and puts its NG All Switch at bit 7.
So changing the noise gate type turns the noise gate on or off, and NGALL cannot be set.
Use bit 7.
--- sound/soc/codecs/cs42l52.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/cs42l52.c +1 -1
@@ -273,7 +273,7 @@ static const char * const cs42l52_ng_type_text[] = { }; static SOC_ENUM_SINGLE_DECL(ng_type_enum, - CS42L52_NOISE_GATE_CTL, 6, + CS42L52_NOISE_GATE_CTL, 7, cs42l52_ng_type_text);static const char *const left_swap_text[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1712/1887 ASoC: pcm3168a: Fix the DAC zero flag polarity bit
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit b26edc925c1cfa0184cd270ed81d4833db045ce0 ]
The DAC Zero Flag Polarity enum uses PCM3168A_DAC_ATSPDA_SHIFT, which is bit 6 of register 70. That bit is ATSPDA, the attenuation speed, which the DAC Volume Rate Multiplier enum already owns. The datasheet puts ZREV, the zero flag polarity, at bit 0. The header defines PCM3168A_DAC_ZREV_SHIFT for it, but nothing uses it.
So changing the zero flag polarity changes the attenuation speed, and ZREV cannot be set.
Use PCM3168A_DAC_ZREV_SHIFT.
--- sound/soc/codecs/pcm3168a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/pcm3168a.c +1 -1
@@ -104,7 +104,7 @@ static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF,static const char *const pcm3168a_pol[] = {"Active High" ,"Active Low" }; static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF, - PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol); + PCM3168A_DAC_ZREV_SHIFT, pcm3168a_pol);static const char *const pcm3168a_con[] = {"Differential" ,"Single-Ended" };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1713/1887 ASoC: max98371: Fix the Speaker DHT Min Volume bits
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit f7934340c56a84fc1b246ebf6b2e806d775f3b54 ]
Register 0x31 holds two 4-bit fields. The datasheet puts SPK_GAIN_MIN at bits 7:4 and DHT_VROT_PNT at bits 3:0. The Speaker DHT Min Volume and Speaker DHT Rotation Volume controls both use bits 3:0.
So setting the minimum speaker gain changes the DHT rotation point, and SPK_GAIN_MIN cannot be set.
Move Speaker DHT Min Volume to bits 7:4.
--- sound/soc/codecs/max98371.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/max98371.c +1 -1
@@ -166,7 +166,7 @@ static const struct snd_kcontrol_new max98371_snd_controls[] = { 0, (1<<MAX98371_DHT_MAX_WIDTH)-1, 0, max98371_dht_max_gain),SOC_SINGLE_TLV ("Speaker DHT Min Volume" ,MAX98371_DHT_GAIN , -0 , (1 <<MAX98371_DHT_GAIN_WIDTH )-1 ,0 , +4 , (1 <<MAX98371_DHT_GAIN_WIDTH )-1 ,0 , max98371_dht_min_gain), SOC_SINGLE_TLV("Speaker DHT Rotation Volume", MAX98371_DHT_GAIN, 0, (1<<MAX98371_DHT_ROT_WIDTH)-1, 0,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1714/1887 ASoC: wm8978: Fix the 128x oversampling switch bits
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit d0567ca9a2faa33efbe5ae84ef7b86423a93bffd ]
The DAC and ADC 128x Oversampling Switches use bit 5 of R10 and R14. Table 66 of the WM8978 datasheet puts DACOSR128 and ADCOSR128 at bit 3 of those registers.
In R14, bit 5 is inside HPFCUT[6:4], which the High Pass Cut Off control owns. So turning on ADC oversampling changes the high pass cut-off, and the oversampling bit cannot be set. In R10, bit 5 is reserved, so the DAC switch has no effect.
Use bit 3 for both.
--- sound/soc/codecs/wm8978.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/codecs/wm8978.c +2 -2
@@ -255,9 +255,9 @@ static const struct snd_kcontrol_new wm8978_snd_controls[] = {/* DAC / ADC oversampling */ SOC_SINGLE ("DAC 128x Oversampling Switch" ,WM8978_DAC_CONTROL , -5 ,1 ,0 ), +3 ,1 ,0 ),SOC_SINGLE ("ADC 128x Oversampling Switch" ,WM8978_ADC_CONTROL , - 5, 1, 0), + 3, 1, 0), };/* Mixer #1: Output (OUT1, OUT2) Mixer: mix AUX, Input mixer output and DAC */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1715/1887 ASoC: nau8822: Fix the 128x oversampling switch bits
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 4db45fc1da3d62d0fa6e8f1e457ae92e8741ed07 ]
The DAC and ADC 128x Oversampling Switches use bit 5 of R10 and R14. The NAU8822 datasheet register map puts DACOS and ADCOS at bit 3 of those registers.
In R14, bit 5 is inside HPF[6:4], which the High Pass Cut Off control owns. So turning on ADC oversampling changes the high pass cut-off, and the oversampling bit cannot be set. In R10, bit 5 is reserved, so the DAC switch has no effect.
Use bit 3 for both.
--- sound/soc/codecs/nau8822.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/codecs/nau8822.c +2 -2
@@ -379,9 +379,9 @@ static const struct snd_kcontrol_new nau8822_snd_controls[] = { NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 0, 7, 0, boost_tlv), SOC_SINGLE("DAC 128x Oversampling Switch", - NAU8822_REG_DAC_CONTROL, 5, 1, 0), + NAU8822_REG_DAC_CONTROL, 3, 1, 0), SOC_SINGLE("ADC 128x Oversampling Switch", - NAU8822_REG_ADC_CONTROL, 5, 1, 0), + NAU8822_REG_ADC_CONTROL, 3, 1, 0), };/* LMAIN and RMAIN Mixer */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1716/1887 spi: tegra114: assert CS GPIO for every transfer in a message
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos Jones Jr <[email protected]>
[ Upstream commit 8980bc573ae2d2b9d86d76aeb86c76e1597070bf ]
The driver provides its own transfer_one_message() and therefore drives the chip-select GPIO itself rather than through the SPI core. The GPIO is asserted only in the is_first_of_msg path of tegra_spi_setup_transfer_one(), but tegra_spi_transfer_end() deasserts it whenever a transfer has cs_change set. For a multi-transfer message whose earlier transfers request cs_change -- for example a register read that sends the address in one transfer and clocks the data back in the next -- the CS GPIO is released after the first transfer and never re-asserted, so the remaining transfers are clocked with chip-select inactive and the peripheral never drives the bus.
This was observed with an ADIS16470 IMU (adis16475 driver), whose register read is a two-transfer, cs_change-framed exchange: a logic analyzer showed the data frame clocked with CS high, and the driver read 0 while the device drove 0x4056 on the wire.
Re-assert the CS GPIO for every transfer so that multi-transfer messages keep chip-select active across the whole message. gpiod_set_value() is idempotent and polarity-aware, so this is a no-op for the first transfer and for messages that keep CS asserted throughout.
--- drivers/spi/spi-tegra114.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/spi/spi-tegra114.c +7 -0
@@ -860,6 +860,13 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, command1 |=SPI_BIT_LENGTH (bits_per_word -1 ); } +/* +* Re-assert the CS GPIO for every transfer: transfer_end() drops it +* on cs_change, and the assert above only covers is_first_of_msg. +*/ +if (spi_get_csgpiod (spi,0 )) +gpiod_set_value (spi_get_csgpiod (spi,0 ),1 ); +return command1; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1717/1887 nios2: fix __wsum type degradation in csum_fold()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keith Busch <[email protected]>
[ Upstream commit b963f2345fa20417401c51a69dedb6a58eea33a9 ]
csum_fold() shifts a bitwise __wsum type, which sparse reports as "restricted __wsum degrades to integer". Sparse only checks the body of a static inline once something instantiates it, so this went unnoticed until a recent block layer change added the first csum_fold() caller to a file built on this architecture.
Force cast to a __u32 for the shift, as the other architectures do.
--- arch/nios2/include/asm/checksum.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/nios2/include/asm/checksum.h +1 -1
@@ -27,7 +27,7 @@ static inline __sum16 csum_fold(__wsum sum) "add %0, %0, r8\n" "nor %0, %0, %0\n" : "=r" (sum) - : "r" (sum << 16), "0" (sum) + : "r" ((__force u32)sum << 16), "0" (sum) : "r8");return (__force __sum16 ) sum; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1718/1887 scsi: st: Save the visited block for the partition the drive is in
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laurence Oberman <[email protected]>
[ Upstream commit c9e9f024dd4f61f0f6636c9f2ed0830f87060e11 ]
set_location() saves the current tape location before switching partitions, so that switch_partition() can return to it later. It reads the location with READ POSITION but stores it in the st_partstat of STp->partition, ignoring the partition the drive reports.
The two differ after a device reset. When the reset is recovered with MTREW, MTSEEK or MTEOM, st_ioctl() sets STp->partition = 0 and calls switch_partition() to return to STp->new_partition. A drive that was in partition 1 is still there, so set_location() files the partition 1 position under partition 0. The next switch to partition 0 locates to that block: if partition 0 holds less data, MTSETPART fails with EIO (BLANK CHECK), otherwise the tape is silently positioned at the wrong block.
IBM ULTRIUM-TD5 (LTO-5), LU reset in partition 1 at block 1025:
st 12:0:0:0: [st0] Visited block 1025 for partition 0 saved.
...
st 12:0:0:0: [st0] Setting block to 1025 and partition to 0. st 12:0:0:0: [st0] Error: 402, cmd: 2b 2 0 0 0 4 st 12:0:0:0: [st0] Sense Key : Blank Check [current] st 12:0:0:0: [st0] Add. Sense: End-of-data detected
Store the location in the st_partstat of the partition reported by READ POSITION. With the fix:
st 12:0:0:0: [st0] Visited block 1025 for partition 1 saved.
This is a pre-existing issue. It was not caught when testing the recent st reset series because the partition test was only run on scsi_debug:
on the LTO drive it was skipped, since can-partitions is off in the test harness's stinit.conf, as is normal for LTO. scsi_debug hides the problem because its emulated tape returns to the beginning of partition 0 on an LU reset. It was found while validating a backport of that series to RHEL 9.8, when the partition tests were run on real hardware with can-partitions enabled. The same failure then reproduced on unmodified RHEL 9.8 and on upstream, and the fix makes the test pass on v7.3-rc3 and RHEL 9.8 with an LTO-5.
The harness (https://gitlab.com/loberman/tapetest, test X03) now refuses to silently skip the partition tests on hardware.
--- drivers/scsi/st.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/scsi/st.c +10 -4
@@ -3187,14 +3187,20 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition partition >= ST_NBR_PARTITIONS)return (-EINVAL );if (partition != STp->partition) { -if (get_location (STp, &blk, &p,1 )) +/* +* Save the location for the partition the drive reports, +* not for STp->partition: after a reset STp->partition may +* not match the partition the drive is in. +*/ +if (get_location (STp, &blk, &p,1 ) || + p <0 || p >=ST_NBR_PARTITIONS ) STps->last_block_valid =0 ;else { - STps->last_block_valid =1 ; - STps->last_block_visited = blk; + STp->ps[p].last_block_valid =1 ; + STp->ps[p].last_block_visited = blk;DEBC_printk (STp,"Visited block %d for " "partition %d saved.\n" , - blk, STp->partition); + blk, p); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1719/1887 scsi: target: iscsi: Fix race in discovery auth updates
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linfeng Sun <[email protected]>
[ Upstream commit e15b81f602edbdee39c335546f25486a1747f3f0 ]
Separate configfs opens can concurrently update the discovery AuthMethod parameter. Both callers may free the same value in iscsi_update_param_value(), causing a double-free.
Protect the lookup and replacement with the discovery TPG access lock, as used by the other TPG configfs parameter updates.
--- drivers/target/iscsi/iscsi_target_configfs.c | 26 ++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-)
drivers/target/iscsi/iscsi_target_configfs.c +19 -7
@@ -1308,17 +1308,24 @@ static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item,return -EINVAL ; } +if (iscsit_get_tpg (discovery_tpg) <0 ) +return -EINVAL ; + param =iscsi_find_param_from_key (AUTHMETHOD , discovery_tpg->param_list); -if (!param) -return -EINVAL ; +if (!param) { + err = -EINVAL ; + goto out; + }if (op) {/* * Reset the AuthMethod key to CHAP. */ -if (iscsi_update_param_value (param,CHAP ) <0 ) -return -EINVAL ; +if (iscsi_update_param_value (param,CHAP ) <0 ) { + err = -EINVAL ; + goto out; + } discovery_tpg->tpg_attrib.authentication =1 ; iscsit_global->discovery_acl.node_auth.enforce_discovery_auth =1 ;
@@ -1329,8 +1336,10 @@ static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item,/* * Reset the AuthMethod key to CHAP,None */ -if (iscsi_update_param_value (param,"CHAP,None" ) <0 ) -return -EINVAL ; +if (iscsi_update_param_value (param,"CHAP,None" ) <0 ) { + err = -EINVAL ; + goto out; + } discovery_tpg->tpg_attrib.authentication =0 ; iscsit_global->discovery_acl.node_auth.enforce_discovery_auth =0 ;
@@ -1339,7 +1348,10 @@ static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item, " Discovery TPG\n"); } -return count; + err = count; +out: +iscsit_put_tpg (discovery_tpg); +return err; }CONFIGFS_ATTR (iscsi_disc_, enforce_discovery_auth);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1720/1887 ocfs2/dlm: Protect the recovery list during debugfs reads
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <[email protected]>
[ Upstream commit 4c435828932bf46f29860e4a0375bcae101b778a ]
Recovery participant records must remain alive while debug_state_print() walks reco.node_data and formats their fields. The formatter holds dlm->spinlock, but the recovery participant list is protected by dlm_reco_state_lock. In particular, dlm_destroy_recovery_area() detaches the list under dlm_reco_state_lock and frees the detached records after releasing it. A concurrent debugfs open can therefore read freed memory.
Protect the participant traversal and field reads in debug_state_print() with dlm_reco_state_lock, matching the existing list writers. This also serializes the traversal against list_add_tail() during recovery-area initialization. Make the existing lock available to the debug code through dlmcommon.h; the lock remains internal to the OCFS2 DLM module.
Release dlm->spinlock after formatting the other domain state and before acquiring dlm_reco_state_lock, so the debug reader does not nest the two locks. Leave recovery list insertion, detachment and freeing unchanged.
KASAN report as below:
BUG: KASAN: slab-use-after-free in debug_state_open+0x1169/0x12d0
Read of size 4 at addr ffff88810662ef80 by task dlm-state-stres/896
CPU: 1 UID: 0 PID: 896 Comm: dlm-state-stres Not tainted 7.3.0-rc4-next-20260921-pmb-ocfs2-functional-v1+ #1 PREEMPT(lazy)
Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? debug_state_open+0x1169/0x12d0
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20e/0x420
? debug_state_open+0x1169/0x12d0
kasan_report+0xe0/0x110
? debug_state_open+0x1169/0x12d0
debug_state_open+0x1169/0x12d0
? __pfx_debug_state_open+0x10/0x10
full_proxy_open_regular+0x193/0x310
do_dentry_open+0x595/0x12d0
? __pfx_full_proxy_open_regular+0x10/0x10
vfs_open_consume+0xd1/0x400
? srso_alias_return_thunk+0x5/0xfbef5
path_openat+0x18d0/0x2020
? __pfx_path_openat+0x10/0x10
do_file_open+0x21e/0x470
? __pfx_do_file_open+0x10/0x10
? _raw_spin_unlock+0x23/0x40
? srso_alias_return_thunk+0x5/0xfbef5
? alloc_fd+0x3a6/0x6b0
do_sys_openat2+0xf4/0x1b0
? __pfx_do_sys_openat2+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __fput+0x5b5/0xa60
__x64_sys_openat+0x136/0x1e0
? __pfx___x64_sys_openat+0x10/0x10
do_syscall_64+0x114/0x620
entry_SYSCALL_64_after_hwframe+0x77/0x7f
[Register dump omitted.]
</TASK>
Allocated by task 880:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_cache_noprof+0x28d/0x610
dlm_remaster_locks+0x147/0x1d90
dlm_do_recovery+0xde1/0x1580
dlm_recovery_thread+0x109/0x300
kthread+0x351/0x460
ret_from_fork+0x659/0x940
ret_from_fork_asm+0x1a/0x30
Freed by task 880:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x5f/0x80
kfree+0x308/0x580
dlm_destroy_recovery_area+0x285/0x460
dlm_remaster_locks+0x17c4/0x1d90
dlm_do_recovery+0xde1/0x1580
dlm_recovery_thread+0x109/0x300
kthread+0x351/0x460
ret_from_fork+0x659/0x940
ret_from_fork_asm+0x1a/0x30
The buggy address belongs to the object at ffff88810662ef80
which belongs to the cache kmalloc-32 of size 32
The buggy address is located 0 bytes inside of
freed 32-byte region [ffff88810662ef80, ffff88810662efa0)[Page and memory-state dumps omitted.]
--- fs/ocfs2/dlm/dlmcommon.h | 2 ++ fs/ocfs2/dlm/dlmdebug.c | 5 ++++- fs/ocfs2/dlm/dlmrecovery.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-)
fs/ocfs2/dlm/dlmcommon.h +2 -0
@@ -435,6 +435,8 @@ enum { DLM_DEREF_LOCKRES_DONE = 522, }; +extern spinlock_t dlm_reco_state_lock; +struct dlm_reco_node_data {int state;
fs/ocfs2/dlm/dlmdebug.c +4 -1
@@ -792,8 +792,11 @@ static int debug_state_print(struct dlm_ctxt *dlm, char *buf, int len) buf + out, len - out); out +=scnprintf (buf + out, len - out,"\n" ); +spin_unlock (&dlm->spinlock); +/* Recovery Node State: */ out +=scnprintf (buf + out, len - out,"Recovery Node State:\n" ); +spin_lock (&dlm_reco_state_lock);list_for_each_entry (node, &dlm->reco.node_data, list) {switch (node->state) {case DLM_RECO_NODE_DATA_INIT :
@@ -825,7 +828,7 @@ static int debug_state_print(struct dlm_ctxt *dlm, char *buf, int len) node->node_num, state); } -spin_unlock (&dlm->spinlock); +spin_unlock (&dlm_reco_state_lock);return out; }
fs/ocfs2/dlm/dlmrecovery.c +1 -1
@@ -80,7 +80,7 @@ static int dlm_lockres_master_requery(struct dlm_ctxt *dlm,static u64 dlm_get_next_mig_cookie (void ); -static DEFINE_SPINLOCK (dlm_reco_state_lock); +DEFINE_SPINLOCK (dlm_reco_state_lock);static DEFINE_SPINLOCK (dlm_mig_cookie_lock);static u64 dlm_mig_cookie =1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1721/1887 samples: pidfd: fix userprogs typo
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
[ Upstream commit f1365f97fb7498d805981102eee22d362ae643f2 ]
The Makefile adds pidfd-metadata to "usertprogs-always-y", which kbuild does not know, so the sample has not been built since the conversion to userprogs, even with CONFIG_SAMPLE_PIDFD=y.
Fix the variable name. pidfd-metadata.c builds without warnings with gcc and clang for x86_64 and arm64.
--- samples/pidfd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
samples/pidfd/Makefile +1 -1
@@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -usertprogs-always-y += pidfd-metadata +userprogs-always-y += pidfd-metadata userccflags += -I usr/include
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1722/1887 pipe: preserve existing fasync readers on writer setup failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
[ Upstream commit 40bb03d3ea6f6a915218508819ecc4d7a7fa260d ]
F_SETFL and FIOASYNC decide whether to invoke ->fasync() before pipe_fasync() takes pipe->mutex. Two enables of one O_RDWR FIFO can therefore both enter the callback.
fasync_helper() allocates before checking for an existing entry. If the first enable installs both entries, a second enable can update the reader entry and then fail the allocation for the writer entry. The error path removes the pre-existing reader entry, clearing FASYNC while the writer entry remains registered. __fput() then skips ->fasync(), so a later pipe notification can dereference the freed file or its f_owner. An unprivileged memory-pressure reproducer triggers a KASAN slab-use-after-free in send_sigio() through this path.
Keep the reader helper's result and undo the registration only if this call added it. The pipe mutex serializes changes to both lists, so a failed new registration still removes its reader, while a failed duplicate preserves the existing registrations and FASYNC. Successful duplicate enables continue to update fa_fd as before.
--- fs/pipe.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/pipe.c +4 -2
@@ -750,9 +750,11 @@ pipe_fasync(int fd, struct file *filp, int on)if (filp->f_mode &FMODE_READ ) retval =fasync_helper (fd, filp, on, &pipe->fasync_readers);if ((filp->f_mode &FMODE_WRITE ) && retval >=0 ) { +int read_ret = retval; + retval =fasync_helper (fd, filp, on, &pipe->fasync_writers); -if (retval <0 && (filp->f_mode &FMODE_READ )) -/* this can happen only if on == T */ +/* Undo only a reader entry added by this call. */ +if (retval <0 && read_ret >0 )fasync_helper (-1 , filp,0 , &pipe->fasync_readers); }__pipe_unlock (pipe);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1723/1887 scsi: libsas: Fix SMP IO deadlock during HA resume
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xingui Yang <[email protected]>
[ Upstream commit 81e097a064b28b4a1f6ca1a8b433e659c1bd64c0 ]
smp_execute_task_sg() calls pm_runtime_get_sync() on the host before issuing an SMP command. When that command is itself issued from the HA resume path, the get_sync() deadlocks: it waits for the ongoing resume (the device is RPM_RESUMING), while the resume is blocked in sas_drain_work() waiting for that same SMP IO to complete.
The deadlock needs an expander-attached SATA disk. During sas_resume_ha() -> sas_drain_work(), DISCE_RESUME -> sas_resume_sata() -> ata_sas_port_resume() requests ATA_EH_RESET, and the hard reset for such a disk is done via SMP PHY CONTROL (sas_ata_hard_reset() -> sas_phy_reset() -> sas_smp_phy_control() -> smp_execute_task_sg()). Direct-attached SATA resets through lldd_control_phy() and SSP devices use TMFs, so neither hits this.
Replace the get_sync()/put_sync() pair with pm_runtime_get_noresume()/pm_runtime_put(). smp_execute_task_sg() only needs to hold off autosuspend while the SMP is in flight, and it must not try to resume the host: a sync resume issued from the HA resume path itself is what deadlocks, and by the time sas_resume_ha() runs, hw_init has already reinitialized the hardware, so the device is accessible without one.
The usage reference is still required. Discovery work normally runs inside an event worker's PM reference, taken at sas_notify_port_event() notify time and held until the handler has flushed the disco queue. sas_rediscover_ex_phy() however requeues DISCE_REVALIDATE_DOMAIN from within the revalidation worker itself, and flush_workqueue() does not wait for work items queued during execution, so that chained revalidation runs with no outer PM reference - without the get_noresume(), its SMP could race autosuspend.
For the BSG path, sas_smp_handler() is the only caller which may find the host autosuspended: expander SMP requests do not go through any SCSI device request queue, so nothing else in that path holds the host awake. Resume it there with pm_runtime_resume_and_get() and check the result.
--- drivers/scsi/libsas/sas_expander.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
drivers/scsi/libsas/sas_expander.c +12 -2
@@ -40,7 +40,11 @@ static int smp_execute_task_sg(struct domain_device *dev,to_sas_internal (dev->port->ha->shost->transportt);struct sas_ha_struct *ha = dev->port->ha; -pm_runtime_get_sync (ha->dev); +/* +* Non-blocking: a sync resume here would deadlock against +* sas_drain_work() during HA resume. +*/ +pm_runtime_get_noresume (ha->dev);mutex_lock (&dev->ex_dev.cmd_mutex);for (retry =0 ; retry <3 ; retry++) {if (test_bit (SAS_DEV_GONE , &dev->state)) {
@@ -113,7 +117,7 @@ static int smp_execute_task_sg(struct domain_device *dev, } }mutex_unlock (&dev->ex_dev.cmd_mutex); -pm_runtime_put_sync (ha->dev); +pm_runtime_put (ha->dev);BUG_ON (retry ==3 && task !=NULL );sas_free_task (task);
@@ -2159,6 +2163,11 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, goto out; } +/* The host may have autosuspended, resume it here. */ + ret =pm_runtime_resume_and_get (dev->port->ha->dev); +if (ret) + goto out; + ret =smp_execute_task_sg (dev, job->request_payload.sg_list, job->reply_payload.sg_list);if (ret >=0 ) {
@@ -2166,6 +2175,7 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, rcvlen = job->reply_payload.payload_len - ret; ret =0 ; } +pm_runtime_put (dev->port->ha->dev); out:bsg_job_done (job, ret, rcvlen);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1724/1887 netlink: avoid hashing the network namespace pointer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
[ Upstream commit f88bb3606e4bd11ee035b682cddc2999e604609a ]
The netlink rhashtable key includes a raw struct net pointer and a user-controlled port ID. Both /proc/net/netlink and socket diagnostics expose the table's bucket order. By binding and rebinding chosen NETLINK_USERSOCK port IDs, an unprivileged reader can distinguish equal buckets and recover the low bits of the Jenkins hash. Its 32-bit seed and the limited set of kernel-image slides can then be searched offline to recover the address of init_net.
Use the namespace's unique, non-address net_cookie in the comparison key instead. It is assigned before the per-net initializers run and remains unchanged for the namespace's lifetime. The lookup key and object hash are still built by netlink_compare_arg_init(), keeping lookup, insertion, removal and rehashing consistent while preserving namespace separation. Neither public table walker needs to change.
Reading the socket's namespace cookie in netlink_compare() is safe under RCU, including during namespace teardown. netlink_release() removes the socket from the hash table and defers its final put with call_rcu(). cleanup_net() runs the per-net exit methods and waits for outstanding RCU callbacks with rcu_barrier() before freeing namespace storage.
Unlike ns.ns_id, net_cookie is also available and initialized during setup_net() in older stable kernels, making the change straightforward to backport to v5.15 and later.
--- net/netlink/af_netlink.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/netlink/af_netlink.c +3 -3
@@ -463,7 +463,7 @@ netlink_unlock_table(void)struct netlink_compare_arg { -possible_net_t pnet; +u64 net_cookie;u32 portid; };
@@ -478,14 +478,14 @@ static inline int netlink_compare(struct rhashtable_compare_arg *arg,const struct netlink_sock *nlk = ptr;return nlk->portid != x->portid || - !net_eq (sock_net (&nlk->sk),read_pnet (&x->pnet)); +sock_net (&nlk->sk)->net_cookie != x->net_cookie; }static void netlink_compare_arg_init (struct netlink_compare_arg *arg,struct net *net,u32 portid) {memset (arg,0 ,sizeof (*arg)); -write_pnet (&arg->pnet, net); + arg->net_cookie = net->net_cookie; arg->portid = portid; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1725/1887 net: bcmgenet: unshare the skb before writing the control block
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Buchwitz <[email protected]>
[ Upstream commit 89771ce4f8f67dcffae561b2ccac95c0f6e3aa01 ]
bcmgenet stores first_cb, last_cb and bytes_sent in the skb control block and reads them back on completion to free the skb and credit BQL. ether_setup() leaves IFF_TX_SKB_SHARING set, so the stack can resubmit a shared skb that is still in the ring. The next transmit overwrites last_cb, so the earlier slots complete without crediting their bytes and BQL stalls the queue until the watchdog resets it.
Unshare the skb before writing the control block.
Reproduce with pktgen in clone_skb mode, which hands the driver the same skb while earlier copies are still in the ring:
modprobe pktgen
pg=/proc/net/pktgen
echo "add_device eth0" > $pg/kpktgend_0
echo "dst_mac AA:BB:CC:DD:EE:FF" > $pg/eth0
echo "dst 192.0.2.1" > $pg/eth0
echo "clone_skb 8" > $pg/eth0
echo "count 0" > $pg/eth0
echo start > $pg/pgctrl &
sleep 5
echo stop > $pg/pgctrl
wait
cat /sys/class/net/eth0/queues/tx-0/byte_queue_limits/inflight
inflight stays nonzero on the now idle queue. clone_skb 0 leaves it at zero.
--- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +10 -0
@@ -2099,6 +2099,16 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) goto out; } +/* We store Tx state in the control block, so the skb must not be +* shared, but ether_setup() leaves IFF_TX_SKB_SHARING set. +*/ + skb =skb_share_check (skb,GFP_ATOMIC ); +if (!skb) { +BCMGENET_STATS64_INC ((&ring->stats64), dropped); + ret =NETDEV_TX_OK ; + goto out; + } +/* Retain how many bytes will be sent on the wire, without TSB inserted * by transmit checksum offload */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1726/1887 gpio: mxc: enable pad wakeup on i.MX8x platforms
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shenwei Wang <[email protected]>
[ Upstream commit f60c9eac54af28d7b5651fe49944bfd5098550e6 ]
On i.MX8QM/QXP/DXL SoCs, even a GPIO is selected as the wakeup source, the GPIO block will be powered off when system enters into suspend state. This can greatly reduce the power consumption of suspend state because the whole partition can be shutdown. This is called PAD wakeup feature on i.MX8x platform.
This patch adds the noirq suspend/resume hooks and uses the pad wakeup feature as the default wakeup method for GPIO modules on i.MX8QM/QXP/DXL platforms.
Stable-dep-of: b7719c575dec ("gpio: mxc: fix both_edges bit operations")
--- drivers/gpio/gpio-mxc.c | 92 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-)
drivers/gpio/gpio-mxc.c +91 -1
@@ -25,6 +25,12 @@#include <linux/of_device.h> #include <linux/bug.h> +#define IMX_SCU_WAKEUP_OFF 0 +#define IMX_SCU_WAKEUP_LOW_LVL 4 +#define IMX_SCU_WAKEUP_FALL_EDGE 5 +#define IMX_SCU_WAKEUP_RISE_EDGE 6 +#define IMX_SCU_WAKEUP_HIGH_LVL 7 +/* device type dependent stuff */ struct mxc_gpio_hwdata {unsigned dr_reg;
@@ -62,6 +68,9 @@ struct mxc_gpio_port {u32 both_edges;struct mxc_gpio_reg_saved gpio_saved_reg;bool power_off; +u32 wakeup_pads; +bool is_pad_wakeup; +u32 pad_type[32 ];const struct mxc_gpio_hwdata *hwdata; };
@@ -131,6 +140,9 @@ static const struct of_device_id mxc_gpio_dt_ids[] = { { .compatible = "fsl,imx31-gpio", .data = &imx31_gpio_hwdata }, { .compatible = "fsl,imx35-gpio", .data = &imx35_gpio_hwdata }, { .compatible = "fsl,imx7d-gpio", .data = &imx35_gpio_hwdata }, + { .compatible = "fsl,imx8dxl-gpio", .data = &imx35_gpio_hwdata }, + { .compatible = "fsl,imx8qm-gpio", .data = &imx35_gpio_hwdata }, + { .compatible = "fsl,imx8qxp-gpio", .data = &imx35_gpio_hwdata }, {/* sentinel */ } };MODULE_DEVICE_TABLE (of, mxc_gpio_dt_ids);
@@ -207,6 +219,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) }writel (1 << gpio_idx, port->base +GPIO_ISR ); + port->pad_type[gpio_idx] = type;raw_spin_unlock_irqrestore (&port->gc.bgpio_lock, flags);
@@ -266,6 +279,9 @@ static void mx3_gpio_irq_handler(struct irq_desc *desc)struct mxc_gpio_port *port =irq_desc_get_handler_data (desc);struct irq_chip *chip =irq_desc_get_chip (desc); +if (port->is_pad_wakeup) +return ; +chained_irq_enter (chip, desc); irq_stat =readl (port->base +GPIO_ISR ) &readl (port->base +GPIO_IMR );
@@ -318,11 +334,13 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) ret =enable_irq_wake (port->irq_high); else ret =enable_irq_wake (port->irq); + port->wakeup_pads |= (1 << gpio_idx); }else {if (port->irq_high && (gpio_idx >=16 )) ret =disable_irq_wake (port->irq_high);else ret =disable_irq_wake (port->irq); + port->wakeup_pads &= ~(1 << gpio_idx); }return ret;
@@ -377,7 +395,6 @@ static int mxc_gpio_probe(struct platform_device *pdev)return -ENOMEM ; port->dev = &pdev->dev; - port->hwdata =device_get_match_data (&pdev->dev); port->base =devm_platform_ioremap_resource (pdev,0 );
@@ -509,6 +526,78 @@ static void mxc_gpio_restore_regs(struct mxc_gpio_port *port)writel (port->gpio_saved_reg.dr, port->base +GPIO_DR ); } +static bool mxc_gpio_generic_config (struct mxc_gpio_port *port, +unsigned int offset,unsigned long conf) +{ +struct device_node *np = port->dev->of_node; + +if (of_device_is_compatible (np,"fsl,imx8dxl-gpio" ) || +of_device_is_compatible (np,"fsl,imx8qxp-gpio" ) || +of_device_is_compatible (np,"fsl,imx8qm-gpio" )) +return (gpiochip_generic_config (&port->gc, offset, conf) ==0 ); + +return false; +} + +static bool mxc_gpio_set_pad_wakeup (struct mxc_gpio_port *port,bool enable) +{ +unsigned long config; +bool ret = false; +int i, type; + +static const u32 pad_type_map[] = { +IMX_SCU_WAKEUP_OFF ,/* 0 */ +IMX_SCU_WAKEUP_RISE_EDGE ,/* IRQ_TYPE_EDGE_RISING */ +IMX_SCU_WAKEUP_FALL_EDGE ,/* IRQ_TYPE_EDGE_FALLING */ +IMX_SCU_WAKEUP_FALL_EDGE ,/* IRQ_TYPE_EDGE_BOTH */ +IMX_SCU_WAKEUP_HIGH_LVL ,/* IRQ_TYPE_LEVEL_HIGH */ +IMX_SCU_WAKEUP_OFF ,/* 5 */ +IMX_SCU_WAKEUP_OFF ,/* 6 */ +IMX_SCU_WAKEUP_OFF ,/* 7 */ +IMX_SCU_WAKEUP_LOW_LVL ,/* IRQ_TYPE_LEVEL_LOW */ + }; + +for (i =0 ; i <32 ; i++) { +if ((port->wakeup_pads & (1 << i))) { + type = port->pad_type[i]; +if (enable) + config = pad_type_map[type]; +else + config =IMX_SCU_WAKEUP_OFF ; + ret |=mxc_gpio_generic_config (port, i, config); + } + } + +return ret; +} + +static int __maybe_unused mxc_gpio_noirq_suspend (struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct mxc_gpio_port *port =platform_get_drvdata (pdev); + +if (port->wakeup_pads >0 ) + port->is_pad_wakeup =mxc_gpio_set_pad_wakeup (port, true); + +return 0 ; +} + +static int __maybe_unused mxc_gpio_noirq_resume (struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct mxc_gpio_port *port =platform_get_drvdata (pdev); + +if (port->wakeup_pads >0 ) +mxc_gpio_set_pad_wakeup (port, false); + port->is_pad_wakeup = false; + +return 0 ; +} + +static const struct dev_pm_ops mxc_gpio_dev_pm_ops = { +SET_NOIRQ_SYSTEM_SLEEP_PM_OPS (mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume) +}; +static int mxc_gpio_syscore_suspend (void ) {struct mxc_gpio_port *port;
@@ -548,6 +637,7 @@ static struct platform_driver mxc_gpio_driver = { .name = "gpio-mxc", .of_match_table = mxc_gpio_dt_ids, .suppress_bind_attrs = true, + .pm = &mxc_gpio_dev_pm_ops, }, .probe = mxc_gpio_probe, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1727/1887 gpio: mxc: use lock guards for the generic GPIO chip lock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <[email protected]>
[ Upstream commit ba441322c7aac4735d78fc6781e497a01fb8eac7 ]
Simplify the code by using lock guards for the bgpio_lock.
Stable-dep-of: b7719c575dec ("gpio: mxc: fix both_edges bit operations")
--- drivers/gpio/gpio-mxc.c | 48 ++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 27 deletions(-)
drivers/gpio/gpio-mxc.c +21 -27
@@ -7,6 +7,7 @@// Authors: Daniel Mack, Juergen Beisert. // Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/init.h>
@@ -160,7 +161,6 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) {struct irq_chip_generic *gc =irq_data_get_irq_chip_data (d);struct mxc_gpio_port *port = gc->private; -unsigned long flags;u32 bit, val;u32 gpio_idx = d->hwirq;int edge;
@@ -199,41 +199,38 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)return -EINVAL ; } -raw_spin_lock_irqsave (&port->gc.bgpio_lock, flags); + scoped_guard(raw_spinlock_irqsave, &port->gc.bgpio_lock) { +if (GPIO_EDGE_SEL >=0 ) { + val =readl (port->base +GPIO_EDGE_SEL ); +if (edge ==GPIO_INT_BOTH_EDGES ) +writel (val | (1 << gpio_idx), + port->base +GPIO_EDGE_SEL ); +else +writel (val & ~(1 << gpio_idx), + port->base +GPIO_EDGE_SEL ); + } -if (GPIO_EDGE_SEL >=0 ) { - val =readl (port->base +GPIO_EDGE_SEL ); -if (edge ==GPIO_INT_BOTH_EDGES ) -writel (val | (1 << gpio_idx), - port->base +GPIO_EDGE_SEL ); -else -writel (val & ~(1 << gpio_idx), - port->base +GPIO_EDGE_SEL ); - } +if (edge !=GPIO_INT_BOTH_EDGES ) { + reg +=GPIO_ICR1 + ((gpio_idx &0x10 ) >>2 );/* lower or upper register */ + bit = gpio_idx &0xf ; + val =readl (reg) & ~(0x3 << (bit <<1 )); +writel (val | (edge << (bit <<1 )), reg); + } -if (edge !=GPIO_INT_BOTH_EDGES ) { - reg +=GPIO_ICR1 + ((gpio_idx &0x10 ) >>2 );/* lower or upper register */ - bit = gpio_idx &0xf ; - val =readl (reg) & ~(0x3 << (bit <<1 )); -writel (val | (edge << (bit <<1 )), reg); +writel (1 << gpio_idx, port->base +GPIO_ISR ); + port->pad_type[gpio_idx] = type; } -writel (1 << gpio_idx, port->base +GPIO_ISR ); - port->pad_type[gpio_idx] = type; - -raw_spin_unlock_irqrestore (&port->gc.bgpio_lock, flags); -return port->gc.direction_input (&port->gc, gpio_idx); }static void mxc_flip_edge (struct mxc_gpio_port *port,u32 gpio) {void __iomem *reg = port->base; -unsigned long flags;u32 bit, val;int edge; -raw_spin_lock_irqsave (&port->gc.bgpio_lock, flags); +guard (raw_spinlock_irqsave)(&port->gc.bgpio_lock); reg +=GPIO_ICR1 + ((gpio &0x10 ) >>2 );/* lower or upper register */ bit = gpio &0xf ;
@@ -249,12 +246,9 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) }else {pr_err ("mxc: invalid configuration for GPIO %d: %x\n" , gpio, edge); - goto unlock; +return ; }writel (val | (edge << (bit <<1 )), reg); - -unlock: -raw_spin_unlock_irqrestore (&port->gc.bgpio_lock, flags); }/* handle 32 interrupts in one status register */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1728/1887 gpio: mxc: fix both_edges bit operations
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peng Fan <[email protected]>
[ Upstream commit b7719c575dec69146f6d537fd616b27083c0cf45 ]
gpio_set_irq_type() can be called concurrently for different pins on the same port. The IRQ core serializes per irq descriptor, but different pins have different descriptors, so on SMP systems two concurrent gpio_set_irq_type() calls for pins on the same port run without mutual exclusion.
The read-modify-write of port->both_edges is performed outside the port-wide scoped_guard(gpio_generic_lock_irqsave) section, so concurrent updates for different pins can overwrite each other, causing missed interrupts or stuck IRQ lines on dual-edge triggered pins.
The original uniprocessor MXC SoCs were not affected; the race became reachable on multi-core i.MX7 and i.MX8 SoCs that reuse this driver.
Convert both_edges from u32 to unsigned long and use set_bit(), clear_bit(), and test_bit() to make the modifications atomic.
--- drivers/gpio/gpio-mxc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/gpio/gpio-mxc.c +5 -4
@@ -7,6 +7,7 @@// Authors: Daniel Mack, Juergen Beisert. // Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. +#include <linux/bitops.h> #include <linux/cleanup.h> #include <linux/clk.h> #include <linux/err.h>
@@ -66,7 +67,7 @@ struct mxc_gpio_port {struct irq_domain *domain;struct gpio_chip gc;struct device *dev; -u32 both_edges; +unsigned long both_edges;struct mxc_gpio_reg_saved gpio_saved_reg;bool power_off;u32 wakeup_pads;
@@ -166,7 +167,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)int edge;void __iomem *reg = port->base; - port->both_edges &= ~(1 << gpio_idx); +clear_bit (gpio_idx, &port->both_edges);switch (type) {case IRQ_TYPE_EDGE_RISING : edge =GPIO_INT_RISE_EDGE ;
@@ -186,7 +187,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) edge =GPIO_INT_HIGH_LEV ;pr_debug ("mxc: set GPIO %d to high trigger\n" , gpio_idx); } - port->both_edges |=1 << gpio_idx; +set_bit (gpio_idx, &port->both_edges); }break ;case IRQ_TYPE_LEVEL_LOW :
@@ -257,7 +258,7 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat)while (irq_stat !=0 ) {int irqoffset =fls (irq_stat) -1 ; -if (port->both_edges & (1 << irqoffset)) +if (test_bit (irqoffset, &port->both_edges))mxc_flip_edge (port, irqoffset);generic_handle_domain_irq (port->domain, irqoffset);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1729/1887 gpio: mxc: use BIT() macro
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Stein <[email protected]>
[ Upstream commit 9de94681ee48770ec7e2062451a572b557bf9298 ]
Replace the open-code with the BIT() macro.
Stable-dep-of: 170aeff46fb5 ("gpio: mxc: fix wakeup_pads bit operations")
--- drivers/gpio/gpio-mxc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpio/gpio-mxc.c +2 -2
@@ -329,13 +329,13 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) ret =enable_irq_wake (port->irq_high); else ret =enable_irq_wake (port->irq); - port->wakeup_pads |= (1 << gpio_idx); + port->wakeup_pads |=BIT (gpio_idx); }else {if (port->irq_high && (gpio_idx >=16 )) ret =disable_irq_wake (port->irq_high);else ret =disable_irq_wake (port->irq); - port->wakeup_pads &= ~(1 << gpio_idx); + port->wakeup_pads &= ~BIT (gpio_idx); }return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1730/1887 gpio: mxc: fix wakeup_pads bit operations
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peng Fan <[email protected]>
[ Upstream commit 170aeff46fb54f41545c85a72aec525aebc79d44 ]
gpio_set_wake_irq() can be called concurrently for different pins on the same port. The writer-vs-writer race is the concern: two concurrent gpio_set_wake_irq() calls for different pins on the same port both do a non-atomic read-modify-write on the same wakeup_pads word. The old |= and &= compile to separate load/modify/store instructions that can interleave, losing one CPU's update.
assign_bit() uses an atomic RMW instruction, so concurrent writers to different bits in the same word are safe.
The reader side (for_each_set_bit in noirq_suspend, wakeup_pads > 0) runs in noirq context where no concurrent writer can execute, so reader atomicity is not needed.
wakeup_pads is a u32, while assign_bit() operates on unsigned long pointers. On 64-bit platforms, this causes an 8-byte read-modify-write on a 4-byte field, corrupting the adjacent is_pad_wakeup. So change wakeup_pads to unsigned long and reorder to avoid wasting words.
And fix the enable/disable path unconditionally sets/clears the wakeup_pads bit even when enable_irq_wake()/disable_irq_wake() fails. Only update the bit on success.
--- drivers/gpio/gpio-mxc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/gpio/gpio-mxc.c +6 -4
@@ -70,8 +70,8 @@ struct mxc_gpio_port {unsigned long both_edges;struct mxc_gpio_reg_saved gpio_saved_reg;bool power_off; -u32 wakeup_pads;bool is_pad_wakeup; +unsigned long wakeup_pads;u32 pad_type[32 ];const struct mxc_gpio_hwdata *hwdata; };
@@ -329,16 +329,18 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) ret =enable_irq_wake (port->irq_high); else ret =enable_irq_wake (port->irq); - port->wakeup_pads |=BIT (gpio_idx); }else {if (port->irq_high && (gpio_idx >=16 )) ret =disable_irq_wake (port->irq_high);else ret =disable_irq_wake (port->irq); - port->wakeup_pads &= ~BIT (gpio_idx); } +if (ret) +return ret; -return ret; +assign_bit (gpio_idx, &port->wakeup_pads, enable); + +return 0 ; }static int mxc_gpio_init_gc (struct mxc_gpio_port *port,int irq_base)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1731/1887 autofs: ignore notification errors from a replaced pipe
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sung Byeongchan <[email protected]>
commit 65676cd4203c0e41a94caf54080a7f0a95434bda upstream.
autofs_notify_daemon() takes a reference to the current notification pipe under wq_mutex, then drops the mutex before writing the request. The write can block while the daemon enters catatonic mode and installs a replacement pipe.
If the old pipe's reader is then closed, the delayed write returns -EPIPE and the generic error path enters catatonic mode again. That transition acts on the current superblock state, closes the replacement pipe, and releases the new daemon generation's wait queues.
Only enter catatonic mode when the pipe which failed is still the current pipe. Factor the already-locked transition so the identity check and state change are atomic with respect to another replacement.
This was reproduced on v7.3-rc5-337-gff47652a4b66c in a local QEMU guest. An unprivileged UID 65534 lookup filled the old packet pipe before a normal CATATONIC/SETPIPEFD restart. On the unmodified kernel, the new pipe received HUP and both a pending victim lookup and a later lookup failed with ENOENT in two out of two fresh-mount runs.
With this change, the new pipe remained active, received an intact 304-byte request, and both victim lookups completed in two out of two runs. Normal lookup and restart-without-a-blocked-writer controls passed. No KASAN, oops, refcount, or lock diagnostic was observed. A source reproducer and complete local logs are available privately on request.
The demonstrated impact is limited to denial of a shared autofs service during a legitimate daemon restart. No memory corruption, information leak, privilege escalation, or code execution primitive was observed.
--- fs/autofs/waitq.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-)
fs/autofs/waitq.c +19 -6
@@ -12,15 +12,13 @@*/ static autofs_wqt_t autofs_next_wait_queue =1 ; -void autofs_catatonic_mode (struct autofs_sb_info *sbi) +static void autofs_catatonic_mode_locked (struct autofs_sb_info *sbi) {struct autofs_wait_queue *wq, *nwq; -mutex_lock (&sbi->wq_mutex); -if (sbi->flags &AUTOFS_SBI_CATATONIC ) { -mutex_unlock (&sbi->wq_mutex); +lockdep_assert_held (&sbi->wq_mutex); +if (sbi->flags &AUTOFS_SBI_CATATONIC )return ; - }pr_debug ("entering catatonic mode\n" );
@@ -40,6 +38,21 @@ void autofs_catatonic_mode(struct autofsfput (sbi->pipe);/* Close the pipe */ sbi->pipe =NULL ; sbi->pipefd =-1 ; +} + +void autofs_catatonic_mode (struct autofs_sb_info *sbi) +{ +mutex_lock (&sbi->wq_mutex); +autofs_catatonic_mode_locked (sbi); +mutex_unlock (&sbi->wq_mutex); +} + +static void autofs_catatonic_mode_for_pipe (struct autofs_sb_info *sbi, +struct file *pipe) +{ +mutex_lock (&sbi->wq_mutex); +if (sbi->pipe == pipe) +autofs_catatonic_mode_locked (sbi);mutex_unlock (&sbi->wq_mutex); }
@@ -170,7 +183,7 @@ static void autofs_notify_daemon(structautofs_wait_release (sbi, wq->wait_queue_token, ret);break ;default : -autofs_catatonic_mode (sbi); +autofs_catatonic_mode_for_pipe (sbi, pipe);break ; }fput (pipe);
Greg Kroah-Hartman
maintainerPATCH 1732/1887 unicode: free the map after a grace period
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit a96c5299bd7305eb984377681eb3222a57376405 upstream.
generic_ci_d_hash() and generic_ci_d_compare() read sb->s_encoding and dereference the unicode map while a pathwalk in rcu mode holds nothing but rcu_read_lock(). The filesystems that use them, ext4, f2fs and tmpfs, drop the map with utf8_unload() from ->put_super(), which runs when the last reference to the mount goes away. A lookup that is still inside such a filesystem at that point reads a freed map.
With a pathwalk held up in utf8_casefold_hash() while the last reference to a casefolded tmpfs goes away:
BUG: KASAN: slab-use-after-free in utf8nlookup+0x74c/0x950 Read of size 8 at addr ff110001030fe658 by task walker/98 Call Trace: <TASK> utf8nlookup+0x74c/0x950 utf8byte+0x160/0x1560 utf8_casefold_hash+0x167/0x230 generic_ci_d_hash+0xdd/0x1c0 link_path_walk+0x11ad/0x1d30 path_lookupat+0x63/0xb00 filename_lookup+0x1f1/0x5b0 vfs_statx+0xd7/0x3b0 [...] Allocated by task 94: __kmalloc_cache_noprof+0x249/0x560 utf8_load+0x4e/0x570 shmem_parse_opt_casefold.isra.0+0x92/0x270 [...] Freed by task 97: kfree+0x1db/0x5b0 shmem_put_super+0x72/0x170 generic_shutdown_super+0x14c/0x530 kill_anon_super+0x3a/0x60 deactivate_locked_super+0x9c/0xf0 cleanup_mnt+0x9f/0x130
So far that has been hard to hit. umount(2) waits for a grace period in namespace_unlock() before it drops the mount, so only a mount whose last reference goes away elsewhere, like the close of a file or a chdir out of a lazily unmounted directory, can race a walker. So it is reachable.
Delay the free until a grace period has passed. The map and the data table it holds a reference to then outlive any pathwalk that found the superblock before the mount went away. The reference on the data table module is dropped from the rcu callback as well. utf8-core is built in whenever CONFIG_UNICODE is set, so there is no module exit that would have to wait for the callbacks.
Overlayfs points the s_encoding of an overlay at the map of its first layer without taking a reference of its own. That stays correct. The layer is held by the overlay, so its map is dropped only after the overlay is gone.
--- fs/unicode/utf8-core.c | 21 +++++++++++++++++---- include/linux/unicode.h | 1 + 2 files changed, 18 insertions(+), 4 deletions(-)
fs/unicode/utf8-core.c +17 -4
@@ -3,6 +3,7 @@#include <linux/kernel.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/rcupdate.h> #include <linux/parser.h> #include <linux/errno.h> #include <linux/stringhash.h>
@@ -205,12 +206,24 @@ out_free_um: }EXPORT_SYMBOL (utf8_load); +static void utf8_unload_rcu (struct rcu_head *head) +{ + struct unicode_map *um = container_of(head, struct unicode_map, rcu); + +symbol_put (utf8_data_table); +kfree (um); +} + +/* +* A pathwalk in rcu mode may still be in ->d_hash() or ->d_compare() of a +* filesystem that is being torn down and read the map through its +* superblock, so the map and the tables it points to have to outlive the +* grace period. +*/ void utf8_unload (struct unicode_map *um) { -if (um) { -symbol_put (utf8_data_table); -kfree (um); - } +if (um) +call_rcu (&um->rcu, utf8_unload_rcu); }EXPORT_SYMBOL (utf8_unload);
include/linux/unicode.h +1 -0
@@ -51,6 +51,7 @@ struct unicode_map {unsigned int version;const struct utf8data *ntab[UTF8_NMAX ];const struct utf8data_table *tables; +struct rcu_head rcu; };int utf8_validate (const struct unicode_map *um,const struct qstr *str);
Greg Kroah-Hartman
maintainerPATCH 1733/1887 KVM: nVMX: Reset MMU back to the root MMU if loading L2 state fails for !VM-Entry
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amirmohammad Eftekhar <[email protected]>
commit c8f4cfe1cf93bce924e27f2abead7a4c4a487505 upstream.
Reset the vCPU's MMU pointer back to the root MMU if loading L2 state fails in the "not from VM-Entry" case, i.e. when emulating RSM or handling KVM_SET_NESTED_STATE. Failure to unwind the MMU pointer results in KVM trying to run L1 with a nested MMU, and is especially problematic if the vCPU manages to free its nested state before the VM crashes. Constructing the root for a nested EPT MMU goes through vmcs12, which is dynamically allocated/freed when nVMX is enabled/disabled. And so if the nested state is freed with the MMU still pointing at the nested MMU, KVM will hit a NULL pointer deref when attempting to get L1=>L2 EPTP.
BUG: kernel NULL pointer dereference, address: 0000000000000078 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 114a2d067 P4D 111743067 PUD 11141f067 PMD 0 Oops: Oops: 0000 [#1] SMP CPU: 20 UID: 1000 PID: 1272 Comm: nested_tdp_faul Not tainted 7.3.0-rc4-8c89f11d1a99b-sink-vm #1914 PREEMPTLAZY Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:nested_ept_get_eptp+0xb/0x10 [kvm_intel] Call Trace: <TASK> kvm_mmu_load+0xcd/0x870 [kvm] kvm_arch_vcpu_ioctl_run+0x18f5/0x1f80 [kvm] kvm_vcpu_ioctl+0x2c7/0x970 [kvm] __x64_sys_ioctl+0x90/0xd0 do_syscall_64+0x9c/0x4d0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x47491b </TASK> Modules linked in: kvm_intel kvm irqbypass CR2: 0000000000000078 ---[ end trace 0000000000000000 ]--- RIP: 0010:nested_ept_get_eptp+0xb/0x10 [kvm_intel]
--- arch/x86/kvm/vmx/nested.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/x86/kvm/vmx/nested.c +3 -1
@@ -3540,8 +3540,10 @@ vmentry_fail_vmexit_guest_mode: vmentry_fail_vmexit:vmx_switch_vmcs (vcpu, &vmx->vmcs01); -if (!from_vmentry) +if (!from_vmentry) { +nested_ept_uninit_mmu_context (vcpu);return NVMX_VMENTRY_VMEXIT ; + }kvm_vcpu_unmap (vcpu, &vmx->nested.apic_access_page_map, false);kvm_vcpu_unmap (vcpu, &vmx->nested.virtual_apic_map, true);
Greg Kroah-Hartman
maintainerPATCH 1734/1887 fsnotify: prevent mark additions during connector teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
commit 36ebddca56b9d8993d6dc984fdecc748ee1f5e06 upstream.
fsnotify_destroy_marks() keeps a reference to its current mark while it drops conn->lock to destroy the mark. This stabilizes the forward-walk cursor, but does not prevent a new mark from being inserted before it. For example, an inotify watch re-added after IN_IGNORED sorts before the old, detached mark for the same group. The walk can miss the replacement and then detach the entire connector from the object.
The replacement is still on its group's marks_list and, for inotify, in the watch IDR. The group mutex no longer protects the connector's object from disappearing. An unprivileged fdinfo read racing the final detach can consequently call igrab(NULL):
BUG: KASAN: null-ptr-deref in igrab+0x24/0x100 Write of size 4 at addr 0000000000000148 Call Trace: igrab+0x24/0x100 inotify_show_fdinfo+0x1dc/0x5e0 seq_show+0x397/0x690
Set a DESTROYING flag under conn->lock before starting the walk, and reject new marks on that connector with -ENOENT. The existing add-mark error paths undo the temporary group-list entry and the backend's watch allocation. Do not wait for teardown while holding the group mutex, which the destroyer needs. Once the old connector is detached, an add can install a fresh connector as before.
This closes the insertion race for all object types using the common connector teardown, without changing the mark reference or SRCU lifetime rules.
--- fs/notify/mark.c | 11 +++++++++++ include/linux/fsnotify_backend.h | 1 + 2 files changed, 12 insertions(+)
fs/notify/mark.c +11 -0
@@ -719,6 +719,11 @@ restart: goto out_err; } +if (conn->flags &FSNOTIFY_CONN_FLAG_DESTROYING ) { + err = -ENOENT ; + goto out_err; + } +/* is mark the first mark? */ if (hlist_empty (&conn->list)) {hlist_add_head_rcu (&mark->obj_list, &conn->list);
@@ -902,6 +907,12 @@ void fsnotify_destroy_marks(fsnotify_conif (!conn)return ;/* +* New marks could be inserted before our cursor and survive the final +* detachment of the connector from the object. Prevent additions to +* this connector before dropping its lock. +*/ + conn->flags |=FSNOTIFY_CONN_FLAG_DESTROYING ; +/* * We have to be careful since we can race with e.g. * fsnotify_clear_marks_by_group() and once we drop the conn->lock, the * list can get modified. However we are holding mark reference and
include/linux/fsnotify_backend.h +1 -0
@@ -474,6 +474,7 @@ struct fsnotify_mark_connector {unsigned short type;/* Type of object [lock] */ #define FSNOTIFY_CONN_FLAG_HAS_FSID 0x01#define FSNOTIFY_CONN_FLAG_HAS_IREF 0x02 +#define FSNOTIFY_CONN_FLAG_DESTROYING 0x04unsigned short flags;/* flags [lock] */ __kernel_fsid_t fsid;/* fsid of filesystem containing object */ union {
Greg Kroah-Hartman
maintainerPATCH 1735/1887 net/sched: fix use-after-free in __tcf_action_put()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Jean <[email protected]>
commit 7b16eb911091aae237a8673da94e4dfb9cd21d54 upstream.
__tcf_action_put() decrements the reference count before decrementing the binding count. Another thread can free the action between these operations, causing the binding-count update to access freed memory. KASAN reports it as:
BUG: KASAN: slab-use-after-free in __tcf_action_put+0x327/0x340 Write of size 4 at addr ff11000000d46420 by task tc-put-pause/64
Hold the action IDR mutex across both counter updates and IDR removal, keeping cleanup outside the lock.
--- net/sched/act_api.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
net/sched/act_api.c +5 -6
@@ -378,9 +378,10 @@ static int __tcf_action_put(struct tc_ac {struct tcf_idrinfo *idrinfo = p->idrinfo; -if (refcount_dec_and_mutex_lock (&p->tcfa_refcnt, &idrinfo->lock)) { -if (bind) -atomic_dec (&p->tcfa_bindcnt); +mutex_lock (&idrinfo->lock); +if (bind) +atomic_dec (&p->tcfa_bindcnt); +if (refcount_dec_and_test (&p->tcfa_refcnt)) {idr_remove (&idrinfo->action_idr, p->tcfa_index);mutex_unlock (&idrinfo->lock);
@@ -388,9 +389,7 @@ static int __tcf_action_put(struct tc_acreturn 1 ; } -if (bind) -atomic_dec (&p->tcfa_bindcnt); - +mutex_unlock (&idrinfo->lock);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 1736/1887 net: rds: fix uninitialized trans dereference in CM event handler
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aohan Mei <[email protected]>
commit 492ba6ac1b1ffb8a06ff52db0825c1af2cdb28c8 upstream.
rds_rdma_cm_event_handler_cmn() assigns trans only when the RDMA device is an InfiniBand CA (RDMA_NODE_IB_CA). On any other device type, e.g. an iWARP RNIC such as siw, trans stays uninitialized, but the event switch dereferences it: unconditionally in the RDMA_CM_EVENT_CONNECT_REQUEST case via trans->cm_handle_connect(), and (with a connection context) in the ROUTE_RESOLVED and ESTABLISHED cases.
An RDS listener on an iWARP device therefore crashes the kernel as soon as a connect request arrives: with CONFIG_INIT_STACK_ALL_ZERO the wild load becomes a NULL dereference at offset 0xa0 (&trans->cm_handle_connect) in the iw_cm_wq workqueue.
GCC masks the bug in default builds by folding the uninitialized load into &rds_ib_transport; Clang-built kernels take the real uninitialized path and oops.
The active side can land on a non-IB device too: the id that rds_ib_conn_path_connect() creates is not restricted to a node type, so rdma_resolve_addr() binds it to whichever device serves the local address, and an iWARP RNIC on the same netdev qualifies. The crash there is different: resolving a route on an iWARP id never fills in cm_id->route.path_rec, and the ROUTE_RESOLVED case writes path_rec[0].sl before it calls into the transport.
The iWARP transport was dropped long ago and IB is the only transport left, so make that explicit: initialize trans to &rds_ib_transport at declaration, drop the conditional assignment, reject a connect request that arrives on a non-IB device, and drop a connection whose address resolved to one instead of resolving a route on it. The rejection is limited to RDMA_CM_EVENT_CONNECT_REQUEST on purpose: a non-zero return from the handler makes rdma_cm destroy the id the event was delivered on, which is right for the request's freshly created id but would free a connection id that RDS still owns for any other event. On the active side the id stays ic->i_cm_id and the connection's shutdown destroys it, so that case returns 0.
[achender: reject only on RDMA_CM_EVENT_CONNECT_REQUEST instead of
bailing out for every event on a non-IB device, so that rdma_cm does not destroy connection ids RDS still tracks; drop a connection whose address resolved to a non-IB device before a route is resolved on it; changelog adjusted]
--- net/rds/rdma_transport.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
net/rds/rdma_transport.c +22 -4
@@ -52,7 +52,7 @@ static int rds_rdma_cm_event_handler_cmn {/* this can be null in the listening path */ struct rds_connection *conn = cm_id->context; -struct rds_transport *trans; +struct rds_transport *trans = &rds_ib_transport;int ret =0 ;int *err;u8 len;
@@ -60,9 +60,6 @@ static int rds_rdma_cm_event_handler_cmnrdsdebug ("conn %p id %p handling event %u (%s)\n" , conn, cm_id, event->event,rdma_event_msg (event->event)); -if (cm_id->device->node_type ==RDMA_NODE_IB_CA ) - trans = &rds_ib_transport; -/* Prevent shutdown from tearing down the connection * while we're executing. */ if (conn) {
@@ -82,11 +79,32 @@ static int rds_rdma_cm_event_handler_cmnswitch (event->event) {case RDMA_CM_EVENT_CONNECT_REQUEST : +/* Only the IB transport is supported, but RDS listens on +* every RDMA device: reject a request that arrived on any +* other kind. A non-zero return has rdma_cm destroy the +* request's id, which is what we want here and only here. +*/ +if (cm_id->device->node_type !=RDMA_NODE_IB_CA ) { + ret =1 ; +break ; + } ret = trans->cm_handle_connect (cm_id, event, isv6);break ;case RDMA_CM_EVENT_ADDR_RESOLVED :if (conn) { +/* The address resolved to a device RDS has no +* transport for. Do not go on to resolve a route: +* an iWARP route leaves cm_id->route.path_rec +* unset, which the ROUTE_RESOLVED case below +* dereferences. Drop the connection instead; the +* id is still ic->i_cm_id, so return 0 and let the +* shutdown destroy it. +*/ +if (cm_id->device->node_type !=RDMA_NODE_IB_CA ) { +rds_conn_drop (conn); +break ; + }rdma_set_service_type (cm_id, conn->c_tos);rdma_set_min_rnr_timer (cm_id,IB_RNR_TIMER_000_32 ); ret = rdma_resolve_route(cm_id,
Greg Kroah-Hartman
maintainerPATCH 1737/1887 pinctrl: amd: Clear S4 wake bits when firmware has _AEI
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit 1cca81a683da7f0ef2fbaf34442376044cbbad22 upstream.
Commit ffe8a0c6b552 ("pinctrl-amd: Don't clear S4 wake bits at probe") preserves firmware-programmed S4 wake sources because some PCIe devices rely on them for Wake-on-LAN. The system that motivated that change does not expose ACPI GPIO events through _AEI.
On a Chuwi CoreBook Plus, firmware exposes _AEI but also leaves the S4/S5 wake bit set for GPIO 24. This causes the machine to power back on immediately after shutdown even though Wake-on-LAN is not enabled.
GPIO register dumps show that the only relevant difference is bit 15 on GPIO 24. Clearing that bit makes the machine remain off. GPIO 24 is not itself listed in _AEI, so _AEI is not a per-pin indication of which pins the OS manages; it is a platform level signal of which wake model the firmware follows.
Use that signal to decide what to clear. Continue clearing S0i3/S3 bits on every system. Clear S4 bits when firmware exposes _AEI, indicating that the platform hands GPIO events to the OS, but preserve S4 bits when _AEI is absent so that firmware-programmed sources such as PCIe PME that bypass the GPIO IRQ wake API keep working.
A platform that exposes _AEI for some pins while routing a wake capable device through a raw GPIO not listed in _AEI would lose that wake source unless firmware re-arms it during the sleep transition. No such system has been reported.
--- drivers/pinctrl/pinctrl-amd.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/pinctrl/pinctrl-amd.c +9 -0
@@ -871,6 +871,15 @@ static void amd_gpio_irq_init(struct amd mask =BIT (WAKE_CNTRL_OFF_S0I3 ) |BIT (WAKE_CNTRL_OFF_S3 ); +#ifdef CONFIG_ACPI +/* +* Platforms without _AEI leave GPIO wake sources to firmware, so +* preserve their S4 wake bits. +*/ +if (acpi_has_method (ACPI_HANDLE (&gpio_dev->pdev->dev),"_AEI" )) + mask |=BIT (WAKE_CNTRL_OFF_S4 ); +#endif +for (i =0 ; i < desc->npins; i++) {int pin = desc->pins[i].number;const struct pin_desc *pd =pin_desc_get (gpio_dev->pctrl, pin);
Greg Kroah-Hartman
maintainerPATCH 1738/1887 sctp: revalidate output stream after association connect wait
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit b7ad72414c673ce1fa1f463e807cd4f34f8be9bf upstream.
When message interleaving is enabled, the first send waits for association establishment before building its data chunks. The wait drops the socket lock, and handshake processing can reduce the output stream count to the peer-advertised inbound stream count. sctp_stream_init() then frees the extension of every removed stream.
The sender resumes with the stream that it checked before the wait. If the peer removed that stream, sctp_outq_tail() later dereferences its NULL extension. Fatal-oops policies then panic the host.
KASAN: null-ptr-deref in range [0x38-0x3f] RIP: sctp_outq_tail+0x49e/0xaa0 Call Trace: sctp_primitive_SEND sctp_sendmsg_to_asoc sctp_sendmsg
A range check alone is insufficient. Stream reconfiguration can grow the output count again while the lock is released without recreating extensions freed by the earlier shrink. The stream can then be in range while its extension remains NULL. The send-buffer wait has the same issue.
Factor the range and extension checks into a helper and repeat both after each send-path wait that drops the socket lock. Once the lock is reacquired, the validation remains stable through data creation and queueing.
If validation fails after the connect wait, the auto-created association is already established. Return ESRCH so the existing caller path keeps it under state-machine ownership instead of freeing it directly, which would leave protocol, counter and socket state inconsistent.
--- net/sctp/socket.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-)
net/sctp/socket.c +21 -12
@@ -1784,6 +1784,18 @@ static int sctp_sendmsg_check_sflags(strreturn 1 ; } +static int sctp_sendmsg_check_stream (struct sctp_association *asoc, +struct sctp_sndrcvinfo *sinfo) +{ +if (unlikely (sinfo->sinfo_stream >= asoc->stream.outcnt)) +return -EINVAL ; + +if (unlikely (!SCTP_SO (&asoc->stream, sinfo->sinfo_stream)->ext)) +return sctp_stream_init_ext (&asoc->stream, sinfo->sinfo_stream); + +return 0 ; +} + static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, struct msghdr *msg, size_t msg_len, struct sctp_transport *transport,
@@ -1798,16 +1810,9 @@ static int sctp_sendmsg_to_asoc(struct slong timeo;int err; -if (sinfo->sinfo_stream >= asoc->stream.outcnt) { - err = -EINVAL ; + err =sctp_sendmsg_check_stream (asoc, sinfo); +if (err) goto err; - } - -if (unlikely (!SCTP_SO (&asoc->stream, sinfo->sinfo_stream)->ext)) { - err =sctp_stream_init_ext (&asoc->stream, sinfo->sinfo_stream); -if (err) - goto err; - }if (sp->disable_fragments && msg_len > asoc->frag_point) { err = -EMSGSIZE ;
@@ -1828,10 +1833,9 @@ static int sctp_sendmsg_to_asoc(struct s err =sctp_wait_for_sndbuf (asoc, transport, &timeo, msg_len);if (err) goto err; -if (unlikely (sinfo->sinfo_stream >= asoc->stream.outcnt)) { - err = -EINVAL ; + err =sctp_sendmsg_check_stream (asoc, sinfo); +if (err) goto err; - } }if (sctp_state (asoc,CLOSED )) {
@@ -1846,6 +1850,11 @@ static int sctp_sendmsg_to_asoc(struct s err = -ESRCH ; goto err; } + err =sctp_sendmsg_check_stream (asoc, sinfo); +if (err) { + err = -ESRCH ; + goto err; + } }else { wait_connect = true; }
Greg Kroah-Hartman
maintainerPATCH 1739/1887 tools: gpio: fix building from the top level with O=
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sasha Levin <[email protected]>
commit 52336337f1a01ad803c7f3ddb23f40222e9ad58d upstream.
"make O=<dir> tools/gpio" fails:
Makefile:27: /tools/build/Makefile.include: No such file or directory
tools/Makefile clears srctree, and the gpio Makefile only works it out again when building_out_of_srctree is not set, which the top-level Makefile sets for O= builds.
Also work out srctree when it is empty, as tools/bpf/Makefile does since commit a89b2cbf71d64 ("tools, bpf: Fix build for 'make -s tools/bpf O=<dir>'").
--- tools/gpio/Makefile | 6 ++++++ 1 file changed, 6 insertions(+)
tools/gpio/Makefile +6 -0
@@ -7,7 +7,13 @@ bindir ?= /usr/bin # isn't set and when invoked from selftests build, where srctree # is set to ".". building_out_of_srctree is undefined for in srctree # builds +ifeq ($(srctree),) +update_srctree := 1 +endif ifndef building_out_of_srctree +update_srctree := 1 +endif +ifeq ($(update_srctree),1) srctree := $(patsubst %/,%,$(dir $(CURDIR))) srctree := $(patsubst %/,%,$(dir $(srctree))) endif
Greg Kroah-Hartman
maintainerPATCH 1740/1887 i2c: qcom-cci: Fix HALT_ACK reset request being dropped
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Loic Poulain <[email protected]>
commit 195f3d74b5de98969dc4fad956393bb00787efd1 upstream.
A HALT_ACK interrupt indicates that the corresponding I2C master has entered the halted state and must be reset before further operation.
The M0 and M1 HALT_ACK status bits may be asserted simultaneously in a single interrupt. However, the interrupt handler currently overwrites the reset mask when processing each HALT_ACK condition, causing the first reset request to be lost if both events are reported together.
Accumulate reset requests instead of overwriting them so that both masters are properly reset when M0 and M1 HALT_ACK events occur in the same interrupt.
--- drivers/i2c/busses/i2c-qcom-cci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/i2c/busses/i2c-qcom-cci.c +2 -2
@@ -168,12 +168,12 @@ static irqreturn_t cci_isr(int irq, void }if (unlikely (val &CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK )) { - reset =CCI_RESET_CMD_M0_MASK ; + reset |=CCI_RESET_CMD_M0_MASK ; ret =IRQ_HANDLED ; }if (unlikely (val &CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK )) { - reset =CCI_RESET_CMD_M1_MASK ; + reset |=CCI_RESET_CMD_M1_MASK ; ret =IRQ_HANDLED ; }
Greg Kroah-Hartman
maintainerPATCH 1741/1887 scsi: xen/scsifront: Check for a NULL shadow entry on a backend response
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
commit 8c8222c255772713eb36cde695777a1fce224917 upstream.
scsifront_do_response() validates the rqid in a backend response against VSCSIIF_MAX_REQS before using it to index info->shadow[], but then dereferences the entry to test ->inflight without checking that the slot is populated. Shadow slots are NULL before a command is submitted (the host private area is zeroed at allocation) and are reset to NULL in _scsifront_put_rqid() once a request completes, so an in-range rqid that does not correspond to an outstanding request makes the frontend dereference a NULL pointer.
A malicious or buggy backend can thus crash the guest by returning a response whose rqid is in range but not in flight -- for example a spurious response before any command has been issued, or a duplicate of one already completed. The ring has only VSCSIIF_MAX_REQS (16) slots, so before the first command every in-range rqid selects a NULL slot.
Reject a response whose shadow slot is not populated.
--- drivers/scsi/xen-scsifront.c | 1 + 1 file changed, 1 insertion(+)
drivers/scsi/xen-scsifront.c +1 -0
@@ -367,6 +367,7 @@ static void scsifront_do_response(structstruct vscsifrnt_shadow *shadow;if (ring_rsp->rqid >=VSCSIIF_MAX_REQS || + !info->shadow[ring_rsp->rqid] || !info->shadow[ring_rsp->rqid]->inflight) {scsifront_set_error (info,"illegal rqid returned by backend!" );return ;
Greg Kroah-Hartman
maintainerPATCH 1742/1887 scsi: libiscsi: Reject a negative task index from parse_pdu_itt
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
commit 8ee2a09a1dbb257c9e828ad2497f8e4832dfb142 upstream.
A transport that implements parse_pdu_itt hands libiscsi an index taken from the PDU, and both lookups bound it from above only:
if (i >= session->cmds_max)
i and cmds_max are both int, so a negative index passes and session->cmds[i] is read from before the array.
be2iscsi produces one. beiscsi_parse_pdu() assigns the raw tag,
*index = (int)itt;
and beiscsi_complete_pdu() forwards an unsolicited NOP-In from the hardware async ring without replacing its ITT, so the value is the target's. It also reports the session's own age rather than the one in the tag, which leaves the age comparison in iscsi_verify_itt() with nothing to reject.
Bound the index from below in both lookups.
--- drivers/scsi/libiscsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/libiscsi.c +2 -2
@@ -1191,7 +1191,7 @@ struct iscsi_task *iscsi_itt_to_task(str session->tt->parse_pdu_itt (conn, itt, &i,NULL ); else i =get_itt (itt); -if (i >= session->cmds_max) +if (i <0 || i >= session->cmds_max)return NULL ;return session->cmds[i];
@@ -1384,7 +1384,7 @@ int iscsi_verify_itt(struct iscsi_conn *return ISCSI_ERR_BAD_ITT ; } -if (i >= session->cmds_max) { +if (i <0 || i >= session->cmds_max) {iscsi_conn_printk (KERN_ERR , conn,"received invalid itt index %u (max cmds " "%u.\n" , i, session->cmds_max);
Greg Kroah-Hartman
maintainerPATCH 1743/1887 scsi: libiscsi: Validate the ITT reflected in a Reject PDU
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
commit c5958c770b2a0ee492414e26b07da9164a0d1f5d upstream.
A Reject PDU carries a copy of the header it rejects, and iscsi_handle_reject() takes the ITT out of that copy to find the task to clean up:
memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
...
task = iscsi_itt_to_task(conn, rejected_pdu.itt);That value is whatever the target put there. iscsi_itt_to_task() bounds the index against cmds_max and checks nothing else, so any task in the pool can be named, and iscsi_nop_out_rsp() then completes it.
An index that has never been used gives a NULL task->conn: the pool is zeroed at session setup and conn is assigned only when a task is allocated. If the task was used and returned, iscsi_complete_task() hits its WARN_ON_ONCE(task->state == ISCSI_TASK_FREE) and the refcount underflows. An in-flight SCSI command is completed as successful - a 1 MiB read returned 1048576 with none of its buffer written and no warning.
Validate the reflected ITT the way iscsi_itt_to_ctask() validates a command ITT, and require the task to be in flight and not a SCSI command.
[ 6.248477] Oops: general protection fault, probably for non-canonical address 0xdffffc000000000c: 0000 [#1] SMP KASAN NOPTI [ 6.249357] KASAN: null-ptr-deref in range [0x0000000000000060-0x0000000000000067] [ 6.249951] CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Not tainted 7.2.0-rc5-ISCSI1-gf5098b6bae76 #1 PREEMPT(lazy) [ 6.250718] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 6.251616] RIP: 0010:iscsi_nop_out_rsp.constprop.0+0x46/0x160 [ 6.252043] Code: c1 ea 03 48 83 ec 08 80 3c 02 00 0f 85 f5 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 8b 6b 58 48 8d 7d 60 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 c0 00 00 00 48 8b 45 60 48 39 c3 74 50 48 b8 00 [ 6.252813] RSP: 0018:ffff88806c907b80 EFLAGS: 00010206 [ 6.253042] RAX: dffffc0000000000 RBX: ffff88800607e000 RCX: ffffffff8d571a25 [ 6.253345] RDX: 000000000000000c RSI: ffff88806c907c38 RDI: 0000000000000060 [ 6.253642] RBP: 0000000000000000 R08: 0000000000000000 R09: fffffbfff235a504 [ 6.253947] R10: 0000000000000003 R11: 7463656e6e6f6320 R12: 0000000000000000 [ 6.254251] R13: 0000000000000000 R14: ffff88806c907c38 R15: 0000000000000000 [ 6.254549] FS: 0000000000000000(0000) GS:ffff8880d95bc000(0000) knlGS:0000000000000000 [ 6.254887] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 6.255140] CR2: 00007fc393e8ffc0 CR3: 0000000005252006 CR4: 0000000000770ef0 [ 6.255439] PKRU: 55555554 [ 6.255564] Call Trace: [ 6.255674] <IRQ> [ 6.255768] __iscsi_complete_pdu+0x18bf/0x22a0 [ 6.256733] iscsi_complete_pdu+0x54/0xa0 [ 6.256905] iscsi_tcp_data_recv_done+0xf4/0x250 [ 6.257103] iscsi_tcp_recv_skb+0x31e/0xec0 [ 6.257680] iscsi_sw_tcp_recv+0x12f/0x390 [ 6.258061] __tcp_read_sock+0x1ab/0x810 [ 6.258853] iscsi_sw_tcp_data_ready+0x18b/0x510 [ 6.259808] tcp_data_queue+0x1f13/0x4cd0 [ 6.260567] tcp_rcv_established+0x8a5/0x3a00 [ 6.261931] tcp_v4_do_rcv+0x449/0x960 [ 6.262269] tcp_v4_rcv+0x2245/0x3bc0
--- drivers/scsi/libiscsi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/scsi/libiscsi.c +5 -3
@@ -1142,13 +1142,15 @@ static int iscsi_handle_reject(struct isspin_unlock (&conn->session->frwd_lock);spin_lock (&conn->session->back_lock); }else { -struct iscsi_task *task; +struct iscsi_task *task =NULL ;/* * Our nop as ping got dropped. We know the target * and transport are ok so just clean up */ - task =iscsi_itt_to_task (conn, rejected_pdu.itt); -if (!task) { +if (!iscsi_verify_itt (conn, rejected_pdu.itt)) + task =iscsi_itt_to_task (conn, rejected_pdu.itt); +if (!task || task->state ==ISCSI_TASK_FREE || + task->sc) {iscsi_conn_printk (KERN_ERR , conn,"Invalid pdu reject. Could " "not lookup rejected task.\n" );
Greg Kroah-Hartman
maintainerPATCH 1744/1887 scsi: libiscsi: Validate the task named by a management response
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
commit 11bffcd9cb346732eab2914ef44fe777a3f0b585 upstream.
__iscsi_complete_pdu() fetches the task for five response types from one place and checks only that the index resolved:
case ISCSI_OP_LOGOUT_RSP:
case ISCSI_OP_LOGIN_RSP:
case ISCSI_OP_TEXT_RSP:
case ISCSI_OP_SCSI_TMFUNC_RSP:
case ISCSI_OP_NOOP_IN:
task = iscsi_itt_to_task(conn, hdr->itt);
if (!task)
return ISCSI_ERR_BAD_ITT;iscsi_itt_to_task() bounds the index against cmds_max and looks at nothing else, so a target can name any slot in the pool, including one that has never been used. task->conn is then NULL, and both iscsi_nop_out_rsp() and iscsi_complete_task() dereference it. One unsolicited NOP-In is enough; a Text Response carrying the same ITT crashes in iscsi_complete_task() instead.
Require the task to be in flight and not a SCSI command, the way iscsi_itt_to_ctask() does for the command opcodes.
[ 6.298634] Oops: general protection fault, probably for non-canonical address 0xdffffc000000000c: 0000 [#1] SMP KASAN NOPTI [ 6.298642] KASAN: null-ptr-deref in range [0x0000000000000060-0x0000000000000067] [ 6.298652] CPU: 1 UID: 0 PID: 111 Comm: iscsistart Not tainted 7.2.0-rc5-ISCSI1-gf5098b6bae76 #1 PREEMPT(lazy) [ 6.298654] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 6.298656] RIP: 0010:iscsi_nop_out_rsp.constprop.0+0x46/0x160 [ 6.298691] Code: c1 ea 03 48 83 ec 08 80 3c 02 00 0f 85 f5 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 8b 6b 58 48 8d 7d 60 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 c0 00 00 00 48 8b 45 60 48 39 c3 74 50 48 b8 00 [ 6.298698] RSP: 0018:ffff88806c907be8 EFLAGS: 00010206 [ 6.298701] RAX: dffffc0000000000 RBX: ffff888006116800 RCX: 0000000000000020 [ 6.298702] RDX: 000000000000000c RSI: ffff88800525d578 RDI: 0000000000000060 [ 6.298703] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 [ 6.298706] R10: 0000000000000020 R11: 0000000000000000 R12: 0000000000000000 [ 6.298706] R13: 000000000000002e R14: ffff8880056eb440 R15: ffff888006116800 [ 6.298707] FS: 00007fc02d1c2740(0000) GS:ffff8880b29bc000(0000) knlGS:0000000000000000 [ 6.298710] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 6.298711] CR2: 000055fe3b56ddf8 CR3: 00000000053b9004 CR4: 0000000000770ef0 [ 6.298712] PKRU: 55555554 [ 6.298713] Call Trace: [ 6.298714] <IRQ> [ 6.298714] __iscsi_complete_pdu+0x13a8/0x22a0 [ 6.298758] iscsi_complete_pdu+0x54/0xa0 [ 6.298759] iscsi_tcp_hdr_recv_done+0x870/0x2c80 [ 6.298778] iscsi_tcp_recv_skb+0x31e/0xec0 [ 6.298800] iscsi_sw_tcp_recv+0x12f/0x390 [ 6.298804] __tcp_read_sock+0x1ab/0x810 [ 6.298812] iscsi_sw_tcp_data_ready+0x18b/0x510 [ 6.298814] tcp_rcv_established+0x1f56/0x3a00 [ 6.298842] tcp_v4_do_rcv+0x449/0x960 [ 6.298847] tcp_v4_rcv+0x2245/0x3bc0
--- drivers/scsi/libiscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/libiscsi.c +1 -1
@@ -1286,7 +1286,7 @@ int __iscsi_complete_pdu(struct iscsi_cocase ISCSI_OP_SCSI_TMFUNC_RSP :case ISCSI_OP_NOOP_IN : task =iscsi_itt_to_task (conn, hdr->itt); -if (!task) +if (!task || task->state ==ISCSI_TASK_FREE || task->sc)return ISCSI_ERR_BAD_ITT ;break ;default :
Greg Kroah-Hartman
maintainerPATCH 1745/1887 drm/amdgpu/sdma3: Work around POLL_REGMEM / FENCE hang
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
commit 752480ad62964edf0254e151110d3e53a7cb37de upstream.
SDMA can randomly hang on Polaris 10. Hard to reproduce, but has been occurring sporadically in the Mesa CI on the RADV Polaris 10 job even when Mesa isn't using the SDMA engine.
When Mesa actually uses the SDMA on Polaris, the hang becomes more frequent and the reproduction rate goes up significantly in the CI system.
We don't know why the hangs occur, but it seems that inserting a single NOP packet before each POLL_REGMEM and FENCE packet works around it. At the moment it's unclear which GPUs are affected, so let's apply this to SDMA 3.x for now.
Note that this issue is not documented or acknowledged by AMD.
--- drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +21 -4
@@ -460,6 +460,9 @@ static void sdma_v3_0_ring_emit_hdp_fluselse ref_and_mask =REG_SET_FIELD (ref_and_mask,GPU_HDP_FLUSH_DONE ,SDMA1 ,1 ); +/* Hang workaround */ +amdgpu_ring_write (ring,SDMA_PKT_NOP_HEADER_OP (SDMA_OP_NOP )); +amdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_POLL_REGMEM ) |SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH (1 ) |SDMA_PKT_POLL_REGMEM_HEADER_FUNC (3 ));/* == */
@@ -487,6 +490,10 @@ static void sdma_v3_0_ring_emit_fence(st unsigned flags) {bool write64bit = flags &AMDGPU_FENCE_FLAG_64BIT ; + +/* Hang workaround */ +amdgpu_ring_write (ring,SDMA_PKT_NOP_HEADER_OP (SDMA_OP_NOP )); +/* write the fence */ amdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ));amdgpu_ring_write (ring,lower_32_bits (addr));
@@ -495,7 +502,11 @@ static void sdma_v3_0_ring_emit_fence(st/* optionally write high bits as well */ if (write64bit) { +/* Hang workaround */ +amdgpu_ring_write (ring,SDMA_PKT_NOP_HEADER_OP (SDMA_OP_NOP )); + addr +=4 ; +amdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ));amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));
@@ -1043,6 +1054,9 @@ static void sdma_v3_0_ring_emit_pipelineuint32_t seq = ring->fence_drv.sync_seq;uint64_t addr = ring->fence_drv.gpu_addr; +/* Hang workaround */ +amdgpu_ring_write (ring,SDMA_PKT_NOP_HEADER_OP (SDMA_OP_NOP )); +/* wait for idle */ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH(0) |
@@ -1071,6 +1085,9 @@ static void sdma_v3_0_ring_emit_vm_flush {amdgpu_gmc_emit_flush_gpu_tlb (ring, vmid, pd_addr); +/* Hang workaround */ +amdgpu_ring_write (ring,SDMA_PKT_NOP_HEADER_OP (SDMA_OP_NOP )); +/* wait for flush */ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH(0) |
@@ -1579,11 +1596,11 @@ static const struct amdgpu_ring_funcs sd .get_wptr = sdma_v3_0_ring_get_wptr, .set_wptr = sdma_v3_0_ring_set_wptr, .emit_frame_size = -6 +/* sdma_v3_0_ring_emit_hdp_flush */ +6 +1 +/* sdma_v3_0_ring_emit_hdp_flush */ 3 +/* hdp invalidate */ -6 +/* sdma_v3_0_ring_emit_pipeline_sync */ -VI_FLUSH_GPU_TLB_NUM_WREG *3 +6 +/* sdma_v3_0_ring_emit_vm_flush */ - 10 + 10 + 10, /* sdma_v3_0_ring_emit_fence x3 for user fence, vm fence */ +6 +1 +/* sdma_v3_0_ring_emit_pipeline_sync */ +VI_FLUSH_GPU_TLB_NUM_WREG *3 +6 +1 +/* sdma_v3_0_ring_emit_vm_flush */ + (10 + 1) * 3, /* sdma_v3_0_ring_emit_fence x3 for user fence, vm fence */ .emit_ib_size = 7 + 6, /* sdma_v3_0_ring_emit_ib */ .emit_ib = sdma_v3_0_ring_emit_ib, .emit_fence = sdma_v3_0_ring_emit_fence,
Greg Kroah-Hartman
maintainerPATCH 1746/1887 drm/amdgpu: dont drop the runtime PM reference twice in amdgpu_gpr
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesse Zhang <[email protected]>
commit de9f6bcdb44f0e410031002e2f103826ea6b6259 upstream.
amdgpu_debugfs_gpr_read() drops its runtime PM reference right after reading the wave registers. When copying them to userspace fails, it jumps to the err label, which drops the reference a second time. A read into a bad buffer on Navi31 either steals a reference somebody else holds (power/runtime_usage goes from 1 to 0) or underflows the count:
amdgpu 0000:03:00.0: Runtime PM usage count underflow!
The registers are already in the kernel buffer at that point, so finish the hardware access first and copy the buffer with a single copy_to_user() instead of the put_user() loop with its own error path.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +3 -18
@@ -997,7 +997,6 @@ static ssize_t amdgpu_debugfs_gpr_read(s {struct amdgpu_device *adev = f->f_inode->i_private;int r; -ssize_t result =0 ;uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data;if (size >4096 || size &3 || *pos &3 )
@@ -1042,25 +1041,11 @@ static ssize_t amdgpu_debugfs_gpr_read(spm_runtime_mark_last_busy (adev_to_drm (adev)->dev);pm_runtime_put_autosuspend (adev_to_drm (adev)->dev); +amdgpu_virt_disable_access_debugfs (adev); -while (size) { -uint32_t value; - - value = data[result >>2 ]; - r =put_user (value, (uint32_t *)buf); -if (r) { -amdgpu_virt_disable_access_debugfs (adev); - goto err; - } - - result +=4 ; - buf +=4 ; - size -=4 ; - } - + r =copy_to_user (buf, data, size) ? -EFAULT : size;kfree (data); -amdgpu_virt_disable_access_debugfs (adev); -return result; +return r; err:pm_runtime_put_autosuspend (adev_to_drm (adev)->dev);
Greg Kroah-Hartman
maintainerPATCH 1747/1887 tracing: Fix the shift out of bounds in the log2 histogram modifier
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
commit 647c2f97fcb94bc642cefe6db004999974563f06 upstream.
The .log2 key modifier files a value under its base-2 order:
# echo 'hist:keys=bytes_req.log2' > events/kmem/kmalloc/trigger
hist_field_log2() computes that as ilog2(roundup_pow_of_two(val)). The out-of-line form of roundup_pow_of_two() is
return 1UL << fls_long(n - 1);
which shifts by 64 on a 64-bit kernel both when n is 0, where n - 1 wraps to ULONG_MAX, and when n is above 2^63. Both are ordinary keys, because the field fetch hands every value over as a u64: a syscall argument of 0 reaches the first, and one above 2^63 reaches the second.
Keying sys_enter_lseek on offset.log2 and passing 0, 1, 2, 3, 1000, 2^63+1 and U64_MAX gives
{ offset: ~ 2^1 } hitcount: 1
{ offset: ~ 2^10 } hitcount: 1
{ offset: ~ 2^2 } hitcount: 1
{ offset: ~ 2^0 } hitcount: 4Keys above 2^63 land in the lowest bucket. With CONFIG_UBSAN_SHIFT=y the shift is also reported:
UBSAN: shift-out-of-bounds in include/linux/log2.h:57:13 shift exponent 64 is too large for 64-bit type 'long unsigned int' __ubsan_handle_shift_out_of_bounds.cold+0xdd/0x1cb hist_fn_call.cold+0x8b/0xd9 event_hist_trigger+0x1cc/0x790 ftrace_syscall_enter+0x197/0x360 do_syscall_64+0x402/0x4b0
Use order_base_2(), which is ilog2(n - 1) + 1 for n > 1 and 0 below that. It returns what the old expression returned on every input the old one was defined for. Where it was not, 0 stays in bucket 0, which is where x86_64 had been putting it, and the keys above 2^63 move into bucket 64.
--- kernel/trace/trace_events_hist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_events_hist.c +1 -1
@@ -281,7 +281,7 @@ static u64 hist_field_log2(struct hist_fu64 val =hist_fn_call (operand, elt, buffer, rbe, event); -return (u64 )ilog2 (roundup_pow_of_two (val)); +return order_base_2 (val); } static u64 hist_field_bucket(struct hist_field *hist_field,
Greg Kroah-Hartman
maintainerPATCH 1748/1887 tracing: Do not initialize tracefs work if tracing is disabled
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amit Machhiwal <[email protected]>
commit b3b974008388ab59e44d764ba7a63c988fec2524 upstream.
If trace buffer allocation fails during early boot (e.g. in early_trace_init() -> allocate_trace_buffers()), tracing_disabled is left set to 1 and the global trace array events list remains uninitialized.
Later during boot, tracer_init_tracefs() (invoked via fs_initcall) queues tracerfs_init_work asynchronously without checking if tracing was disabled. When tracer_init_tracefs_work_func() runs, it calls event_trace_init() and init_tracer_tracefs(&global_trace, NULL) unconditionally. This leads to __find_event_file() dereferencing an uninitialized tr->events list, causing an early boot NULL pointer dereference Oops:
BUG: Kernel NULL pointer dereference on read at 0x00000010 Faulting instruction address: 0xc000000000485be0 Oops: Kernel access of bad area, sig: 7 [#1] ... NIP [c000000000485be0] __find_event_file+0x70/0x3c0 LR [c000000000448874] init_tracer_tracefs+0x274/0xc80 Call Trace: init_tracer_tracefs+0x274/0xc80 tracer_init_tracefs_work_func+0x50/0x320 process_one_work+0x1e8/0x5c0 worker_thread+0x1dc/0x3d0 kthread+0x194/0x1b0 start_kernel_thread+0x14/0x18
Check tracing_disabled at the beginning of tracer_init_tracefs_work_func() and return immediately if tracing is disabled or failed to initialize, preventing the crash.
--- kernel/trace/trace.c | 6 ++++++ 1 file changed, 6 insertions(+)
kernel/trace/trace.c +6 -0
@@ -10005,6 +10005,12 @@ static struct notifier_block trace_modulstatic __init void tracer_init_tracefs_work_func (struct work_struct *work) { +/* +* Do not attempt to initialize tracefs if tracing was disabled or +* failed to allocate +*/ +if (tracing_disabled) +return ;event_trace_init ();
Greg Kroah-Hartman
maintainerPATCH 1749/1887 tracing: Fix hist trigger timestamps for buffered events
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tengda Wu <[email protected]>
commit 9414ca3b99e5a7f1f3bf51c2a01b383e1b355dd0 upstream.
Syzkaller triggered a WARN_ON_ONCE(!nest) warning:
WARNING: kernel/trace/ring_buffer.c:821 at ring_buffer_event_time_stamp
Call trace:
ring_buffer_event_time_stamp
hist_field_timestamp
hist_fn_call
event_hist_trigger
event_triggers_call
__event_trigger_test_discard
trace_event_buffer_commit
do_trace_event_raw_event_sched_switch
trace_event_raw_event_sched_switchThe warning is probabilistically reproducible and is related to syzkaller executing the following commands:
echo 'prev_pid == 999999' > events/sched/sched_switch/filter echo 'hist:keys=common_timestamp' > events/sched/sched_switch/trigger
The specific triggering process is as follows:
CPU 0 CPU 1
(context switching) (echo 'hist:keys=common_timestamp' > \
events/sched/sched_switch/trigger)
do_trace_event_raw_event_##call
trace_event_buffer_lock_reserve
if (!tr->no_filter_buffering_ref &&
trace_file->flags & EVENT_FILE_FL_FILTERED)
return entry; // return directly
event_hist_trigger_parse
hist_register_trigger
tracing_set_filter_buffering(file->tr, true);
tr->no_filter_buffering_ref++;
__trace_buffer_lock_reserve
rb_start_commit
local_inc(&cpu_buffer->committing); // skipped and not executed trace_event_buffer_commit
__event_trigger_test_discard
event_triggers_call
event_hist_trigger
hist_fn_call
hist_field_timestamp
ring_buffer_event_time_stamp
nest = local_read(&cpu_buffer->committing); WARN_ON_ONCE(!nest) // trigger warning
The root cause is that when an event file has a filter attached and the hist trigger has not yet been attached, trace_event_buffer_lock_reserve() writes the event into the per-CPU trace_buffered_event temp buffer instead of reserving it in the ring buffer, so cpu_buffer->committing is not incremented. When the event is later processed at commit time by a hist trigger, hist_field_timestamp() -> ring_buffer_event_time_stamp() sees a zero committing count, triggering WARN_ON_ONCE(!nest).
tracing_event_time_stamp() was added by commit d8279bfc5e959 ("tracing:
Add tracing_event_time_stamp() API") for exactly this case: if the event is the per-CPU trace_buffered_event, it returns the current ring buffer timestamp. But it never gained a caller. Use it in hist_field_timestamp(), so that a hist trigger that races onto a buffered event records the current time, which is only marginally later than when the event was recorded, instead of warning and recording a bogus timestamp.
--- kernel/trace/trace_events_hist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_events_hist.c +1 -1
@@ -863,7 +863,7 @@ static u64 hist_field_timestamp(struct hstruct hist_trigger_data *hist_data = hist_field->hist_data;struct trace_array *tr = hist_data->event_file->tr; -u64 ts =ring_buffer_event_time_stamp (buffer, rbe); +u64 ts =tracing_event_time_stamp (buffer, rbe);if (hist_data->attrs->ts_in_usecs &&trace_clock_in_ns (tr)) ts =ns2usecs (ts);
Greg Kroah-Hartman
maintainerPATCH 1750/1887 wifi: p54: validate firmware record lengths
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heyang Tan <[email protected]>
commit db7b86bd97b380ece8fa39cfdd7502a9fd35e56f upstream.
The p54 firmware parser accesses component ID and component version records without checking that their lengths cover the fields being read. A malformed record can therefore make the parser read past the record.
Validate the component ID and component version record lengths before accessing their data. The descriptor record is also checked against the shortest descriptor length found in the supported firmware images.
Reject descriptor values that underflow the RX offset or produce an empty RX range before updating the driver state.
--- drivers/net/wireless/intersil/p54/fwio.c | 42 +++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 5 deletions(-)
drivers/net/wireless/intersil/p54/fwio.c +37 -5
@@ -52,6 +52,13 @@ int p54_parse_firmware(struct ieee80211_u32 code =le32_to_cpu (bootrec->code);switch (code) {case BR_CODE_COMPONENT_ID : +if (len <sizeof (struct bootrec_comp_id ) / +sizeof (*bootrec->data)) { +wiphy_err (priv->hw->wiphy, +"firmware component ID is too short\n" ); +return -EINVAL ; + } + priv->fw_interface =be32_to_cpup ((__be32 *) bootrec->data);switch (priv->fw_interface) {
@@ -72,16 +79,41 @@ int p54_parse_firmware(struct ieee80211_ }break ;case BR_CODE_COMPONENT_VERSION : +if (len <DIV_ROUND_UP (sizeof (struct bootrec_comp_ver ), +sizeof (*bootrec->data))) { +wiphy_err (priv->hw->wiphy, +"firmware component version is too short\n" ); +return -EINVAL ; + } +/* 24 bytes should be enough for all firmwares */ -if (strnlen ((unsigned char *) bootrec->data,24 ) <24 ) - fw_version = (unsigned char *) bootrec->data; +if (strnlen ((unsigned char *)bootrec->data, +sizeof (struct bootrec_comp_ver )) < +sizeof (struct bootrec_comp_ver )) + fw_version = (unsigned char *)bootrec->data;break ;case BR_CODE_DESCR : {struct bootrec_desc *desc = (struct bootrec_desc *)bootrec->data; - priv->rx_start =le32_to_cpu (desc->rx_start); -/* FIXME add sanity checking */ - priv->rx_end =le32_to_cpu (desc->rx_end) -0x3500 ; +u32 rx_start, rx_end; + +/* 0xa is the shortest descriptor in supported firmware. */ +if (len <0xa ) { +wiphy_err (priv->hw->wiphy, +"firmware descriptor is too short\n" ); +return -EINVAL ; + } + + rx_start =le32_to_cpu (desc->rx_start); + rx_end =le32_to_cpu (desc->rx_end); +if (rx_end <0x3500 || rx_end -0x3500 <= rx_start) { +wiphy_err (priv->hw->wiphy, +"firmware descriptor has invalid RX range\n" ); +return -EINVAL ; + } + + priv->rx_start = rx_start; + priv->rx_end = rx_end -0x3500 ; priv->headroom = desc->headroom; priv->tailroom = desc->tailroom; priv->privacy_caps = desc->privacy_caps;
Greg Kroah-Hartman
maintainerPATCH 1751/1887 tcp: fix use-after-free in do_tcp_getsockopt(TCP_CONGESTION)
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft Security FORGE Labs) <[email protected]>
commit 5271b79b7ad68dcb222e893773f92bdabf7750f3 upstream.
do_tcp_getsockopt() reads icsk->icsk_ca_ops->name without holding rcu_read_lock(). Since commit 0baf26b0fcd7 ("bpf: tcp: Support tcp_congestion_ops in bpf"), icsk_ca_ops can point to dynamically allocated BPF struct_ops memory that may be freed concurrently via setsockopt(TCP_CONGESTION), leading to a use-after-free.
BUG: KASAN: slab-use-after-free in _copy_to_user+0x37/0x60 Read of size 16 at addr ffff888013505260 by task exploit/149 _copy_to_user+0x37/0x60 do_tcp_getsockopt+0x158a/0x2460 (net/ipv4/tcp.c:4585) tcp_getsockopt+0x91/0xf0 __sys_getsockopt+0xf7/0x170
Fix this by holding rcu_read_lock() around the ca_ops->name access, using READ_ONCE() to load icsk_ca_ops, and copying the name to a stack buffer before releasing the lock. Also annotate the relevant icsk_ca_ops stores with WRITE_ONCE() to fix the accompanying KCSAN data-race issue.
--- net/ipv4/tcp.c | 14 +++++++++++--- net/ipv4/tcp_cong.c | 4 ++-- net/ipv4/tcp_dctcp.c | 2 +- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_output.c | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-)
net/ipv4/tcp.c +11 -3
@@ -4224,16 +4224,24 @@ int do_tcp_getsockopt(struct sock *sk, i val = !inet_csk_in_pingpong_mode (sk);break ; -case TCP_CONGESTION : +case TCP_CONGESTION : { +char ca_name[TCP_CA_NAME_MAX ] = {}; +if (copy_from_sockptr (&len, optlen,sizeof (int )))return -EFAULT ; len = min_t(unsigned int, len, TCP_CA_NAME_MAX);if (copy_to_sockptr (optlen, &len,sizeof (int )))return -EFAULT ; -if (copy_to_sockptr (optval, icsk->icsk_ca_ops->name, len)) + +rcu_read_lock (); +memcpy (ca_name,READ_ONCE (icsk->icsk_ca_ops)->name, +sizeof (ca_name)); +rcu_read_unlock (); + +if (copy_to_sockptr (optval, ca_name, len))return -EFAULT ;return 0 ; - + }case TCP_ULP :if (copy_from_sockptr (&len, optlen,sizeof (int )))return -EFAULT ;
net/ipv4/tcp_cong.c +2 -2
@@ -174,7 +174,7 @@ void tcp_assign_congestion_control(struc ca =rcu_dereference (net->ipv4.tcp_congestion_control);if (unlikely (!bpf_try_module_get (ca, ca->owner))) ca = &tcp_reno; - icsk->icsk_ca_ops = ca; +WRITE_ONCE (icsk->icsk_ca_ops, ca);rcu_read_unlock ();memset (icsk->icsk_ca_priv,0 ,sizeof (icsk->icsk_ca_priv));
@@ -204,7 +204,7 @@ static void tcp_reinit_congestion_controstruct inet_connection_sock *icsk =inet_csk (sk);tcp_cleanup_congestion_control (sk); - icsk->icsk_ca_ops = ca; +WRITE_ONCE (icsk->icsk_ca_ops, ca); icsk->icsk_ca_setsockopt =1 ;memset (icsk->icsk_ca_priv,0 ,sizeof (icsk->icsk_ca_priv));
net/ipv4/tcp_dctcp.c +1 -1
@@ -108,7 +108,7 @@ static void dctcp_init(struct sock *sk)/* No ECN support? Fall back to Reno. Also need to clear * ECT from sk since it is set during 3WHS for DCTCP. */ -inet_csk (sk)->icsk_ca_ops = &dctcp_reno; +WRITE_ONCE (inet_csk (sk)->icsk_ca_ops, &dctcp_reno);INET_ECN_dontxmit (sk); }
net/ipv4/tcp_minisocks.c +1 -1
@@ -425,7 +425,7 @@ void tcp_ca_openreq_child(struct sock *s ca =tcp_ca_find_key (ca_key);if (likely (ca &&bpf_try_module_get (ca, ca->owner))) { icsk->icsk_ca_dst_locked =tcp_ca_dst_locked (dst); - icsk->icsk_ca_ops = ca; +WRITE_ONCE (icsk->icsk_ca_ops, ca); ca_got_dst = true; }rcu_read_unlock ();
net/ipv4/tcp_output.c +1 -1
@@ -3720,7 +3720,7 @@ static void tcp_ca_dst_init(struct sockif (likely (ca &&bpf_try_module_get (ca, ca->owner))) {bpf_module_put (icsk->icsk_ca_ops, icsk->icsk_ca_ops->owner); icsk->icsk_ca_dst_locked =tcp_ca_dst_locked (dst); - icsk->icsk_ca_ops = ca; +WRITE_ONCE (icsk->icsk_ca_ops, ca); }rcu_read_unlock (); }
Greg Kroah-Hartman
maintainerPATCH 1752/1887 tcp: fix use-after-free in do_tcp_getsockopt(TCP_CC_INFO)
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft Security FORGE Labs) <[email protected]>
commit 385e474086c2e7e29e2dded690be40dc273e20ee upstream.
do_tcp_getsockopt() reads icsk->icsk_ca_ops and dereferences the get_info function pointer without rcu_read_lock(). With BPF struct_ops congestion control, ca_ops can point to dynamically allocated memory that is freed concurrently, resulting in a use-after-free when the kernel dereferences or calls through the stale pointer.
BUG: KASAN: slab-use-after-free in do_tcp_getsockopt+0x2037/0x23e0 Read of size 8 at addr ffff888013701258 by task exploit/149 do_tcp_getsockopt+0x2037/0x23e0 (net/ipv4/tcp.c:4564) tcp_getsockopt+0x91/0xf0 __sys_getsockopt+0xf7/0x170
Fix this by wrapping the ca_ops load and get_info call within rcu_read_lock()/rcu_read_unlock(), and using READ_ONCE() to load the icsk_ca_ops pointer.
--- net/ipv4/tcp.c | 4 +++- net/ipv4/tcp_dctcp.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-)
net/ipv4/tcp.c +3 -1
@@ -4209,9 +4209,11 @@ int do_tcp_getsockopt(struct sock *sk, iif (copy_from_sockptr (&len, optlen,sizeof (int )))return -EFAULT ; - ca_ops = icsk->icsk_ca_ops; +rcu_read_lock (); + ca_ops =READ_ONCE (icsk->icsk_ca_ops);if (ca_ops && ca_ops->get_info) sz = ca_ops->get_info (sk, ~0U , &attr, &info); +rcu_read_unlock (); len = min_t(unsigned int, len, sz);if (copy_to_sockptr (optlen, &len,sizeof (int )))
net/ipv4/tcp_dctcp.c +1 -1
@@ -203,7 +203,7 @@ static size_t dctcp_get_info(struct sockif (ext & (1 << (INET_DIAG_DCTCPINFO -1 )) || ext & (1 << (INET_DIAG_VEGASINFO -1 ))) {memset (&info->dctcp,0 ,sizeof (info->dctcp)); -if (inet_csk (sk)->icsk_ca_ops != &dctcp_reno) { +if (READ_ONCE (inet_csk (sk)->icsk_ca_ops) != &dctcp_reno) { info->dctcp.dctcp_enabled =1 ; info->dctcp.dctcp_ce_state = (u16 ) ca->ce_state; info->dctcp.dctcp_alpha = ca->dctcp_alpha;
Greg Kroah-Hartman
maintainerPATCH 1753/1887 cgroup: fix spurious SIGKILL of CLONE_INTO_CGROUP children
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Etienne Perot <[email protected]>
commit 8e359920216689b3b79e0fe8961a77fe312a511f upstream.
Since commit b69bb476dee9 ("cgroup: fix race between fork and cgroup.kill"), the fork path snapshots the kill_seq of the child's future cgroup into kargs->kill_seq, and cgroup_post_fork() SIGKILLs the child if that cgroup's kill_seq has changed in the meantime, to catch forks racing with a cgroup.kill sweep.
For CLONE_INTO_CGROUP, however, the snapshot in cgroup_css_set_fork() is taken before the target cgroup has been resolved: kargs->cgrp is always NULL at this point (it is only set at the end of the function). So the "if (kargs->cgrp)" branch is dead code and the snapshot always records the kill_seq of the parent's cgroup. cgroup_post_fork() then compares it with the kill_seq of the target cgroup, so the child gets SIGKILLed whenever the two cgroups have been killed a different number of times.
As a result, once cgroup.kill has been written to a cgroup, every child subsequently cloned into it with clone3(CLONE_INTO_CGROUP) is killed on the spot, for as long as the cgroup exists: kill_seq is not exposed to userspace and never resets.
Re-snapshot kill_seq from the target cgroup once it has been resolved, and drop the dead branch at the early snapshot site.
This does not reopen the race fixed by b69bb476dee9. For CLONE_INTO_CGROUP, everything from the snapshot to the check in cgroup_post_fork() runs with cgroup_mutex held, and kill_seq is only ever incremented under cgroup_mutex.
tj: Updated the comment above kill_seq to reflect the new serialization rules as suggested by Shakeel Butt.
--- include/linux/cgroup-defs.h | 5 ++++- kernel/cgroup/cgroup.c | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-)
include/linux/cgroup-defs.h +4 -1
@@ -421,7 +421,10 @@ struct cgroup {int nr_threaded_children;/* # of live threaded child cgroups */ -/* sequence number for cgroup.kill, serialized by css_set_lock. */ +/* +* Sequence number for cgroup.kill. Incremented with both cgroup_mutex +* and css_set_lock held. Readers hold either one. +*/ unsigned int kill_seq;struct kernfs_node *kn;/* cgroup kernfs entry */
kernel/cgroup/cgroup.c +2 -4
@@ -6443,10 +6443,7 @@ static int cgroup_css_set_fork(struct kespin_lock_irq (&css_set_lock); cset =task_css_set (current);get_css_set (cset); -if (kargs->cgrp) - kargs->kill_seq = kargs->cgrp->kill_seq; -else - kargs->kill_seq = cset->dfl_cgrp->kill_seq; + kargs->kill_seq = cset->dfl_cgrp->kill_seq;spin_unlock_irq (&css_set_lock);if (!(kargs->flags &CLONE_INTO_CGROUP )) {
@@ -6511,6 +6508,7 @@ static int cgroup_css_set_fork(struct keput_css_set (cset);fput (f); kargs->cgrp = dst_cgrp; + kargs->kill_seq = dst_cgrp->kill_seq;return ret; err:
Greg Kroah-Hartman
maintainerPATCH 1754/1887 dm cache: fix demotion stats in passthrough mode
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming-Hung Tsai <[email protected]>
commit 2ccb8878c149443c6acf628b438c9c942c20abb2 upstream.
The demotion counter is incremented per incoming write bio before the invalidation begins, causing the demotion count to exceed the actual number of cached blocks when multiple bios target the same cached block. Additionally, the counter is incremented unconditionally regardless of invalidation failure.
Reproduce steps:
1. Create a cache device consisting of 512 cache entries
modprobe brd rd_size=262144
dmsetup create cmeta --table "0 8192 linear /dev/ram0 0" dmsetup create cdata --table "0 65536 linear /dev/ram0 8192" dmsetup create corig --table "0 65536 linear /dev/ram0 262144" dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct dmsetup create cache --table "0 65536 cache /dev/mapper/cmeta \/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0"
2. Populate the cache, and record the number of cached blocks
fio --name=populate --filename=/dev/mapper/cache --rw=randwrite --bs=4k \
--direct=1 --ioengine=libaio --iodepth=32 --io_size=2048m nr_cached=$(dmsetup status cache | awk '{split($7, a, "/"); print a[1]}')
3. Reload the cache into passthrough mode
dmsetup suspend cache
dmsetup reload cache --table "0 65536 cache /dev/mapper/cmeta \/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" dmsetup resume cache
4. Write to the passthrough cache with multiple jobs to trigger multiple bios hitting the same cached block.
fio --filename=/dev/mapper/cache --name=test --rw=write --bs=4k \
--direct=1 --ioengine=libaio --iodepth=32 --numjobs=4
5. Check if demoted matches cached block count. These numbers should match but may differ due to overcounting per bio.
nr_demoted=$(dmsetup status cache | awk '{print $12}') echo "$nr_cached, $nr_demoted"
Fix by moving the demotion counter increment into invalidate_complete(), gated on the success flag.
--- drivers/md/dm-cache-target.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/md/dm-cache-target.c +3 -1
@@ -1461,6 +1461,9 @@ static void invalidate_complete(struct dstruct bio_list bios;struct cache *cache = mg->cache; +if (success) +atomic_inc (&cache->stats.demotion); +bio_list_init (&bios);if (mg->cell) {if (dm_cell_unlock_v2 (cache->prison, mg->cell, &bios))
@@ -1732,7 +1735,6 @@ static int map_bio(struct cache *cache,if (passthrough_mode (cache)) {if (bio_data_dir (bio) ==WRITE ) {bio_drop_shared_lock (cache, bio); -atomic_inc (&cache->stats.demotion);invalidate_start (cache, cblock, block, bio);return DM_MAPIO_SUBMITTED ; }else