diff options
author | Tao Huang <huangtao@rock-chips.com> | 2018-10-10 19:37:13 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-10-10 19:37:13 +0800 |
commit | d376ad8f232e1d32b334f3f94ae94a84091a6b5d (patch) | |
tree | 6fbd8ab11256b088163ee96f603689b2f3e3af29 /lib | |
parent | 90a00e3789943713ef89ff262bb6182fa99e625d (diff) | |
parent | 8fd9c723bde83907697121ca0f7beb51bbdb32da (diff) |
Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux-linaro-stable.git
* linux-linaro-lsk-v4.4-android: (1212 commits)
ANDROID: sdcardfs: Change current->fs under lock
ANDROID: sdcardfs: Don't use OVERRIDE_CRED macro
ANDROID: restrict store of prefer_idle as boolean
BACKPORT: arm/syscalls: Optimize address limit check
UPSTREAM: syscalls: Use CHECK_DATA_CORRUPTION for addr_limit_user_check
BACKPORT: arm64/syscalls: Check address limit on user-mode return
BACKPORT: x86/syscalls: Check address limit on user-mode return
BACKPORT: lkdtm: add bad USER_DS test
UPSTREAM: bug: switch data corruption check to __must_check
BACKPORT: lkdtm: Add tests for struct list corruption
UPSTREAM: bug: Provide toggle for BUG on data corruption
UPSTREAM: list: Split list_del() debug checking into separate function
UPSTREAM: rculist: Consolidate DEBUG_LIST for list_add_rcu()
BACKPORT: list: Split list_add() debug checking into separate function
FROMLIST: ANDROID: binder: Add BINDER_GET_NODE_INFO_FOR_REF ioctl.
BACKPORT: arm64/vdso: Fix nsec handling for CLOCK_MONOTONIC_RAW
ANDROID: arm64: mm: fix 4.4.154 merge
BACKPORT: zsmalloc: introduce zs_huge_class_size()
BACKPORT: zram: drop max_zpage_size and use zs_huge_class_size()
ANDROID: tracing: fix race condition reading saved tgids
...
Change-Id: I9f23db35eb926b6fa0d7af7dbbb55c9a37d536fc
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig.debug | 10 | ||||
-rw-r--r-- | lib/debugobjects.c | 7 | ||||
-rw-r--r-- | lib/list_debug.c | 110 |
3 files changed, 51 insertions, 76 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 17d43dcf38b9..34c170a4a99d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1898,6 +1898,16 @@ config TEST_STATIC_KEYS If unsure, say N. +config BUG_ON_DATA_CORRUPTION + bool "Trigger a BUG when data corruption is detected" + select CONFIG_DEBUG_LIST + help + Select this option if the kernel should BUG when it encounters + data corruption in kernel memory structures when they get checked + for validity. + + If unsure, say N. + source "samples/Kconfig" source "lib/Kconfig.kgdb" diff --git a/lib/debugobjects.c b/lib/debugobjects.c index 547f7f923dbc..a26328ec39f1 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c @@ -295,9 +295,12 @@ static void debug_object_is_on_stack(void *addr, int onstack) limit++; if (is_on_stack) - pr_warn("object is on stack, but not annotated\n"); + pr_warn("object %p is on stack %p, but NOT annotated.\n", addr, + task_stack_page(current)); else - pr_warn("object is not on stack, but annotated\n"); + pr_warn("object %p is NOT on stack %p, but annotated.\n", addr, + task_stack_page(current)); + WARN_ON(1); } diff --git a/lib/list_debug.c b/lib/list_debug.c index c24c2f7e296f..a34db8d27667 100644 --- a/lib/list_debug.c +++ b/lib/list_debug.c @@ -2,8 +2,7 @@ * Copyright 2006, Red Hat, Inc., Dave Jones * Released under the General Public License (GPL). * - * This file contains the linked list implementations for - * DEBUG_LIST. + * This file contains the linked list validation for DEBUG_LIST. */ #include <linux/export.h> @@ -13,88 +12,51 @@ #include <linux/rculist.h> /* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! + * Check that the data structures for the list manipulations are reasonably + * valid. Failures here indicate memory corruption (and possibly an exploit + * attempt). */ -void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) +bool __list_add_valid(struct list_head *new, struct list_head *prev, + struct list_head *next) { - WARN(next->prev != prev, - "list_add corruption. next->prev should be " - "prev (%p), but was %p. (next=%p).\n", - prev, next->prev, next); - WARN(prev->next != next, - "list_add corruption. prev->next should be " - "next (%p), but was %p. (prev=%p).\n", - next, prev->next, prev); - WARN(new == prev || new == next, - "list_add double add: new=%p, prev=%p, next=%p.\n", - new, prev, next); - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + if (CHECK_DATA_CORRUPTION(next->prev != prev, + "list_add corruption. next->prev should be prev (%p), but was %p. (next=%p).\n", + prev, next->prev, next) || + CHECK_DATA_CORRUPTION(prev->next != next, + "list_add corruption. prev->next should be next (%p), but was %p. (prev=%p).\n", + next, prev->next, prev) || + CHECK_DATA_CORRUPTION(new == prev || new == next, + "list_add double add: new=%p, prev=%p, next=%p.\n", + new, prev, next)) + return false; + + return true; } -EXPORT_SYMBOL(__list_add); +EXPORT_SYMBOL(__list_add_valid); -void __list_del_entry(struct list_head *entry) +bool __list_del_entry_valid(struct list_head *entry) { struct list_head *prev, *next; prev = entry->prev; next = entry->next; - if (WARN(next == LIST_POISON1, - "list_del corruption, %p->next is LIST_POISON1 (%p)\n", - entry, LIST_POISON1) || - WARN(prev == LIST_POISON2, - "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", - entry, LIST_POISON2) || - WARN(prev->next != entry, - "list_del corruption. prev->next should be %p, " - "but was %p\n", entry, prev->next) || - WARN(next->prev != entry, - "list_del corruption. next->prev should be %p, " - "but was %p\n", entry, next->prev)) - return; - - __list_del(prev, next); -} -EXPORT_SYMBOL(__list_del_entry); - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is - * in an undefined state. - */ -void list_del(struct list_head *entry) -{ - __list_del_entry(entry); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} -EXPORT_SYMBOL(list_del); + if (CHECK_DATA_CORRUPTION(next == LIST_POISON1, + "list_del corruption, %p->next is LIST_POISON1 (%p)\n", + entry, LIST_POISON1) || + CHECK_DATA_CORRUPTION(prev == LIST_POISON2, + "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", + entry, LIST_POISON2) || + CHECK_DATA_CORRUPTION(prev->next != entry, + "list_del corruption. prev->next should be %p, but was %p\n", + entry, prev->next) || + CHECK_DATA_CORRUPTION(next->prev != entry, + "list_del corruption. next->prev should be %p, but was %p\n", + entry, next->prev)) + return false; + + return true; -/* - * RCU variants. - */ -void __list_add_rcu(struct list_head *new, - struct list_head *prev, struct list_head *next) -{ - WARN(next->prev != prev, - "list_add_rcu corruption. next->prev should be prev (%p), but was %p. (next=%p).\n", - prev, next->prev, next); - WARN(prev->next != next, - "list_add_rcu corruption. prev->next should be next (%p), but was %p. (prev=%p).\n", - next, prev->next, prev); - new->next = next; - new->prev = prev; - rcu_assign_pointer(list_next_rcu(prev), new); - next->prev = new; } -EXPORT_SYMBOL(__list_add_rcu); +EXPORT_SYMBOL(__list_del_entry_valid); |