|
Jan Kara |
27c3d6 |
From d90a10e2444ba5a351fa695917258ff4c5709fa5 Mon Sep 17 00:00:00 2001
|
|
Jan Kara |
27c3d6 |
From: Robert Kolchmeyer <rkolchmeyer@google.com>
|
|
Jan Kara |
27c3d6 |
Date: Thu, 19 Apr 2018 10:44:33 -0700
|
|
Jan Kara |
27c3d6 |
Subject: [PATCH] fsnotify: Fix fsnotify_mark_connector race
|
|
Jan Kara |
27c3d6 |
Git-commit: d90a10e2444ba5a351fa695917258ff4c5709fa5
|
|
Jan Kara |
27c3d6 |
Patch-mainline: v4.17-rc3
|
|
Jan Kara |
27c3d6 |
References: bsc#1052766
|
|
Jan Kara |
27c3d6 |
|
|
Jan Kara |
27c3d6 |
fsnotify() acquires a reference to a fsnotify_mark_connector through
|
|
Jan Kara |
27c3d6 |
the SRCU-protected pointer to_tell->i_fsnotify_marks. However, it
|
|
Jan Kara |
27c3d6 |
appears that no precautions are taken in fsnotify_put_mark() to
|
|
Jan Kara |
27c3d6 |
ensure that fsnotify() drops its reference to this
|
|
Jan Kara |
27c3d6 |
fsnotify_mark_connector before assigning a value to its 'destroy_next'
|
|
Jan Kara |
27c3d6 |
field. This can result in fsnotify_put_mark() assigning a value
|
|
Jan Kara |
27c3d6 |
to a connector's 'destroy_next' field right before fsnotify() tries to
|
|
Jan Kara |
27c3d6 |
traverse the linked list referenced by the connector's 'list' field.
|
|
Jan Kara |
27c3d6 |
Since these two fields are members of the same union, this behavior
|
|
Jan Kara |
27c3d6 |
results in a kernel panic.
|
|
Jan Kara |
27c3d6 |
|
|
Jan Kara |
27c3d6 |
This issue is resolved by moving the connector's 'destroy_next' field
|
|
Jan Kara |
27c3d6 |
into the object pointer union. This should work since the object pointer
|
|
Jan Kara |
27c3d6 |
access is protected by both a spinlock and the value of the 'flags'
|
|
Jan Kara |
27c3d6 |
field, and the 'flags' field is cleared while holding the spinlock in
|
|
Jan Kara |
27c3d6 |
fsnotify_put_mark() before 'destroy_next' is updated. It shouldn't be
|
|
Jan Kara |
27c3d6 |
possible for another thread to accidentally read from the object pointer
|
|
Jan Kara |
27c3d6 |
after the 'destroy_next' field is updated.
|
|
Jan Kara |
27c3d6 |
|
|
Jan Kara |
27c3d6 |
The offending behavior here is extremely unlikely; since
|
|
Jan Kara |
27c3d6 |
fsnotify_put_mark() removes references to a connector (specifically,
|
|
Jan Kara |
27c3d6 |
it ensures that the connector is unreachable from the inode it was
|
|
Jan Kara |
27c3d6 |
formerly attached to) before updating its 'destroy_next' field, a
|
|
Jan Kara |
27c3d6 |
sizeable chunk of code in fsnotify_put_mark() has to execute in the
|
|
Jan Kara |
27c3d6 |
short window between when fsnotify() acquires the connector reference
|
|
Jan Kara |
27c3d6 |
and saves the value of its 'list' field. On the HEAD kernel, I've only
|
|
Jan Kara |
27c3d6 |
been able to reproduce this by inserting a udelay(1) in fsnotify().
|
|
Jan Kara |
27c3d6 |
However, I've been able to reproduce this issue without inserting a
|
|
Jan Kara |
27c3d6 |
udelay(1) anywhere on older unmodified release kernels, so I believe
|
|
Jan Kara |
27c3d6 |
it's worth fixing at HEAD.
|
|
Jan Kara |
27c3d6 |
|
|
Jan Kara |
27c3d6 |
References: https://bugzilla.kernel.org/show_bug.cgi?id=199437
|
|
Jan Kara |
27c3d6 |
Fixes: 08991e83b7286635167bab40927665a90fb00d81
|
|
Jan Kara |
27c3d6 |
Cc: stable@vger.kernel.org
|
|
Jan Kara |
27c3d6 |
Signed-off-by: Robert Kolchmeyer <rkolchmeyer@google.com>
|
|
Jan Kara |
27c3d6 |
Signed-off-by: Jan Kara <jack@suse.cz>
|
|
Jan Kara |
27c3d6 |
Acked-by: Jan Kara <jack@suse.cz>
|
|
Jan Kara |
27c3d6 |
|
|
Jan Kara |
27c3d6 |
---
|
|
Jan Kara |
27c3d6 |
include/linux/fsnotify_backend.h | 4 +---
|
|
Jan Kara |
27c3d6 |
1 file changed, 1 insertion(+), 3 deletions(-)
|
|
Jan Kara |
27c3d6 |
|
|
Jan Kara |
27c3d6 |
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
|
|
Jan Kara |
27c3d6 |
index 9f1edb92c97e..a3d13d874fd1 100644
|
|
Jan Kara |
27c3d6 |
--- a/include/linux/fsnotify_backend.h
|
|
Jan Kara |
27c3d6 |
+++ b/include/linux/fsnotify_backend.h
|
|
Jan Kara |
27c3d6 |
@@ -217,12 +217,10 @@ struct fsnotify_mark_connector {
|
|
Jan Kara |
27c3d6 |
union { /* Object pointer [lock] */
|
|
Jan Kara |
27c3d6 |
struct inode *inode;
|
|
Jan Kara |
27c3d6 |
struct vfsmount *mnt;
|
|
Jan Kara |
27c3d6 |
- };
|
|
Jan Kara |
27c3d6 |
- union {
|
|
Jan Kara |
27c3d6 |
- struct hlist_head list;
|
|
Jan Kara |
27c3d6 |
/* Used listing heads to free after srcu period expires */
|
|
Jan Kara |
27c3d6 |
struct fsnotify_mark_connector *destroy_next;
|
|
Jan Kara |
27c3d6 |
};
|
|
Jan Kara |
27c3d6 |
+ struct hlist_head list;
|
|
Jan Kara |
27c3d6 |
};
|
|
Jan Kara |
27c3d6 |
|
|
Jan Kara |
27c3d6 |
/*
|
|
Jan Kara |
27c3d6 |
--
|
|
Jan Kara |
27c3d6 |
2.13.6
|
|
Jan Kara |
27c3d6 |
|