186 lines
4.3 KiB
C
186 lines
4.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2018 Matthew Bobrowski. All Rights Reserved.
|
|
*
|
|
* Started by Matthew Bobrowski <mbobrowski@mbobrowski.org>
|
|
*/
|
|
|
|
/*\
|
|
* [Description]
|
|
* This test file has been designed to ensure that the fanotify
|
|
* system calls fanotify_init(2) and fanotify_mark(2) return the
|
|
* correct error code to the calling process when an invalid flag or
|
|
* mask value has been specified in conjunction with FAN_REPORT_FID.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include "tst_test.h"
|
|
#include <errno.h>
|
|
|
|
#ifdef HAVE_SYS_FANOTIFY_H
|
|
#include "fanotify.h"
|
|
|
|
#define MNTPOINT "mntpoint"
|
|
#define FILE1 MNTPOINT"/file1"
|
|
|
|
/*
|
|
* List of inode events that are only available when notification group is
|
|
* set to report fid.
|
|
*/
|
|
#define INODE_EVENTS (FAN_ATTRIB | FAN_CREATE | FAN_DELETE | FAN_MOVE | \
|
|
FAN_DELETE_SELF | FAN_MOVE_SELF)
|
|
|
|
static int fanotify_fd;
|
|
|
|
/*
|
|
* Each test case has been designed in a manner whereby the values defined
|
|
* within should result in the interface to return an error to the calling
|
|
* process.
|
|
*/
|
|
static struct test_case_t {
|
|
unsigned int init_flags;
|
|
unsigned int mark_flags;
|
|
unsigned long long mask;
|
|
} test_cases[] = {
|
|
{
|
|
FAN_CLASS_CONTENT | FAN_REPORT_FID, 0, 0
|
|
},
|
|
{
|
|
FAN_CLASS_PRE_CONTENT | FAN_REPORT_FID, 0, 0
|
|
},
|
|
{
|
|
FAN_CLASS_NOTIF, 0, INODE_EVENTS
|
|
},
|
|
{
|
|
FAN_CLASS_NOTIF | FAN_REPORT_FID, FAN_MARK_MOUNT, INODE_EVENTS
|
|
},
|
|
{
|
|
/* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */
|
|
FAN_CLASS_NOTIF | FAN_REPORT_NAME, 0, 0
|
|
},
|
|
{
|
|
/* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */
|
|
FAN_CLASS_NOTIF | FAN_REPORT_FID | FAN_REPORT_NAME, 0, 0
|
|
},
|
|
};
|
|
|
|
static void do_test(unsigned int number)
|
|
{
|
|
int ret;
|
|
struct test_case_t *tc = &test_cases[number];
|
|
|
|
fanotify_fd = fanotify_init(tc->init_flags, O_RDONLY);
|
|
if (fanotify_fd < 0) {
|
|
/*
|
|
* EINVAL is to be returned to the calling process when
|
|
* an invalid notification class is specified in
|
|
* conjunction with FAN_REPORT_FID.
|
|
*/
|
|
if (errno == EINVAL) {
|
|
tst_res(TPASS,
|
|
"fanotify_fd=%d, fanotify_init(%x, O_RDONLY) "
|
|
"failed with error EINVAL as expected",
|
|
fanotify_fd,
|
|
tc->init_flags);
|
|
return;
|
|
}
|
|
tst_brk(TBROK | TERRNO,
|
|
"fanotify_fd=%d, fanotify_init(%x, O_RDONLY) failed",
|
|
fanotify_fd,
|
|
tc->init_flags);
|
|
}
|
|
|
|
/*
|
|
* A test case with a mask set to zero indicate that they've been
|
|
* specifically designed to test and fail on the fanotify_init()
|
|
* system call.
|
|
*/
|
|
if (tc->mask == 0) {
|
|
tst_res(TFAIL,
|
|
"fanotify_fd=%d fanotify_init(%x, O_RDONLY) "
|
|
"unexpectedly succeeded when tests with mask 0 are"
|
|
"expected to fail when calling fanotify_init()",
|
|
fanotify_fd,
|
|
tc->init_flags);
|
|
goto out;
|
|
}
|
|
|
|
ret = fanotify_mark(fanotify_fd, FAN_MARK_ADD | tc->mark_flags,
|
|
tc->mask, AT_FDCWD, FILE1);
|
|
if (ret < 0) {
|
|
/*
|
|
* EINVAL is to be returned to the calling process when
|
|
* attempting to use INODE_EVENTS without FAN_REPORT_FID
|
|
* specified on the notification group, or using
|
|
* INODE_EVENTS with mark type FAN_MARK_MOUNT.
|
|
*/
|
|
if (errno == EINVAL) {
|
|
tst_res(TPASS,
|
|
"ret=%d, fanotify_mark(%d, FAN_MARK_ADD | %x, "
|
|
"%llx, AT_FDCWD, %s) failed with error EINVAL "
|
|
"as expected",
|
|
ret,
|
|
fanotify_fd,
|
|
tc->mark_flags,
|
|
tc->mask,
|
|
FILE1);
|
|
goto out;
|
|
}
|
|
tst_brk(TBROK | TERRNO,
|
|
"ret=%d, fanotify_mark(%d, FAN_MARK_ADD | %x, %llx, "
|
|
"AT_FDCWD, %s) failed",
|
|
ret,
|
|
fanotify_fd,
|
|
tc->mark_flags,
|
|
tc->mask,
|
|
FILE1);
|
|
}
|
|
|
|
tst_res(TFAIL,
|
|
"fanotify_fd=%d, ret=%d, fanotify_init(%x, O_RDONLY) and "
|
|
"fanotify_mark(%d, FAN_MARK_ADD | %x, %llx, AT_FDCWD, %s) did "
|
|
"not return any errors as expected",
|
|
fanotify_fd,
|
|
ret,
|
|
tc->init_flags,
|
|
fanotify_fd,
|
|
tc->mark_flags,
|
|
tc->mask,
|
|
FILE1);
|
|
out:
|
|
SAFE_CLOSE(fanotify_fd);
|
|
}
|
|
|
|
static void do_setup(void)
|
|
{
|
|
int fd;
|
|
|
|
/* Check for kernel fanotify support */
|
|
fd = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY);
|
|
SAFE_CLOSE(fd);
|
|
|
|
/* Create temporary test file to place marks on */
|
|
SAFE_FILE_PRINTF(FILE1, "0");
|
|
}
|
|
|
|
static void do_cleanup(void)
|
|
{
|
|
if (fanotify_fd > 0)
|
|
SAFE_CLOSE(fanotify_fd);
|
|
}
|
|
|
|
static struct tst_test test = {
|
|
.needs_root = 1,
|
|
.test = do_test,
|
|
.tcnt = ARRAY_SIZE(test_cases),
|
|
.setup = do_setup,
|
|
.cleanup = do_cleanup,
|
|
.mount_device = 1,
|
|
.mntpoint = MNTPOINT,
|
|
.all_filesystems = 1
|
|
};
|
|
|
|
#else
|
|
TST_TEST_TCONF("System does not have required fanotify support");
|
|
#endif
|