From e873c74132f0c5f1452816cd9bb26208f0bba1e1 Mon Sep 17 00:00:00 2001 From: Shivank Garg Date: Sat, 22 Aug 2026 19:22:05 +0000 Subject: dmaengine: fix use-after-free in dma_chan_put() and dma_release_channel() When dma_device_put() drops the last reference on chan->device->ref, dma_device_release() runs and may free the dma_device along with its channels. dma_chan_put() then still reads chan->device->owner via dma_chan_to_owner() for the trailing module_put(). KASAN catches it: slab-use-after-free in dma_chan_put+0x3e6/0x4c0 Read of size 8 by task insmod/6319 Freed by task 6319: kfree+0x225/0x470 dma_chan_put+0x395/0x4c0 dmaengine_put+0xf8/0x160 Cache the module owner in dma_chan_put() before the put so the trailing module_put() does not need chan->device. Fixes: 8ad342a86359 ("dmaengine: Add reference counting to dma_device struct") Suggested-by: Sashiko Link: https://sashiko.dev/#/patchset/20260518-dmaengine-kref-fix-v1-1-4d6125048fb7@amd.com Reviewed-by: Frank Li Reviewed-by: Logan Gunthorpe Signed-off-by: Shivank Garg Link: https://patch.msgid.link/20260822-dmaengine-kref-fix-v5-3-d4a4ee47d927@amd.com Signed-off-by: Vinod Koul --- drivers/rpmsg/rpmsg_internal.h | 96 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 drivers/rpmsg/rpmsg_internal.h (limited to 'drivers/rpmsg/rpmsg_internal.h') diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h new file mode 100644 index 000000000..a8b7065fd --- /dev/null +++ b/drivers/rpmsg/rpmsg_internal.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * remote processor messaging bus internals + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen + * Brian Swetland + */ + +#ifndef __RPMSG_INTERNAL_H__ +#define __RPMSG_INTERNAL_H__ + +#include +#include + +#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev) +#define to_rpmsg_driver(d) container_of_const(d, struct rpmsg_driver, drv) + +extern const struct class rpmsg_class; + +/** + * struct rpmsg_device_ops - indirection table for the rpmsg_device operations + * @create_channel: create backend-specific channel, optional + * @release_channel: release backend-specific channel, optional + * @create_ept: create backend-specific endpoint, required + * @announce_create: announce presence of new channel, optional + * @announce_destroy: announce destruction of channel, optional + * + * Indirection table for the operations that a rpmsg backend should implement. + * @announce_create and @announce_destroy are optional as the backend might + * advertise new channels implicitly by creating the endpoints. + */ +struct rpmsg_device_ops { + struct rpmsg_device *(*create_channel)(struct rpmsg_device *rpdev, + struct rpmsg_channel_info *chinfo); + int (*release_channel)(struct rpmsg_device *rpdev, + struct rpmsg_channel_info *chinfo); + struct rpmsg_endpoint *(*create_ept)(struct rpmsg_device *rpdev, + rpmsg_rx_cb_t cb, void *priv, + struct rpmsg_channel_info chinfo); + + int (*announce_create)(struct rpmsg_device *rpdev); + int (*announce_destroy)(struct rpmsg_device *rpdev); +}; + +/** + * struct rpmsg_endpoint_ops - indirection table for rpmsg_endpoint operations + * @destroy_ept: see @rpmsg_destroy_ept(), required + * @send: see @rpmsg_send(), required + * @sendto: see @rpmsg_sendto(), optional + * @trysend: see @rpmsg_trysend(), required + * @trysendto: see @rpmsg_trysendto(), optional + * @poll: see @rpmsg_poll(), optional + * @set_flow_control: see @rpmsg_set_flow_control(), optional + * @get_mtu: see @rpmsg_get_mtu(), optional + * + * Indirection table for the operations that a rpmsg backend should implement. + * In addition to @destroy_ept, the backend must at least implement @send and + * @trysend, while the variants sending data off-channel are optional. + */ +struct rpmsg_endpoint_ops { + void (*destroy_ept)(struct rpmsg_endpoint *ept); + + int (*send)(struct rpmsg_endpoint *ept, const void *data, int len); + int (*sendto)(struct rpmsg_endpoint *ept, const void *data, int len, u32 dst); + + int (*trysend)(struct rpmsg_endpoint *ept, const void *data, int len); + int (*trysendto)(struct rpmsg_endpoint *ept, const void *data, int len, u32 dst); + __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, + poll_table *wait); + int (*set_flow_control)(struct rpmsg_endpoint *ept, bool pause, u32 dst); + ssize_t (*get_mtu)(struct rpmsg_endpoint *ept); +}; + +struct device *rpmsg_find_device(struct device *parent, + struct rpmsg_channel_info *chinfo); + +struct rpmsg_device *rpmsg_create_channel(struct rpmsg_device *rpdev, + struct rpmsg_channel_info *chinfo); +int rpmsg_release_channel(struct rpmsg_device *rpdev, + struct rpmsg_channel_info *chinfo); +/** + * rpmsg_ctrldev_register_device() - register a char device for control based on rpdev + * @rpdev: prepared rpdev to be used for creating endpoints + * + * This function wraps rpmsg_register_device() preparing the rpdev for use as + * basis for the rpmsg chrdev. + */ +static inline int rpmsg_ctrldev_register_device(struct rpmsg_device *rpdev) +{ + return rpmsg_register_device_override(rpdev, "rpmsg_ctrl"); +} + +#endif -- cgit v1.3.1