Skip to content

Commit

Permalink
dma-api: Teach the "DMA-from-stack" check about vmapped stacks
Browse files Browse the repository at this point in the history
If we're using CONFIG_VMAP_STACK=y and we manage to point an sg entry
at the stack, then either the sg page will be in highmem or sg_virt()
will return the direct-map alias.  In neither case will the existing
check_for_stack() implementation realize that it's a stack page.

Fix it by explicitly checking for stack pages.

This has no effect by itself.  It's broken out for ease of review.

Signed-off-by: Andy Lutomirski <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Brian Gerst <[email protected]>
Cc: Denys Vlasenko <[email protected]>
Cc: H. Peter Anvin <[email protected]>
Cc: Josh Poimboeuf <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/448460622731312298bf19dcbacb1606e75de7a9.1470907718.git.luto@kernel.org
[ Minor edits. ]
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
amluto authored and Ingo Molnar committed Aug 24, 2016
1 parent ba14a19 commit b4a0f53
Showing 1 changed file with 30 additions and 6 deletions.
36 changes: 30 additions & 6 deletions lib/dma-debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/stacktrace.h>
#include <linux/dma-debug.h>
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/export.h>
Expand Down Expand Up @@ -1164,11 +1165,32 @@ static void check_unmap(struct dma_debug_entry *ref)
put_hash_bucket(bucket, &flags);
}

static void check_for_stack(struct device *dev, void *addr)
static void check_for_stack(struct device *dev,
struct page *page, size_t offset)
{
if (object_is_on_stack(addr))
err_printk(dev, NULL, "DMA-API: device driver maps memory from "
"stack [addr=%p]\n", addr);
void *addr;
struct vm_struct *stack_vm_area = task_stack_vm_area(current);

if (!stack_vm_area) {
/* Stack is direct-mapped. */
if (PageHighMem(page))
return;
addr = page_address(page) + offset;
if (object_is_on_stack(addr))
err_printk(dev, NULL, "DMA-API: device driver maps memory from stack [addr=%p]\n", addr);
} else {
/* Stack is vmalloced. */
int i;

for (i = 0; i < stack_vm_area->nr_pages; i++) {
if (page != stack_vm_area->pages[i])
continue;

addr = (u8 *)current->stack + i * PAGE_SIZE + offset;
err_printk(dev, NULL, "DMA-API: device driver maps memory from stack [probable addr=%p]\n", addr);
break;
}
}
}

static inline bool overlap(void *addr, unsigned long len, void *start, void *end)
Expand Down Expand Up @@ -1291,10 +1313,11 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
if (map_single)
entry->type = dma_debug_single;

check_for_stack(dev, page, offset);

if (!PageHighMem(page)) {
void *addr = page_address(page) + offset;

check_for_stack(dev, addr);
check_for_illegal_area(dev, addr, size);
}

Expand Down Expand Up @@ -1386,8 +1409,9 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
entry->sg_call_ents = nents;
entry->sg_mapped_ents = mapped_ents;

check_for_stack(dev, sg_page(s), s->offset);

if (!PageHighMem(sg_page(s))) {
check_for_stack(dev, sg_virt(s));
check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s));
}

Expand Down

0 comments on commit b4a0f53

Please sign in to comment.