Commit f2bc9c90 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fsnotify_for_v5.1-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fsnotify fix from Jan Kara:
 "A fix of user trigerable NULL pointer dereference syzbot has recently
  spotted.

  The problem was introduced in this merge window so no CC stable is
  needed"

* tag 'fsnotify_for_v5.1-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  fsnotify: Fix NULL ptr deref in fanotify_get_fsid()
parents bf3bd966 b1da6a51
...@@ -346,10 +346,16 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) ...@@ -346,10 +346,16 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
__kernel_fsid_t fsid = {}; __kernel_fsid_t fsid = {};
fsnotify_foreach_obj_type(type) { fsnotify_foreach_obj_type(type) {
struct fsnotify_mark_connector *conn;
if (!fsnotify_iter_should_report_type(iter_info, type)) if (!fsnotify_iter_should_report_type(iter_info, type))
continue; continue;
fsid = iter_info->marks[type]->connector->fsid; conn = READ_ONCE(iter_info->marks[type]->connector);
/* Mark is just getting destroyed or created? */
if (!conn)
continue;
fsid = conn->fsid;
if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1])) if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1]))
continue; continue;
return fsid; return fsid;
...@@ -408,8 +414,12 @@ static int fanotify_handle_event(struct fsnotify_group *group, ...@@ -408,8 +414,12 @@ static int fanotify_handle_event(struct fsnotify_group *group,
return 0; return 0;
} }
if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
fsid = fanotify_get_fsid(iter_info); fsid = fanotify_get_fsid(iter_info);
/* Racing with mark destruction or creation? */
if (!fsid.val[0] && !fsid.val[1])
return 0;
}
event = fanotify_alloc_event(group, inode, mask, data, data_type, event = fanotify_alloc_event(group, inode, mask, data, data_type,
&fsid); &fsid);
......
...@@ -239,13 +239,13 @@ static void fsnotify_drop_object(unsigned int type, void *objp) ...@@ -239,13 +239,13 @@ static void fsnotify_drop_object(unsigned int type, void *objp)
void fsnotify_put_mark(struct fsnotify_mark *mark) void fsnotify_put_mark(struct fsnotify_mark *mark)
{ {
struct fsnotify_mark_connector *conn; struct fsnotify_mark_connector *conn = READ_ONCE(mark->connector);
void *objp = NULL; void *objp = NULL;
unsigned int type = FSNOTIFY_OBJ_TYPE_DETACHED; unsigned int type = FSNOTIFY_OBJ_TYPE_DETACHED;
bool free_conn = false; bool free_conn = false;
/* Catch marks that were actually never attached to object */ /* Catch marks that were actually never attached to object */
if (!mark->connector) { if (!conn) {
if (refcount_dec_and_test(&mark->refcnt)) if (refcount_dec_and_test(&mark->refcnt))
fsnotify_final_mark_destroy(mark); fsnotify_final_mark_destroy(mark);
return; return;
...@@ -255,10 +255,9 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) ...@@ -255,10 +255,9 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
* We have to be careful so that traversals of obj_list under lock can * We have to be careful so that traversals of obj_list under lock can
* safely grab mark reference. * safely grab mark reference.
*/ */
if (!refcount_dec_and_lock(&mark->refcnt, &mark->connector->lock)) if (!refcount_dec_and_lock(&mark->refcnt, &conn->lock))
return; return;
conn = mark->connector;
hlist_del_init_rcu(&mark->obj_list); hlist_del_init_rcu(&mark->obj_list);
if (hlist_empty(&conn->list)) { if (hlist_empty(&conn->list)) {
objp = fsnotify_detach_connector_from_object(conn, &type); objp = fsnotify_detach_connector_from_object(conn, &type);
...@@ -266,7 +265,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) ...@@ -266,7 +265,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
} else { } else {
__fsnotify_recalc_mask(conn); __fsnotify_recalc_mask(conn);
} }
mark->connector = NULL; WRITE_ONCE(mark->connector, NULL);
spin_unlock(&conn->lock); spin_unlock(&conn->lock);
fsnotify_drop_object(type, objp); fsnotify_drop_object(type, objp);
...@@ -620,7 +619,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, ...@@ -620,7 +619,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
/* mark should be the last entry. last is the current last entry */ /* mark should be the last entry. last is the current last entry */
hlist_add_behind_rcu(&mark->obj_list, &last->obj_list); hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
added: added:
mark->connector = conn; WRITE_ONCE(mark->connector, conn);
out_err: out_err:
spin_unlock(&conn->lock); spin_unlock(&conn->lock);
spin_unlock(&mark->lock); spin_unlock(&mark->lock);
...@@ -808,6 +807,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark, ...@@ -808,6 +807,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark,
refcount_set(&mark->refcnt, 1); refcount_set(&mark->refcnt, 1);
fsnotify_get_group(group); fsnotify_get_group(group);
mark->group = group; mark->group = group;
WRITE_ONCE(mark->connector, NULL);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment