Skip to content

Commit fa218ab

Browse files
LinoSanfilippo333eparis
authored andcommitted
fanotify: correct broken ref counting in case adding a mark failed
If adding a mount or inode mark failed fanotify_free_mark() is called explicitly. But at this time the mark has already been put into the destroy list of the fsnotify_mark kernel thread. If the thread is too slow it will try to decrease the reference of a mark, that has already been freed by fanotify_free_mark(). (If its fast enough it will only decrease the marks ref counter from 2 to 1 - note that the counter has been increased to 2 in add_mark() - which has practically no effect.) This patch fixes the ref counting by not calling free_mark() explicitly, but decreasing the ref counter and rely on the fsnotify_mark thread to cleanup in case adding the mark has failed. Signed-off-by: Lino Sanfilippo <LinoSanfilippo@gmx.de> Signed-off-by: Eric Paris <eparis@redhat.com>
1 parent b1085ba commit fa218ab

File tree

1 file changed

+14
-17
lines changed

1 file changed

+14
-17
lines changed

fs/notify/fanotify/fanotify_user.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -594,11 +594,10 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
594594
{
595595
struct fsnotify_mark *fsn_mark;
596596
__u32 added;
597+
int ret = 0;
597598

598599
fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
599600
if (!fsn_mark) {
600-
int ret;
601-
602601
if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks)
603602
return -ENOSPC;
604603

@@ -608,17 +607,16 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
608607

609608
fsnotify_init_mark(fsn_mark, fanotify_free_mark);
610609
ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0);
611-
if (ret) {
612-
fanotify_free_mark(fsn_mark);
613-
return ret;
614-
}
610+
if (ret)
611+
goto err;
615612
}
616613
added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
617-
fsnotify_put_mark(fsn_mark);
614+
618615
if (added & ~mnt->mnt_fsnotify_mask)
619616
fsnotify_recalc_vfsmount_mask(mnt);
620-
621-
return 0;
617+
err:
618+
fsnotify_put_mark(fsn_mark);
619+
return ret;
622620
}
623621

624622
static int fanotify_add_inode_mark(struct fsnotify_group *group,
@@ -627,6 +625,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
627625
{
628626
struct fsnotify_mark *fsn_mark;
629627
__u32 added;
628+
int ret = 0;
630629

631630
pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
632631

@@ -642,8 +641,6 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
642641

643642
fsn_mark = fsnotify_find_inode_mark(group, inode);
644643
if (!fsn_mark) {
645-
int ret;
646-
647644
if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks)
648645
return -ENOSPC;
649646

@@ -653,16 +650,16 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
653650

654651
fsnotify_init_mark(fsn_mark, fanotify_free_mark);
655652
ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0);
656-
if (ret) {
657-
fanotify_free_mark(fsn_mark);
658-
return ret;
659-
}
653+
if (ret)
654+
goto err;
660655
}
661656
added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
662-
fsnotify_put_mark(fsn_mark);
657+
663658
if (added & ~inode->i_fsnotify_mask)
664659
fsnotify_recalc_inode_mask(inode);
665-
return 0;
660+
err:
661+
fsnotify_put_mark(fsn_mark);
662+
return ret;
666663
}
667664

668665
/* fanotify syscalls */

0 commit comments

Comments
 (0)