b16c42c8fd
Turn the list debug checking functions __list_*_valid() into inline functions that wrap the out-of-line functions. Care is taken to ensure the inline wrappers are always inlined, so that additional compiler instrumentation (such as sanitizers) does not result in redundant outlining. This change is preparation for performing checks in the inline wrappers. No functional change intended. Signed-off-by: Marco Elver <elver@google.com> Link: https://lore.kernel.org/r/20230811151847.1594958-2-elver@google.com Signed-off-by: Kees Cook <keescook@chromium.org>
70 lines
2.2 KiB
C
70 lines
2.2 KiB
C
/*
|
|
* Copyright 2006, Red Hat, Inc., Dave Jones
|
|
* Released under the General Public License (GPL).
|
|
*
|
|
* This file contains the linked list validation for DEBUG_LIST.
|
|
*/
|
|
|
|
#include <linux/export.h>
|
|
#include <linux/list.h>
|
|
#include <linux/bug.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/rculist.h>
|
|
|
|
/*
|
|
* Check that the data structures for the list manipulations are reasonably
|
|
* valid. Failures here indicate memory corruption (and possibly an exploit
|
|
* attempt).
|
|
*/
|
|
|
|
bool __list_add_valid_or_report(struct list_head *new, struct list_head *prev,
|
|
struct list_head *next)
|
|
{
|
|
if (CHECK_DATA_CORRUPTION(prev == NULL,
|
|
"list_add corruption. prev is NULL.\n") ||
|
|
CHECK_DATA_CORRUPTION(next == NULL,
|
|
"list_add corruption. next is NULL.\n") ||
|
|
CHECK_DATA_CORRUPTION(next->prev != prev,
|
|
"list_add corruption. next->prev should be prev (%px), but was %px. (next=%px).\n",
|
|
prev, next->prev, next) ||
|
|
CHECK_DATA_CORRUPTION(prev->next != next,
|
|
"list_add corruption. prev->next should be next (%px), but was %px. (prev=%px).\n",
|
|
next, prev->next, prev) ||
|
|
CHECK_DATA_CORRUPTION(new == prev || new == next,
|
|
"list_add double add: new=%px, prev=%px, next=%px.\n",
|
|
new, prev, next))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
EXPORT_SYMBOL(__list_add_valid_or_report);
|
|
|
|
bool __list_del_entry_valid_or_report(struct list_head *entry)
|
|
{
|
|
struct list_head *prev, *next;
|
|
|
|
prev = entry->prev;
|
|
next = entry->next;
|
|
|
|
if (CHECK_DATA_CORRUPTION(next == NULL,
|
|
"list_del corruption, %px->next is NULL\n", entry) ||
|
|
CHECK_DATA_CORRUPTION(prev == NULL,
|
|
"list_del corruption, %px->prev is NULL\n", entry) ||
|
|
CHECK_DATA_CORRUPTION(next == LIST_POISON1,
|
|
"list_del corruption, %px->next is LIST_POISON1 (%px)\n",
|
|
entry, LIST_POISON1) ||
|
|
CHECK_DATA_CORRUPTION(prev == LIST_POISON2,
|
|
"list_del corruption, %px->prev is LIST_POISON2 (%px)\n",
|
|
entry, LIST_POISON2) ||
|
|
CHECK_DATA_CORRUPTION(prev->next != entry,
|
|
"list_del corruption. prev->next should be %px, but was %px. (prev=%px)\n",
|
|
entry, prev->next, prev) ||
|
|
CHECK_DATA_CORRUPTION(next->prev != entry,
|
|
"list_del corruption. next->prev should be %px, but was %px. (next=%px)\n",
|
|
entry, next->prev, next))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
EXPORT_SYMBOL(__list_del_entry_valid_or_report);
|