From 746363a33825f03166c37deeb185e3b72a4b46f8 Mon Sep 17 00:00:00 2001 From: Adrian Dudau Date: Thu, 26 May 2016 10:12:29 +0200 Subject: linux-ls1: Fix kernel oops caused by fsnotify race condition Backport from mainline. Only kernels <4.2 are affected by this. Signed-off-by: Adrian Dudau Signed-off-by: Martin Borg --- ...x-oops-in-fsnotify_clear_marks_by_group_f.patch | 80 ++++++++++++++++++++++ recipes-kernel/linux/linux-ls1_3.12.bbappend | 1 + 2 files changed, 81 insertions(+) create mode 100644 recipes-kernel/linux/linux-ls1/0001-fsnotify-fix-oops-in-fsnotify_clear_marks_by_group_f.patch diff --git a/recipes-kernel/linux/linux-ls1/0001-fsnotify-fix-oops-in-fsnotify_clear_marks_by_group_f.patch b/recipes-kernel/linux/linux-ls1/0001-fsnotify-fix-oops-in-fsnotify_clear_marks_by_group_f.patch new file mode 100644 index 0000000..250c8db --- /dev/null +++ b/recipes-kernel/linux/linux-ls1/0001-fsnotify-fix-oops-in-fsnotify_clear_marks_by_group_f.patch @@ -0,0 +1,80 @@ +From 8f2f3eb59dff4ec538de55f2e0592fec85966aab Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 6 Aug 2015 15:46:42 -0700 +Subject: [PATCH] fsnotify: fix oops in fsnotify_clear_marks_by_group_flags() + +fsnotify_clear_marks_by_group_flags() can race with +fsnotify_destroy_marks() so that when fsnotify_destroy_mark_locked() +drops mark_mutex, a mark from the list iterated by +fsnotify_clear_marks_by_group_flags() can be freed and thus the next +entry pointer we have cached may become stale and we dereference free +memory. + +Fix the problem by first moving marks to free to a special private list +and then always free the first entry in the special list. This method +is safe even when entries from the list can disappear once we drop the +lock. + +Upstream-Status: Backported + +Signed-off-by: Jan Kara +Reported-by: Ashish Sangwan +Reviewed-by: Ashish Sangwan +Cc: Lino Sanfilippo +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Adrian Dudau +--- + fs/notify/mark.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 92e48c7..39ddcaf 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -412,16 +412,36 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, + unsigned int flags) + { + struct fsnotify_mark *lmark, *mark; ++ LIST_HEAD(to_free); + ++ /* ++ * We have to be really careful here. Anytime we drop mark_mutex, e.g. ++ * fsnotify_clear_marks_by_inode() can come and free marks. Even in our ++ * to_free list so we have to use mark_mutex even when accessing that ++ * list. And freeing mark requires us to drop mark_mutex. So we can ++ * reliably free only the first mark in the list. That's why we first ++ * move marks to free to to_free list in one go and then free marks in ++ * to_free list one by one. ++ */ + mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); + list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { +- if (mark->flags & flags) { +- fsnotify_get_mark(mark); +- fsnotify_destroy_mark_locked(mark, group); +- fsnotify_put_mark(mark); +- } ++ if (mark->flags & flags) ++ list_move(&mark->g_list, &to_free); + } + mutex_unlock(&group->mark_mutex); ++ ++ while (1) { ++ mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); ++ if (list_empty(&to_free)) { ++ mutex_unlock(&group->mark_mutex); ++ break; ++ } ++ mark = list_first_entry(&to_free, struct fsnotify_mark, g_list); ++ fsnotify_get_mark(mark); ++ fsnotify_destroy_mark_locked(mark, group); ++ mutex_unlock(&group->mark_mutex); ++ fsnotify_put_mark(mark); ++ } + } + + /* +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-ls1_3.12.bbappend b/recipes-kernel/linux/linux-ls1_3.12.bbappend index f34b2d1..338b3bf 100644 --- a/recipes-kernel/linux/linux-ls1_3.12.bbappend +++ b/recipes-kernel/linux/linux-ls1_3.12.bbappend @@ -1,6 +1,7 @@ FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" SRC_URI += "file://ls1021aiot.dts \ + file://0001-fsnotify-fix-oops-in-fsnotify_clear_marks_by_group_f.patch \ " # fix err: "linux-ls1-3.12-r0 do_deploy: Taskhash mismatch" -- cgit v1.2.3-54-g00ecf