summaryrefslogtreecommitdiffstats
path: root/tools/lib/subcmd/subcmd-util.h
diff options
context:
space:
mode:
authorShivank Garg <shivankg@amd.com>2026-08-22 19:22:05 +0000
committerVinod Koul <vkoul@kernel.org>2026-09-09 17:51:44 +0530
commite873c74132f0c5f1452816cd9bb26208f0bba1e1 (patch)
treecc1ce1567f5b982359331863ebd9da38741f8d2e /tools/lib/subcmd/subcmd-util.h
downloadlinux-stable-e873c74132f0c5f1452816cd9bb26208f0bba1e1.tar.gz
linux-stable-e873c74132f0c5f1452816cd9bb26208f0bba1e1.zip
dmaengine: fix use-after-free in dma_chan_put() and dma_release_channel()grafted
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 <sashiko-bot@kernel.org> Link: https://sashiko.dev/#/patchset/20260518-dmaengine-kref-fix-v1-1-4d6125048fb7@amd.com Reviewed-by: Frank Li <Frank.Li@nxp.com> Reviewed-by: Logan Gunthorpe <logang@deltatee.com> Signed-off-by: Shivank Garg <shivankg@amd.com> Link: https://patch.msgid.link/20260822-dmaengine-kref-fix-v5-3-d4a4ee47d927@amd.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'tools/lib/subcmd/subcmd-util.h')
-rw-r--r--tools/lib/subcmd/subcmd-util.h75
1 files changed, 75 insertions, 0 deletions
diff --git a/tools/lib/subcmd/subcmd-util.h b/tools/lib/subcmd/subcmd-util.h
new file mode 100644
index 000000000..c742b0881
--- /dev/null
+++ b/tools/lib/subcmd/subcmd-util.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __SUBCMD_UTIL_H
+#define __SUBCMD_UTIL_H
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <linux/compiler.h>
+
+static inline void report(const char *prefix, const char *err, va_list params)
+{
+ char msg[1024];
+ vsnprintf(msg, sizeof(msg), err, params);
+ fprintf(stderr, " %s%s\n", prefix, msg);
+}
+
+static __noreturn inline void die(const char *err, ...)
+{
+ va_list params;
+
+ va_start(params, err);
+ report(" Fatal: ", err, params);
+ va_end(params);
+ exit(128);
+}
+
+#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
+
+#define alloc_nr(x) (((x)+16)*3/2)
+
+/*
+ * Realloc the buffer pointed at by variable 'x' so that it can hold
+ * at least 'nr' entries; the number of entries currently allocated
+ * is 'alloc', using the standard growing factor alloc_nr() macro.
+ *
+ * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
+ */
+#define ALLOC_GROW(x, nr, alloc) \
+ do { \
+ if ((nr) > alloc) { \
+ if (alloc_nr(alloc) < (nr)) \
+ alloc = (nr); \
+ else \
+ alloc = alloc_nr(alloc); \
+ x = xrealloc((x), alloc * sizeof(*(x))); \
+ } \
+ } while(0)
+
+static inline void *xrealloc(void *ptr, size_t size)
+{
+ void *ret = realloc(ptr, size);
+ if (!ret)
+ die("Out of memory, realloc failed");
+ return ret;
+}
+
+#define astrcatf(out, fmt, ...) \
+({ \
+ char *tmp = *(out); \
+ if (asprintf((out), "%s" fmt, tmp ?: "", ## __VA_ARGS__) == -1) \
+ die("asprintf failed"); \
+ free(tmp); \
+})
+
+static inline void astrcat(char **out, const char *add)
+{
+ char *tmp = *out;
+
+ if (asprintf(out, "%s%s", tmp ?: "", add) == -1)
+ die("asprintf failed");
+
+ free(tmp);
+}
+
+#endif /* __SUBCMD_UTIL_H */