Beispiel #1
0
void mmio_hexdump(const struct mmio *io, size_t length, size_t flags)
{
	__hexdump(io->iobase + io->offset,
		  io->iomem + io->offset,
		  length, flags);
}
Beispiel #2
0
void *kfree_hook(void *p, void *caller)
{
	unsigned long flags;
	struct dfd_node *match = NULL;
	void *tofree = NULL;
	unsigned long addr = (unsigned long)p;
	struct dfd_node entry;
	struct dfd_node *pentry;

	if (!virt_addr_valid(addr)) {
		/* there are too many NULL pointers so don't print for NULL */
		if (addr)
			pr_debug("%s: trying to free an invalid addr %lx "\
				"from %pS\n", __func__, addr, caller);
		return NULL;
	}

	if (addr & KFREE_HOOK_BYPASS_MASK || dfd_disabled) {
		/* return original address to free */
		return (void *)(addr&~(KFREE_HOOK_BYPASS_MASK));
	}

	spin_lock_irqsave(&dfd_list_lock, flags);

	if (dfd_node_list.head == 0)
		pr_debug("%s: circular buffer head rounded to zero.", __func__);

	/* We can detect all the double free in the circular buffer time frame
	 * if we scan the whole circular buffer all the time, but to minimize
	 * the performance degradation we will just check for the magic values
	 * (the number of magic values can be up to KMALLOC_MIN_SIZE/4) */
	if (dfd_check_magic_any(p)) {
		/* memory that is to be freed may originally have had magic
		 * value, so search the whole circ buf for an actual match */
		match = circ_buf_lookup(&dfd_node_list, p);
		if (!match)
			pr_debug("%s: magic set but not in circ buf\n", __func__);
	}

	if (match) {
		pr_err("%s: 0x%08lx was already freed by %pS()\n",
			__func__, (unsigned long)p, match->caller);
		spin_unlock_irqrestore(&dfd_list_lock, flags);
		if (dfd_panic)
			panic("double free detected!");
		/* if we don't panic we just return without adding this entry
		 * to the circular buffer. This means that this kfree is ommited
		 * and we are just forgiving the double free */
		dump_stack();
		return NULL;
	}

	/* mark free magic on the freeing node */
	dfd_set_magic(p);

	/* do an actual kfree for the oldest entry
	 * if the circular buffer is full */
	if (CIRC_SPACE(dfd_node_list.head, dfd_node_list.tail,
		KFREE_CIRC_BUF_SIZE) == 0) {
		pentry = circ_buf_get(&dfd_node_list);
		if (pentry)
			tofree = pentry->addr;
	}

	/* add the new entry to the circular buffer */
	entry.addr = p;
	entry.caller = caller;
	circ_buf_put(&dfd_node_list, &entry);
	if (tofree) {
		if (unlikely(!dfd_check_magic_all(tofree))) {
			pr_emerg("\n%s: Use after free detected on the node "\
				"0x%lx which was freed by %pS.\n",\
				__func__, (unsigned long)tofree,
				pentry->caller);
			__hexdump((void *)tofree, KMALLOC_MIN_SIZE);
			pr_err("\n");
		}
		dfd_clear_magic(tofree);
		spin_unlock_irqrestore(&dfd_list_lock, flags);
		/* do the real kfree */
		kfree((void *)((unsigned long)tofree | KFREE_HOOK_BYPASS_MASK));
		return NULL;
	}

	spin_unlock_irqrestore(&dfd_list_lock, flags);
	return NULL;
}