Skip to content

Commit daafcc0

Browse files
deepanshu406mszyprow
authored andcommitted
tracing/dma: Cap dma_map_sg tracepoint arrays to prevent buffer overflow
The dma_map_sg tracepoint can trigger a perf buffer overflow when tracing large scatter-gather lists. With devices like virtio-gpu creating large DRM buffers, nents can exceed 1000 entries, resulting in: phys_addrs: 1000 * 8 bytes = 8,000 bytes dma_addrs: 1000 * 8 bytes = 8,000 bytes lengths: 1000 * 4 bytes = 4,000 bytes Total: ~20,000 bytes This exceeds PERF_MAX_TRACE_SIZE (8192 bytes), causing: WARNING: CPU: 0 PID: 5497 at kernel/trace/trace_event_perf.c:405 perf buffer not large enough, wanted 24620, have 8192 Cap all three dynamic arrays at 128 entries using min() in the array size calculation. This ensures arrays are only as large as needed (up to the cap), avoiding unnecessary memory allocation for small operations while preventing overflow for large ones. The tracepoint now records the full nents/ents counts and a truncated flag so users can see when data has been capped. Changes in v2: - Use min(nents, DMA_TRACE_MAX_ENTRIES) for dynamic array sizing instead of fixed DMA_TRACE_MAX_ENTRIES allocation (feedback from Steven Rostedt) - This allocates only what's needed up to the cap, avoiding waste for small operations Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=28cea38c382fd15e751a Tested-by: [email protected] Signed-off-by: Deepanshu Kartikey <[email protected]> Reviwed-by: Sean Anderson <[email protected]> Signed-off-by: Marek Szyprowski <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 56c430c commit daafcc0

1 file changed

Lines changed: 19 additions & 6 deletions

File tree

  • include/trace/events

include/trace/events/dma.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,28 +275,38 @@ TRACE_EVENT(dma_free_sgt,
275275
sizeof(u64), sizeof(u64)))
276276
);
277277

278+
#define DMA_TRACE_MAX_ENTRIES 128
279+
278280
TRACE_EVENT(dma_map_sg,
279281
TP_PROTO(struct device *dev, struct scatterlist *sgl, int nents,
280282
int ents, enum dma_data_direction dir, unsigned long attrs),
281283
TP_ARGS(dev, sgl, nents, ents, dir, attrs),
282284

283285
TP_STRUCT__entry(
284286
__string(device, dev_name(dev))
285-
__dynamic_array(u64, phys_addrs, nents)
286-
__dynamic_array(u64, dma_addrs, ents)
287-
__dynamic_array(unsigned int, lengths, ents)
287+
__field(int, full_nents)
288+
__field(int, full_ents)
289+
__field(bool, truncated)
290+
__dynamic_array(u64, phys_addrs, min(nents, DMA_TRACE_MAX_ENTRIES))
291+
__dynamic_array(u64, dma_addrs, min(ents, DMA_TRACE_MAX_ENTRIES))
292+
__dynamic_array(unsigned int, lengths, min(ents, DMA_TRACE_MAX_ENTRIES))
288293
__field(enum dma_data_direction, dir)
289294
__field(unsigned long, attrs)
290295
),
291296

292297
TP_fast_assign(
293298
struct scatterlist *sg;
294299
int i;
300+
int traced_nents = min_t(int, nents, DMA_TRACE_MAX_ENTRIES);
301+
int traced_ents = min_t(int, ents, DMA_TRACE_MAX_ENTRIES);
295302

296303
__assign_str(device);
297-
for_each_sg(sgl, sg, nents, i)
304+
__entry->full_nents = nents;
305+
__entry->full_ents = ents;
306+
__entry->truncated = (nents > DMA_TRACE_MAX_ENTRIES) || (ents > DMA_TRACE_MAX_ENTRIES);
307+
for_each_sg(sgl, sg, traced_nents, i)
298308
((u64 *)__get_dynamic_array(phys_addrs))[i] = sg_phys(sg);
299-
for_each_sg(sgl, sg, ents, i) {
309+
for_each_sg(sgl, sg, traced_ents, i) {
300310
((u64 *)__get_dynamic_array(dma_addrs))[i] =
301311
sg_dma_address(sg);
302312
((unsigned int *)__get_dynamic_array(lengths))[i] =
@@ -306,9 +316,12 @@ TRACE_EVENT(dma_map_sg,
306316
__entry->attrs = attrs;
307317
),
308318

309-
TP_printk("%s dir=%s dma_addrs=%s sizes=%s phys_addrs=%s attrs=%s",
319+
TP_printk("%s dir=%s nents=%d/%d ents=%d/%d%s dma_addrs=%s sizes=%s phys_addrs=%s attrs=%s",
310320
__get_str(device),
311321
decode_dma_data_direction(__entry->dir),
322+
min_t(int, __entry->full_nents, DMA_TRACE_MAX_ENTRIES), __entry->full_nents,
323+
min_t(int, __entry->full_ents, DMA_TRACE_MAX_ENTRIES), __entry->full_ents,
324+
__entry->truncated ? " [TRUNCATED]" : "",
312325
__print_array(__get_dynamic_array(dma_addrs),
313326
__get_dynamic_array_len(dma_addrs) /
314327
sizeof(u64), sizeof(u64)),

0 commit comments

Comments
 (0)