1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2014 SUSE. All Rights Reserved. 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * Started by Jan Kara <jack@suse.cz> 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci 8f08c3bdfSopenharmony_ci/*\ 9f08c3bdfSopenharmony_ci * [Description] 10f08c3bdfSopenharmony_ci * Check that fanotify properly merges ignore mask of an inode and mountpoint. 11f08c3bdfSopenharmony_ci */ 12f08c3bdfSopenharmony_ci 13f08c3bdfSopenharmony_ci/* 14f08c3bdfSopenharmony_ci * This is a regression test for: 15f08c3bdfSopenharmony_ci * 16f08c3bdfSopenharmony_ci * commit 8edc6e1688fc8f02c8c1f53a2ec4928cb1055f4d 17f08c3bdfSopenharmony_ci * Author: Jan Kara <jack@suse.cz> 18f08c3bdfSopenharmony_ci * Date: Thu Nov 13 15:19:33 2014 -0800 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * fanotify: fix notification of groups with inode & mount marks 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * The overlayfs test case is a regression test for: 23f08c3bdfSopenharmony_ci * 24f08c3bdfSopenharmony_ci * commit d989903058a83e8536cc7aadf9256a47d5c173fe 25f08c3bdfSopenharmony_ci * Author: Amir Goldstein <amir73il@gmail.com> 26f08c3bdfSopenharmony_ci * Date: Wed Apr 24 19:39:50 2019 +0300 27f08c3bdfSopenharmony_ci * 28f08c3bdfSopenharmony_ci * ovl: do not generate duplicate fsnotify events for "fake" path 29f08c3bdfSopenharmony_ci */ 30f08c3bdfSopenharmony_ci 31f08c3bdfSopenharmony_ci#define _GNU_SOURCE 32f08c3bdfSopenharmony_ci#include "config.h" 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_ci#include <stdio.h> 35f08c3bdfSopenharmony_ci#include <sys/stat.h> 36f08c3bdfSopenharmony_ci#include <sys/types.h> 37f08c3bdfSopenharmony_ci#include <errno.h> 38f08c3bdfSopenharmony_ci#include <string.h> 39f08c3bdfSopenharmony_ci#include <sys/mount.h> 40f08c3bdfSopenharmony_ci#include <sys/syscall.h> 41f08c3bdfSopenharmony_ci#include "tst_test.h" 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_FANOTIFY_H 44f08c3bdfSopenharmony_ci#include "fanotify.h" 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci#define EVENT_MAX 1024 47f08c3bdfSopenharmony_ci/* size of the event structure, not counting name */ 48f08c3bdfSopenharmony_ci#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) 49f08c3bdfSopenharmony_ci/* reasonable guess as to size of 1024 events */ 50f08c3bdfSopenharmony_ci#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_cistatic unsigned int fanotify_prio[] = { 53f08c3bdfSopenharmony_ci FAN_CLASS_PRE_CONTENT, 54f08c3bdfSopenharmony_ci FAN_CLASS_CONTENT, 55f08c3bdfSopenharmony_ci FAN_CLASS_NOTIF 56f08c3bdfSopenharmony_ci}; 57f08c3bdfSopenharmony_ci#define FANOTIFY_PRIORITIES ARRAY_SIZE(fanotify_prio) 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ci#define GROUPS_PER_PRIO 3 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_ci#define BUF_SIZE 256 62f08c3bdfSopenharmony_cistatic char fname[BUF_SIZE]; 63f08c3bdfSopenharmony_cistatic int fd_notify[FANOTIFY_PRIORITIES][GROUPS_PER_PRIO]; 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_cistatic char event_buf[EVENT_BUF_LEN]; 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_cistatic const char mntpoint[] = OVL_BASE_MNTPOINT; 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_cistatic int ovl_mounted; 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_cistatic struct tcase { 72f08c3bdfSopenharmony_ci const char *tname; 73f08c3bdfSopenharmony_ci const char *mnt; 74f08c3bdfSopenharmony_ci int use_overlay; 75f08c3bdfSopenharmony_ci} tcases[] = { 76f08c3bdfSopenharmony_ci { "Fanotify merge mount mark", mntpoint, 0 }, 77f08c3bdfSopenharmony_ci { "Fanotify merge overlayfs mount mark", OVL_MNT, 1 }, 78f08c3bdfSopenharmony_ci}; 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_cistatic void create_fanotify_groups(void) 81f08c3bdfSopenharmony_ci{ 82f08c3bdfSopenharmony_ci unsigned int p, i; 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci for (p = 0; p < FANOTIFY_PRIORITIES; p++) { 85f08c3bdfSopenharmony_ci for (i = 0; i < GROUPS_PER_PRIO; i++) { 86f08c3bdfSopenharmony_ci fd_notify[p][i] = SAFE_FANOTIFY_INIT(fanotify_prio[p] | 87f08c3bdfSopenharmony_ci FAN_NONBLOCK, 88f08c3bdfSopenharmony_ci O_RDONLY); 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci /* Add mount mark for each group */ 91f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd_notify[p][i], 92f08c3bdfSopenharmony_ci FAN_MARK_ADD | FAN_MARK_MOUNT, 93f08c3bdfSopenharmony_ci FAN_MODIFY, 94f08c3bdfSopenharmony_ci AT_FDCWD, fname); 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci /* Add ignore mark for groups with higher priority */ 97f08c3bdfSopenharmony_ci if (p == 0) 98f08c3bdfSopenharmony_ci continue; 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd_notify[p][i], 101f08c3bdfSopenharmony_ci FAN_MARK_ADD | 102f08c3bdfSopenharmony_ci FAN_MARK_IGNORED_MASK | 103f08c3bdfSopenharmony_ci FAN_MARK_IGNORED_SURV_MODIFY, 104f08c3bdfSopenharmony_ci FAN_MODIFY, AT_FDCWD, fname); 105f08c3bdfSopenharmony_ci } 106f08c3bdfSopenharmony_ci } 107f08c3bdfSopenharmony_ci} 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_cistatic void cleanup_fanotify_groups(void) 110f08c3bdfSopenharmony_ci{ 111f08c3bdfSopenharmony_ci unsigned int i, p; 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci for (p = 0; p < FANOTIFY_PRIORITIES; p++) { 114f08c3bdfSopenharmony_ci for (i = 0; i < GROUPS_PER_PRIO; i++) { 115f08c3bdfSopenharmony_ci if (fd_notify[p][i] > 0) 116f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify[p][i]); 117f08c3bdfSopenharmony_ci } 118f08c3bdfSopenharmony_ci } 119f08c3bdfSopenharmony_ci} 120f08c3bdfSopenharmony_ci 121f08c3bdfSopenharmony_cistatic void verify_event(int group, struct fanotify_event_metadata *event) 122f08c3bdfSopenharmony_ci{ 123f08c3bdfSopenharmony_ci if (event->mask != FAN_MODIFY) { 124f08c3bdfSopenharmony_ci tst_res(TFAIL, "group %d got event: mask %llx (expected %llx) " 125f08c3bdfSopenharmony_ci "pid=%u fd=%d", group, (unsigned long long)event->mask, 126f08c3bdfSopenharmony_ci (unsigned long long)FAN_MODIFY, 127f08c3bdfSopenharmony_ci (unsigned int)event->pid, event->fd); 128f08c3bdfSopenharmony_ci } else if (event->pid != getpid()) { 129f08c3bdfSopenharmony_ci tst_res(TFAIL, "group %d got event: mask %llx pid=%u " 130f08c3bdfSopenharmony_ci "(expected %u) fd=%d", group, 131f08c3bdfSopenharmony_ci (unsigned long long)event->mask, (unsigned int)event->pid, 132f08c3bdfSopenharmony_ci (unsigned int)getpid(), event->fd); 133f08c3bdfSopenharmony_ci } else { 134f08c3bdfSopenharmony_ci tst_res(TPASS, "group %d got event: mask %llx pid=%u fd=%d", 135f08c3bdfSopenharmony_ci group, (unsigned long long)event->mask, 136f08c3bdfSopenharmony_ci (unsigned int)event->pid, event->fd); 137f08c3bdfSopenharmony_ci } 138f08c3bdfSopenharmony_ci} 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_ci/* Close all file descriptors of read events */ 141f08c3bdfSopenharmony_cistatic void close_events_fd(struct fanotify_event_metadata *event, int buflen) 142f08c3bdfSopenharmony_ci{ 143f08c3bdfSopenharmony_ci while (buflen >= (int)FAN_EVENT_METADATA_LEN) { 144f08c3bdfSopenharmony_ci if (event->fd != FAN_NOFD) 145f08c3bdfSopenharmony_ci SAFE_CLOSE(event->fd); 146f08c3bdfSopenharmony_ci buflen -= (int)FAN_EVENT_METADATA_LEN; 147f08c3bdfSopenharmony_ci event++; 148f08c3bdfSopenharmony_ci } 149f08c3bdfSopenharmony_ci} 150f08c3bdfSopenharmony_ci 151f08c3bdfSopenharmony_cistatic void test_fanotify(unsigned int n) 152f08c3bdfSopenharmony_ci{ 153f08c3bdfSopenharmony_ci int ret; 154f08c3bdfSopenharmony_ci unsigned int p, i; 155f08c3bdfSopenharmony_ci struct fanotify_event_metadata *event; 156f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 157f08c3bdfSopenharmony_ci 158f08c3bdfSopenharmony_ci tst_res(TINFO, "Test #%d: %s", n, tc->tname); 159f08c3bdfSopenharmony_ci 160f08c3bdfSopenharmony_ci if (tc->use_overlay && !ovl_mounted) { 161f08c3bdfSopenharmony_ci tst_res(TCONF, "overlayfs is not configured in this kernel"); 162f08c3bdfSopenharmony_ci return; 163f08c3bdfSopenharmony_ci } 164f08c3bdfSopenharmony_ci 165f08c3bdfSopenharmony_ci sprintf(fname, "%s/tfile_%d", tc->mnt, getpid()); 166f08c3bdfSopenharmony_ci SAFE_TOUCH(fname, 0644, NULL); 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_ci create_fanotify_groups(); 169f08c3bdfSopenharmony_ci 170f08c3bdfSopenharmony_ci /* 171f08c3bdfSopenharmony_ci * generate sequence of events 172f08c3bdfSopenharmony_ci */ 173f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(fname, "1"); 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_ci /* First verify all groups without ignore mask got the event */ 176f08c3bdfSopenharmony_ci for (i = 0; i < GROUPS_PER_PRIO; i++) { 177f08c3bdfSopenharmony_ci ret = read(fd_notify[0][i], event_buf, EVENT_BUF_LEN); 178f08c3bdfSopenharmony_ci if (ret < 0) { 179f08c3bdfSopenharmony_ci if (errno == EAGAIN) { 180f08c3bdfSopenharmony_ci tst_res(TFAIL, "group %d did not get " 181f08c3bdfSopenharmony_ci "event", i); 182f08c3bdfSopenharmony_ci } 183f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, 184f08c3bdfSopenharmony_ci "reading fanotify events failed"); 185f08c3bdfSopenharmony_ci } 186f08c3bdfSopenharmony_ci if (ret < (int)FAN_EVENT_METADATA_LEN) { 187f08c3bdfSopenharmony_ci tst_brk(TBROK, 188f08c3bdfSopenharmony_ci "short read when reading fanotify " 189f08c3bdfSopenharmony_ci "events (%d < %d)", ret, 190f08c3bdfSopenharmony_ci (int)EVENT_BUF_LEN); 191f08c3bdfSopenharmony_ci } 192f08c3bdfSopenharmony_ci event = (struct fanotify_event_metadata *)event_buf; 193f08c3bdfSopenharmony_ci if (ret > (int)event->event_len) { 194f08c3bdfSopenharmony_ci tst_res(TFAIL, "group %d got more than one " 195f08c3bdfSopenharmony_ci "event (%d > %d)", i, ret, 196f08c3bdfSopenharmony_ci event->event_len); 197f08c3bdfSopenharmony_ci } else { 198f08c3bdfSopenharmony_ci verify_event(i, event); 199f08c3bdfSopenharmony_ci } 200f08c3bdfSopenharmony_ci close_events_fd(event, ret); 201f08c3bdfSopenharmony_ci } 202f08c3bdfSopenharmony_ci 203f08c3bdfSopenharmony_ci for (p = 1; p < FANOTIFY_PRIORITIES; p++) { 204f08c3bdfSopenharmony_ci for (i = 0; i < GROUPS_PER_PRIO; i++) { 205f08c3bdfSopenharmony_ci ret = read(fd_notify[p][i], event_buf, EVENT_BUF_LEN); 206f08c3bdfSopenharmony_ci if (ret > 0) { 207f08c3bdfSopenharmony_ci tst_res(TFAIL, "group %d got event", 208f08c3bdfSopenharmony_ci p*GROUPS_PER_PRIO + i); 209f08c3bdfSopenharmony_ci close_events_fd((void *)event_buf, ret); 210f08c3bdfSopenharmony_ci } else if (ret == 0) { 211f08c3bdfSopenharmony_ci tst_brk(TBROK, "zero length " 212f08c3bdfSopenharmony_ci "read from fanotify fd"); 213f08c3bdfSopenharmony_ci } else if (errno != EAGAIN) { 214f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, 215f08c3bdfSopenharmony_ci "reading fanotify events failed"); 216f08c3bdfSopenharmony_ci } else { 217f08c3bdfSopenharmony_ci tst_res(TPASS, "group %d got no event", 218f08c3bdfSopenharmony_ci p*GROUPS_PER_PRIO + i); 219f08c3bdfSopenharmony_ci } 220f08c3bdfSopenharmony_ci } 221f08c3bdfSopenharmony_ci } 222f08c3bdfSopenharmony_ci cleanup_fanotify_groups(); 223f08c3bdfSopenharmony_ci} 224f08c3bdfSopenharmony_ci 225f08c3bdfSopenharmony_cistatic void setup(void) 226f08c3bdfSopenharmony_ci{ 227f08c3bdfSopenharmony_ci ovl_mounted = TST_MOUNT_OVERLAY(); 228f08c3bdfSopenharmony_ci} 229f08c3bdfSopenharmony_ci 230f08c3bdfSopenharmony_cistatic void cleanup(void) 231f08c3bdfSopenharmony_ci{ 232f08c3bdfSopenharmony_ci cleanup_fanotify_groups(); 233f08c3bdfSopenharmony_ci 234f08c3bdfSopenharmony_ci if (ovl_mounted) 235f08c3bdfSopenharmony_ci SAFE_UMOUNT(OVL_MNT); 236f08c3bdfSopenharmony_ci} 237f08c3bdfSopenharmony_ci 238f08c3bdfSopenharmony_cistatic struct tst_test test = { 239f08c3bdfSopenharmony_ci .test = test_fanotify, 240f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 241f08c3bdfSopenharmony_ci .setup = setup, 242f08c3bdfSopenharmony_ci .cleanup = cleanup, 243f08c3bdfSopenharmony_ci .needs_root = 1, 244f08c3bdfSopenharmony_ci .mount_device = 1, 245f08c3bdfSopenharmony_ci .mntpoint = mntpoint, 246f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 247f08c3bdfSopenharmony_ci {"linux-git", "8edc6e1688fc"}, 248f08c3bdfSopenharmony_ci {"linux-git", "d989903058a8"}, 249f08c3bdfSopenharmony_ci {} 250f08c3bdfSopenharmony_ci } 251f08c3bdfSopenharmony_ci}; 252f08c3bdfSopenharmony_ci 253f08c3bdfSopenharmony_ci#else 254f08c3bdfSopenharmony_ci TST_TEST_TCONF("system doesn't have required fanotify support"); 255f08c3bdfSopenharmony_ci#endif 256