Skip to content

Commit

Permalink
syscalls/fanotify10: Add test cases for merge with ignored mask on di…
Browse files Browse the repository at this point in the history
…rectory

Pre kernel v5.9, a child mark with ignored mask would not prevent the
delivery of events to a watching parent of that child.

This was fixed by kernel commit eca4784cbb18 ("fsnotify: send event to
parent and child with single callback").

We add test cases for combination of mark of a directory with ignored
mask either watching children or not.

Verified that existing test cases still fail on old kernels without the
relevant fix commits.

In current kernel, there is a limitation that requires setting the event
also in the parent's mask for ignore mask to be correctly merged with
other marks. This is a temporary workaround that could be removed in
the future when the correct behavior could be tested.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Petr Vorel <pvorel@suse.cz>
  • Loading branch information
amir73il authored and pevik committed Sep 10, 2020
1 parent 6ee1c5d commit ad226e0
Showing 1 changed file with 99 additions and 10 deletions.
109 changes: 99 additions & 10 deletions testcases/kernel/syscalls/fanotify/fanotify10.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
* Test case #16 is a regression test for commit:
*
* 2f02fd3fa13e fanotify: fix ignore mask logic for events on child...
*
* Test cases #17-#23 are regression tests for commit:
*
* eca4784cbb18 fsnotify: send event to parent and child with single...
*/
#define _GNU_SOURCE
#include "config.h"
Expand Down Expand Up @@ -97,6 +101,7 @@ static struct tcase {
int mark_type;
const char *ignore_path;
int ignore_mark_type;
unsigned int ignored_onchild;
const char *event_path;
unsigned long long expected_mask_with_ignore;
unsigned long long expected_mask_without_ignore;
Expand All @@ -105,114 +110,181 @@ static struct tcase {
"ignore mount events created on a specific file",
MOUNT_PATH, FANOTIFY_MOUNT,
FILE_MNT2, FANOTIFY_INODE,
0,
FILE_PATH, 0, FAN_OPEN
},
{
"ignore exec mount events created on a specific file",
MOUNT_PATH, FANOTIFY_MOUNT,
FILE_EXEC_PATH2, FANOTIFY_INODE,
0,
FILE_EXEC_PATH, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC
},
{
"don't ignore mount events created on another file",
MOUNT_PATH, FANOTIFY_MOUNT,
FILE_PATH, FANOTIFY_INODE,
0,
FILE2_PATH, FAN_OPEN, FAN_OPEN
},
{
"don't ignore exec mount events created on another file",
MOUNT_PATH, FANOTIFY_MOUNT,
FILE_EXEC_PATH, FANOTIFY_INODE,
0,
FILE2_EXEC_PATH, FAN_OPEN | FAN_OPEN_EXEC,
FAN_OPEN | FAN_OPEN_EXEC
},
{
"ignore inode events created on a specific mount point",
FILE_PATH, FANOTIFY_INODE,
MNT2_PATH, FANOTIFY_MOUNT,
0,
FILE_MNT2, 0, FAN_OPEN
},
{
"ignore exec inode events created on a specific mount point",
FILE_EXEC_PATH, FANOTIFY_INODE,
MNT2_PATH, FANOTIFY_MOUNT,
0,
FILE_EXEC_PATH2, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC
},
{
"don't ignore inode events created on another mount point",
FILE_MNT2, FANOTIFY_INODE,
MNT2_PATH, FANOTIFY_MOUNT,
0,
FILE_PATH, FAN_OPEN, FAN_OPEN
},
{
"don't ignore exec inode events created on another mount point",
FILE_EXEC_PATH2, FANOTIFY_INODE,
MNT2_PATH, FANOTIFY_MOUNT,
0,
FILE_EXEC_PATH, FAN_OPEN | FAN_OPEN_EXEC,
FAN_OPEN | FAN_OPEN_EXEC
},
{
"ignore fs events created on a specific file",
MOUNT_PATH, FANOTIFY_FILESYSTEM,
FILE_PATH, FANOTIFY_INODE,
0,
FILE_PATH, 0, FAN_OPEN
},
{
"ignore exec fs events created on a specific file",
MOUNT_PATH, FANOTIFY_FILESYSTEM,
FILE_EXEC_PATH, FANOTIFY_INODE,
0,
FILE_EXEC_PATH, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC
},
{
"don't ignore mount events created on another file",
MOUNT_PATH, FANOTIFY_FILESYSTEM,
FILE_PATH, FANOTIFY_INODE,
0,
FILE2_PATH, FAN_OPEN, FAN_OPEN
},
{
"don't ignore exec mount events created on another file",
MOUNT_PATH, FANOTIFY_FILESYSTEM,
FILE_EXEC_PATH, FANOTIFY_INODE,
0,
FILE2_EXEC_PATH, FAN_OPEN | FAN_OPEN_EXEC,
FAN_OPEN | FAN_OPEN_EXEC
},
{
"ignore fs events created on a specific mount point",
MOUNT_PATH, FANOTIFY_FILESYSTEM,
MNT2_PATH, FANOTIFY_MOUNT,
0,
FILE_MNT2, 0, FAN_OPEN
},
{
"ignore exec fs events created on a specific mount point",
MOUNT_PATH, FANOTIFY_FILESYSTEM,
MNT2_PATH, FANOTIFY_MOUNT,
0,
FILE_EXEC_PATH2, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC
},
{
"don't ignore fs events created on another mount point",
MOUNT_PATH, FANOTIFY_FILESYSTEM,
MNT2_PATH, FANOTIFY_MOUNT,
0,
FILE_PATH, FAN_OPEN, FAN_OPEN
},
{
"don't ignore exec fs events created on another mount point",
MOUNT_PATH, FANOTIFY_FILESYSTEM,
MNT2_PATH, FANOTIFY_MOUNT,
0,
FILE_EXEC_PATH, FAN_OPEN | FAN_OPEN_EXEC,
FAN_OPEN | FAN_OPEN_EXEC
},
{
"ignore child exec events created on a specific mount point",
MOUNT_PATH, FANOTIFY_INODE,
MOUNT_PATH, FANOTIFY_MOUNT,
0,
FILE_EXEC_PATH, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC
},
{
"ignore events on children of directory created on a specific file",
MNT2_PATH, FANOTIFY_INODE,
FILE_PATH, FANOTIFY_INODE,
FAN_EVENT_ON_CHILD,
FILE_PATH, 0, FAN_OPEN
},
{
"ignore events on file created inside a parent watching children",
FILE_PATH, FANOTIFY_INODE,
MNT2_PATH, FANOTIFY_INODE,
FAN_EVENT_ON_CHILD,
FILE_PATH, 0, FAN_OPEN
},
{
"don't ignore events on file created inside a parent not watching children",
FILE_PATH, FANOTIFY_INODE,
MNT2_PATH, FANOTIFY_INODE,
0,
FILE_PATH, FAN_OPEN, FAN_OPEN
},
{
"ignore mount events created inside a parent watching children",
FILE_PATH, FANOTIFY_MOUNT,
MNT2_PATH, FANOTIFY_INODE,
FAN_EVENT_ON_CHILD,
FILE_PATH, 0, FAN_OPEN
},
{
"don't ignore mount events created inside a parent not watching children",
FILE_PATH, FANOTIFY_MOUNT,
MNT2_PATH, FANOTIFY_INODE,
0,
FILE_PATH, FAN_OPEN, FAN_OPEN
},
{
"ignore fs events created inside a parent watching children",
FILE_PATH, FANOTIFY_FILESYSTEM,
MNT2_PATH, FANOTIFY_INODE,
FAN_EVENT_ON_CHILD,
FILE_PATH, 0, FAN_OPEN
},
{
"don't ignore fs events created inside a parent not watching children",
FILE_PATH, FANOTIFY_FILESYSTEM,
MNT2_PATH, FANOTIFY_INODE,
0,
FILE_PATH, FAN_OPEN, FAN_OPEN
},
};

static int create_fanotify_groups(unsigned int n)
{
struct tcase *tc = &tcases[n];
struct fanotify_mark_type *mark, *ignore_mark;
unsigned int mark_ignored, mask;
unsigned int p, i;
int ret;

Expand Down Expand Up @@ -272,20 +344,36 @@ static int create_fanotify_groups(unsigned int n)
/* Add ignore mark for groups with higher priority */
if (p == 0)
continue;

mask = FAN_OPEN;
mark_ignored = FAN_MARK_IGNORED_MASK |
FAN_MARK_IGNORED_SURV_MODIFY;
add_mark:
ret = fanotify_mark(fd_notify[p][i],
FAN_MARK_ADD | ignore_mark->flag |
FAN_MARK_IGNORED_MASK |
FAN_MARK_IGNORED_SURV_MODIFY,
FAN_OPEN, AT_FDCWD,
tc->ignore_path);
FAN_MARK_ADD | ignore_mark->flag | mark_ignored,
mask, AT_FDCWD, tc->ignore_path);
if (ret < 0) {
tst_brk(TBROK | TERRNO,
"fanotify_mark(%d, FAN_MARK_ADD | %s | "
"FAN_MARK_IGNORED_MASK | "
"FAN_MARK_IGNORED_SURV_MODIFY, "
"FAN_OPEN, AT_FDCWD, %s) failed",
"fanotify_mark(%d, FAN_MARK_ADD | %s | %s, "
"%x, AT_FDCWD, %s) failed",
fd_notify[p][i], ignore_mark->name,
tc->ignore_path);
mark_ignored ? "FAN_MARK_IGNORED_MASK | "
"FAN_MARK_IGNORED_SURV_MODIFY" : "",
mask, tc->ignore_path);
}

/*
* If ignored mask is on a parent watching children,
* also set the flag FAN_EVENT_ON_CHILD in mark mask.
* This is needed to indicate that parent ignored mask
* should be applied to events on children.
*/
if (tc->ignored_onchild && mark_ignored) {
mask = tc->ignored_onchild;
/* XXX: temporary hack may be removed in the future */
mask |= FAN_OPEN;
mark_ignored = 0;
goto add_mark;
}
}
}
Expand Down Expand Up @@ -478,6 +566,7 @@ static struct tst_test test = {
.tags = (const struct tst_tag[]) {
{"linux-git", "9bdda4e9cf2d"},
{"linux-git", "2f02fd3fa13e"},
{"linux-git", "eca4784cbb18"},
{}
}
};
Expand Down

0 comments on commit ad226e0

Please sign in to comment.