Skip to content

Commit f2bc9c9

Browse files
committed
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()
2 parents bf3bd96 + b1da6a5 commit f2bc9c9

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

fs/notify/fanotify/fanotify.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,10 +346,16 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
346346
__kernel_fsid_t fsid = {};
347347

348348
fsnotify_foreach_obj_type(type) {
349+
struct fsnotify_mark_connector *conn;
350+
349351
if (!fsnotify_iter_should_report_type(iter_info, type))
350352
continue;
351353

352-
fsid = iter_info->marks[type]->connector->fsid;
354+
conn = READ_ONCE(iter_info->marks[type]->connector);
355+
/* Mark is just getting destroyed or created? */
356+
if (!conn)
357+
continue;
358+
fsid = conn->fsid;
353359
if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1]))
354360
continue;
355361
return fsid;
@@ -408,8 +414,12 @@ static int fanotify_handle_event(struct fsnotify_group *group,
408414
return 0;
409415
}
410416

411-
if (FAN_GROUP_FLAG(group, FAN_REPORT_FID))
417+
if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
412418
fsid = fanotify_get_fsid(iter_info);
419+
/* Racing with mark destruction or creation? */
420+
if (!fsid.val[0] && !fsid.val[1])
421+
return 0;
422+
}
413423

414424
event = fanotify_alloc_event(group, inode, mask, data, data_type,
415425
&fsid);

fs/notify/mark.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,13 @@ static void fsnotify_drop_object(unsigned int type, void *objp)
239239

240240
void fsnotify_put_mark(struct fsnotify_mark *mark)
241241
{
242-
struct fsnotify_mark_connector *conn;
242+
struct fsnotify_mark_connector *conn = READ_ONCE(mark->connector);
243243
void *objp = NULL;
244244
unsigned int type = FSNOTIFY_OBJ_TYPE_DETACHED;
245245
bool free_conn = false;
246246

247247
/* Catch marks that were actually never attached to object */
248-
if (!mark->connector) {
248+
if (!conn) {
249249
if (refcount_dec_and_test(&mark->refcnt))
250250
fsnotify_final_mark_destroy(mark);
251251
return;
@@ -255,18 +255,17 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
255255
* We have to be careful so that traversals of obj_list under lock can
256256
* safely grab mark reference.
257257
*/
258-
if (!refcount_dec_and_lock(&mark->refcnt, &mark->connector->lock))
258+
if (!refcount_dec_and_lock(&mark->refcnt, &conn->lock))
259259
return;
260260

261-
conn = mark->connector;
262261
hlist_del_init_rcu(&mark->obj_list);
263262
if (hlist_empty(&conn->list)) {
264263
objp = fsnotify_detach_connector_from_object(conn, &type);
265264
free_conn = true;
266265
} else {
267266
__fsnotify_recalc_mask(conn);
268267
}
269-
mark->connector = NULL;
268+
WRITE_ONCE(mark->connector, NULL);
270269
spin_unlock(&conn->lock);
271270

272271
fsnotify_drop_object(type, objp);
@@ -620,7 +619,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
620619
/* mark should be the last entry. last is the current last entry */
621620
hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
622621
added:
623-
mark->connector = conn;
622+
WRITE_ONCE(mark->connector, conn);
624623
out_err:
625624
spin_unlock(&conn->lock);
626625
spin_unlock(&mark->lock);
@@ -808,6 +807,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark,
808807
refcount_set(&mark->refcnt, 1);
809808
fsnotify_get_group(group);
810809
mark->group = group;
810+
WRITE_ONCE(mark->connector, NULL);
811811
}
812812

813813
/*

0 commit comments

Comments
 (0)