void mmio_hexdump(const struct mmio *io, size_t length, size_t flags) { __hexdump(io->iobase + io->offset, io->iomem + io->offset, length, flags); }
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; }