blob: 8dfe861d246dd9fe685bf1970e4664c91c606f52 [file] [log] [blame]
Dave Jones199a9af2006-09-29 01:59:00 -07001/*
2 * Copyright 2006, Red Hat, Inc., Dave Jones
3 * Released under the General Public License (GPL).
4 *
Kees Cook791e53f2016-08-17 14:42:08 -07005 * This file contains the linked list validation for DEBUG_LIST.
Dave Jones199a9af2006-09-29 01:59:00 -07006 */
7
Paul Gortmaker8bc3bcc2011-11-16 21:29:17 -05008#include <linux/export.h>
Dave Jones199a9af2006-09-29 01:59:00 -07009#include <linux/list.h>
Paul Gortmaker50af5ea2012-01-20 18:35:53 -050010#include <linux/bug.h>
Paul Gortmakerb116ee42012-01-20 18:46:49 -050011#include <linux/kernel.h>
Dave Jones559f9ba2012-03-14 22:17:39 -040012#include <linux/rculist.h>
Syed Rameez Mustafacf9c1e42013-07-15 11:52:09 -070013#include <linux/bug.h>
Dave Jones199a9af2006-09-29 01:59:00 -070014
15/*
Kees Cook791e53f2016-08-17 14:42:08 -070016 * Check that the data structures for the list manipulations are reasonably
17 * valid. Failures here indicate memory corruption (and possibly an exploit
18 * attempt).
Dave Jones199a9af2006-09-29 01:59:00 -070019 */
20
Kees Cook791e53f2016-08-17 14:42:08 -070021bool __list_add_valid(struct list_head *new, struct list_head *prev,
22 struct list_head *next)
Dave Jones199a9af2006-09-29 01:59:00 -070023{
Syed Rameez Mustafacf9c1e42013-07-15 11:52:09 -070024
Kees Cookeb235bf2017-02-24 15:00:38 -080025 if (CHECK_DATA_CORRUPTION(next->prev != prev,
Minming Qi2e316b42018-11-07 13:12:49 +080026 "list_add corruption. next->prev should be prev (%p), but was %p. (next=%p).\n",
27 prev, next->prev, next) ||
28 CHECK_DATA_CORRUPTION(prev->next != next,
29 "list_add corruption. prev->next should be next (%p), but was %p. (prev=%p).\n",
30 next, prev->next, prev) ||
31 CHECK_DATA_CORRUPTION(new == prev || new == next,
32 "list_add double add: new=%p, prev=%p, next=%p.\n",
33 new, prev, next))
34 return false;
Syed Rameez Mustafacf9c1e42013-07-15 11:52:09 -070035
Dave Jones199a9af2006-09-29 01:59:00 -070036 next->prev = new;
37 new->next = next;
38 new->prev = prev;
Paul E. McKenney1c97be62015-09-20 22:02:17 -070039 WRITE_ONCE(prev->next, new);
Dave Jones199a9af2006-09-29 01:59:00 -070040
Kees Cook791e53f2016-08-17 14:42:08 -070041 return true;
Dave Jones199a9af2006-09-29 01:59:00 -070042}
Kees Cook791e53f2016-08-17 14:42:08 -070043EXPORT_SYMBOL(__list_add_valid);
Dave Jones199a9af2006-09-29 01:59:00 -070044
Kees Cookca48e8c2016-08-17 14:42:10 -070045bool __list_del_entry_valid(struct list_head *entry)
Linus Torvalds3c18d4d2011-02-18 11:32:28 -080046{
47 struct list_head *prev, *next;
48
49 prev = entry->prev;
50 next = entry->next;
51
Kees Cookeb235bf2017-02-24 15:00:38 -080052 if (CHECK_DATA_CORRUPTION(next == LIST_POISON1,
53 "list_del corruption, %p->next is LIST_POISON1 (%p)\n",
54 entry, LIST_POISON1) ||
55 CHECK_DATA_CORRUPTION(prev == LIST_POISON2,
56 "list_del corruption, %p->prev is LIST_POISON2 (%p)\n",
57 entry, LIST_POISON2) ||
58 CHECK_DATA_CORRUPTION(prev->next != entry,
59 "list_del corruption. prev->next should be %p, but was %p\n",
60 entry, prev->next) ||
61 CHECK_DATA_CORRUPTION(next->prev != entry,
62 "list_del corruption. next->prev should be %p, but was %p\n",
63 entry, next->prev))
64 return false;
Linus Torvalds3c18d4d2011-02-18 11:32:28 -080065
Kees Cookca48e8c2016-08-17 14:42:10 -070066 return true;
Linus Torvalds3c18d4d2011-02-18 11:32:28 -080067
Dave Jones199a9af2006-09-29 01:59:00 -070068}
Kees Cookca48e8c2016-08-17 14:42:10 -070069EXPORT_SYMBOL(__list_del_entry_valid);