Skip to contentSkip to conversation

Check list_head->next/prev for NULL in __list_del_entry_valid

PATCH New Ronnie Sahlberg 1 participant 2 messages Jan 10, 2018 1 message not in the archive

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

Steve, all,

I am trying to track down a NULL deref that happens during cifs_reconnect(). I don't have the root cause yet but I can mitigate the issue slightly by adding NULL checks in the list_debug code and avoid the bug I am chasing from causing a NULL deref to to just become a harmless run-time check.

This is not a fix for the underlying bug, I have yet for find it, but it will avoif the debugging code from making things worse by causing a crash.

During cifs_reconnect() we are calling

                list_del_init(&mid_entry->qhead);

at this point entry->prev->next is equal to entry and all is good, but entry->next is NULL which causes the crash in list_debug.c:__list_del_entry_valid() :

            CHECK_DATA_CORRUPTION(next->prev != entry,

Since __list_del_entry_valid() is used to check that the pointers are all valid, I think is is acceptable to also add NULL checks here as NULL is a common value for invalid pointers.

A message that is not in the archive (sent off-list or not yet received): 20180110000349.14963-1-lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org

#2 lore raw

PATCH 1/1 list_debug: check prev/next for NULL when checking list_head for validity

---
 lib/list_debug.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
lib/list_debug.c +7 -1
index a34db8d27667..01ef3f6d4706 100644
@@ -42,7 +42,13 @@ bool __list_del_entry_valid(struct list_head *entry)
 	prev = entry->prev;
 	next = entry->next;
 
-	if (CHECK_DATA_CORRUPTION(next == LIST_POISON1,
+	if (CHECK_DATA_CORRUPTION(next == NULL,
+			"list_del corruption, %p->next is NULL (%p)\n",
+			entry, LIST_POISON1) ||
+	    CHECK_DATA_CORRUPTION(prev == NULL,
+			"list_del corruption, %p->prev is NULL (%p)\n",
+			entry, LIST_POISON2) ||
+	    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,
Signature · 1 line
2.13.3