From patchwork Sun Sep 23 08:53:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amir Goldstein X-Patchwork-Id: 973646 X-Patchwork-Delegate: petr.vorel@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.linux.it (client-ip=2001:1418:10:5::2; helo=picard.linux.it; envelope-from=ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ktIyO7JY"; dkim-atps=neutral Received: from picard.linux.it (picard.linux.it [IPv6:2001:1418:10:5::2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42J1MR6Fmgz9s9h for ; Sun, 23 Sep 2018 18:53:20 +1000 (AEST) Received: from picard.linux.it (localhost [IPv6:::1]) by picard.linux.it (Postfix) with ESMTP id 74D613E70C2 for ; Sun, 23 Sep 2018 10:53:13 +0200 (CEST) X-Original-To: ltp@lists.linux.it Delivered-To: ltp@picard.linux.it Received: from in-4.smtp.seeweb.it (in-4.smtp.seeweb.it [217.194.8.4]) by picard.linux.it (Postfix) with ESMTP id 442B03E7095 for ; Sun, 23 Sep 2018 10:53:12 +0200 (CEST) Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by in-4.smtp.seeweb.it (Postfix) with ESMTPS id 127AA10004A2 for ; Sun, 23 Sep 2018 10:53:11 +0200 (CEST) Received: by mail-wr1-x441.google.com with SMTP id m16so219652wrx.12 for ; Sun, 23 Sep 2018 01:53:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=iDJ8KYVMxU5Vs4rpNAQjNifH01wfRjv/hz+PchIurrY=; b=ktIyO7JYmYB7U6gbIVhXsf2UjCHJirsvjrZAfcUq42c13HrKW/tx+wQ23Znr7tget1 76Uvnk03mi54rVOeq3+bOpmBG4Cd+30fmBfrhDwbF9TQuzy3dqK4sanGZe92VH1p2DuD 2JjDZtaNK5ThfWrZ5Y8Vdt3fr1bJ65RegkXIEKkwu7lurKRBlS0IxBQlAPzxJAbGQX3U irHaufvrdVzjYpEtbAzyI0E31wu7WYGXq5XdiqERbdAySYQ0TiZ4NamOA4zoRgcnYX04 ri10DwQCQ6CHBTgglHus85hziK/DU/EB6r4UTigtBJ+qMkUzU5HQPjGJYAQdbDW5VfVq vvGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=iDJ8KYVMxU5Vs4rpNAQjNifH01wfRjv/hz+PchIurrY=; b=kcfYijx2YFlHrdzP6oxbLxSuSRqwbg8qmoYd614u62YCVuf7NRl8MNfiLY/2CV60oG lCr9vuzKxx1U788kg46rFQ+Fr69izO7i2WTBKBmr16qb+rzKAngnEGdR9z9VEERxPGUO oKAcl1Sf1j3vbDr3VOO+sxs7eU1NLpaP55DPQ39M2pZPalLcwdJNnvrdsdSQpu/k1Zh9 QOZoCq5gieTJhfXRZCH7b5b2R5oUmqCQW35torG0w+C6JS1QYjP7QKzwcVO3VqEDSKH8 lvSO+HgLwU8u1G96K0pTD08YCIYOIfMi3/HuW6cARfTw5xZYCNx2TsV0YrqxzB3ssQng W0DA== X-Gm-Message-State: ABuFfoiXmTlo5hAVSGp1oXHCyOAX3EknGlZr3l98Eke+Tzcckxqthhaf /guXGmXyon3X6x6OsrufW4o= X-Google-Smtp-Source: ACcGV639KLpN9mWXu1h1meg9JRAPJ70/5XkBTkki+qSsiStxbYExVeNKz4dRBlyxiHPuFUoisCjEBw== X-Received: by 2002:adf:8567:: with SMTP id 94-v6mr4466613wrh.223.1537692790339; Sun, 23 Sep 2018 01:53:10 -0700 (PDT) Received: from localhost.localdomain ([141.226.14.107]) by smtp.gmail.com with ESMTPSA id y203-v6sm8034457wmd.1.2018.09.23.01.53.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 23 Sep 2018 01:53:09 -0700 (PDT) From: Amir Goldstein To: Cyril Hrubis Date: Sun, 23 Sep 2018 11:53:02 +0300 Message-Id: <20180923085302.29446-1-amir73il@gmail.com> X-Mailer: git-send-email 2.17.1 X-Virus-Scanned: clamav-milter 0.99.2 at in-4.smtp.seeweb.it X-Virus-Status: Clean X-Spam-Status: No, score=0.1 required=7.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, SPF_PASS autolearn=disabled version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on in-4.smtp.seeweb.it Cc: Jan Kara , ltp@lists.linux.it Subject: [LTP] [PATCH v2] syscalls/fanotify10: new test for mount ignore mask X-BeenThere: ltp@lists.linux.it X-Mailman-Version: 2.1.18 Precedence: list List-Id: Linux Test Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it Sender: "ltp" This is a regression test for commit: 9bdda4e9cf2d fsnotify: fix ignore mask logic in fsnotify() Signed-off-by: Amir Goldstein --- Cyril, Following discussion with you and Richard, I decided to leave fanotify06 unchanged, because this new test is sufficiently different and also fails on old kernels. I implemented the test with index and added 4 new test cases instead of just the one that checks the regression. This test structure makes it easy to add coverage for to the upcoming filesystem mark type (see my fanotify_sb tests [1]). Changes from v1: - Use test index to iterate test cases [1] https://github.com/amir73il/ltp/commits/fanotify_sb runtest/syscalls | 1 + testcases/kernel/syscalls/fanotify/.gitignore | 1 + testcases/kernel/syscalls/fanotify/fanotify.h | 12 + .../kernel/syscalls/fanotify/fanotify10.c | 331 ++++++++++++++++++ 4 files changed, 345 insertions(+) create mode 100644 testcases/kernel/syscalls/fanotify/fanotify10.c diff --git a/runtest/syscalls b/runtest/syscalls index 0d0be7713..cd52561a5 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -497,6 +497,7 @@ fanotify06 fanotify06 fanotify07 fanotify07 fanotify08 fanotify08 fanotify09 fanotify09 +fanotify10 fanotify10 ioperm01 ioperm01 ioperm02 ioperm02 diff --git a/testcases/kernel/syscalls/fanotify/.gitignore b/testcases/kernel/syscalls/fanotify/.gitignore index ec7553995..c26f2bd27 100644 --- a/testcases/kernel/syscalls/fanotify/.gitignore +++ b/testcases/kernel/syscalls/fanotify/.gitignore @@ -7,3 +7,4 @@ /fanotify07 /fanotify08 /fanotify09 +/fanotify10 diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h index f5f7df25e..5adef54d7 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify.h +++ b/testcases/kernel/syscalls/fanotify/fanotify.h @@ -54,4 +54,16 @@ static long fanotify_mark(int fd, unsigned int flags, uint64_t mask, #endif /* HAVE_SYS_FANOTIFY_H */ +#ifndef FAN_MARK_INODE +#define FAN_MARK_INODE 0 +#endif + +struct fanotify_mark_type { + unsigned int flag; + const char * name; +}; + +#define INIT_FANOTIFY_MARK_TYPE(t) \ + { FAN_MARK_ ## t, "FAN_MARK_" #t } + #endif /* __FANOTIFY_H__ */ diff --git a/testcases/kernel/syscalls/fanotify/fanotify10.c b/testcases/kernel/syscalls/fanotify/fanotify10.c new file mode 100644 index 000000000..75e747c29 --- /dev/null +++ b/testcases/kernel/syscalls/fanotify/fanotify10.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2014 SUSE. All Rights Reserved. + * Copyright (c) 2018 CTERA Networks. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Started by Jan Kara + * Forked from fanotify06.c by Amir Goldstein + * + * DESCRIPTION + * Check that fanotify properly merges ignore mask of a mount mark + * with a mask of an inode mark on the same group. Unlike the + * prototype test fanotify06, do not use FAN_MODIFY event for the + * test mask, because it hides the bug. + * + * This is a regression test for commit: + * + * 9bdda4e9cf2d fsnotify: fix ignore mask logic in fsnotify() + */ +#define _GNU_SOURCE +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "tst_test.h" +#include "fanotify.h" + +#if defined(HAVE_SYS_FANOTIFY_H) +#include + +#define EVENT_MAX 1024 +/* size of the event structure, not counting name */ +#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) +/* reasonable guess as to size of 1024 events */ +#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) + +static unsigned int fanotify_prio[] = { + FAN_CLASS_PRE_CONTENT, + FAN_CLASS_CONTENT, + FAN_CLASS_NOTIF +}; +#define FANOTIFY_PRIORITIES ARRAY_SIZE(fanotify_prio) + +#define GROUPS_PER_PRIO 3 + +static int fd_notify[FANOTIFY_PRIORITIES][GROUPS_PER_PRIO]; + +static char event_buf[EVENT_BUF_LEN]; + +#define MOUNT_PATH "fs_mnt" +#define MNT2_PATH "mntpoint" +#define FILE_NAME "testfile" +#define FILE2_NAME "testfile2" +#define FILE_PATH MOUNT_PATH"/"FILE_NAME +#define FILE2_PATH MOUNT_PATH"/"FILE2_NAME +#define FILE_MNT2 MNT2_PATH"/"FILE_NAME +#define FILE2_MNT2 MNT2_PATH"/"FILE2_NAME + +static int mount_created, bind_mount_created; + +enum { + FANOTIFY_INODE, + FANOTIFY_MOUNT, +}; + +static struct fanotify_mark_type fanotify_mark_types[] = { + INIT_FANOTIFY_MARK_TYPE(INODE), + INIT_FANOTIFY_MARK_TYPE(MOUNT), +}; + +static struct tcase { + const char *tname; + const char *mark_path; + int mark_type; + const char *ignore_path; + int ignore_mark_type; + const char *event_path; + int expect_event; +} tcases[] = { + { + "ignore mount events created on a specific file", + MOUNT_PATH, FANOTIFY_MOUNT, + FILE_MNT2, FANOTIFY_INODE, + FILE_PATH, 0 + }, + { + "don't ignore mount events created on another file", + MOUNT_PATH, FANOTIFY_MOUNT, + FILE_PATH, FANOTIFY_INODE, + FILE2_PATH, 1 + }, + { + "ignore inode events created on a specific mount point", + FILE_PATH, FANOTIFY_INODE, + MNT2_PATH, FANOTIFY_MOUNT, + FILE_MNT2, 0 + }, + { + "don't ignore inode events created on another mount point", + FILE_MNT2, FANOTIFY_INODE, + MNT2_PATH, FANOTIFY_MOUNT, + FILE_PATH, 1 + }, +}; + +static void create_fanotify_groups(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + struct fanotify_mark_type *mark, *ignore_mark; + unsigned int p, i; + int ret; + + mark = &fanotify_mark_types[tc->mark_type]; + ignore_mark = &fanotify_mark_types[tc->ignore_mark_type]; + + for (p = 0; p < FANOTIFY_PRIORITIES; p++) { + for (i = 0; i < GROUPS_PER_PRIO; i++) { + fd_notify[p][i] = SAFE_FANOTIFY_INIT(fanotify_prio[p] | + FAN_NONBLOCK, + O_RDONLY); + + /* Add mark for each group */ + ret = fanotify_mark(fd_notify[p][i], + FAN_MARK_ADD | mark->flag, + FAN_OPEN, AT_FDCWD, tc->mark_path); + if (ret < 0) { + tst_brk(TBROK | TERRNO, + "fanotify_mark(%d, FAN_MARK_ADD | %s," + "FAN_OPEN, AT_FDCWD, %s) failed", + fd_notify[p][i], mark->name, + tc->mark_path); + } + /* Add ignore mark for groups with higher priority */ + if (p == 0) + continue; + 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); + 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", + fd_notify[p][i], ignore_mark->name, + tc->ignore_path); + } + } + } +} + +static void cleanup_fanotify_groups(void) +{ + unsigned int i, p; + + for (p = 0; p < FANOTIFY_PRIORITIES; p++) { + for (i = 0; i < GROUPS_PER_PRIO; i++) { + if (fd_notify[p][i] > 0) + SAFE_CLOSE(fd_notify[p][i]); + } + } +} + +static void verify_event(int group, struct fanotify_event_metadata *event) +{ + if (event->mask != FAN_OPEN) { + tst_res(TFAIL, "group %d got event: mask %llx (expected %llx) " + "pid=%u fd=%u", group, (unsigned long long)event->mask, + (unsigned long long)FAN_OPEN, + (unsigned)event->pid, event->fd); + } else if (event->pid != getpid()) { + tst_res(TFAIL, "group %d got event: mask %llx pid=%u " + "(expected %u) fd=%u", group, + (unsigned long long)event->mask, (unsigned)event->pid, + (unsigned)getpid(), event->fd); + } else { + tst_res(TPASS, "group %d got event: mask %llx pid=%u fd=%u", + group, (unsigned long long)event->mask, + (unsigned)event->pid, event->fd); + } +} + +static void test_fanotify(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + struct fanotify_mark_type *mark, *ignore_mark; + int ret, fd; + unsigned int p, i; + struct fanotify_event_metadata *event; + + tst_res(TINFO, "Test #%d: %s", n, tc->tname); + + create_fanotify_groups(n); + + mark = &fanotify_mark_types[tc->mark_type]; + ignore_mark = &fanotify_mark_types[tc->ignore_mark_type]; + + /* + * generate sequence of events + */ + fd = SAFE_OPEN(tc->event_path, O_RDONLY); + SAFE_CLOSE(fd); + + /* First verify all groups without matching ignore mask got the event */ + for (p = 0; p < FANOTIFY_PRIORITIES; p++) { + if (p > 0 && !tc->expect_event) + break; + + for (i = 0; i < GROUPS_PER_PRIO; i++) { + ret = read(fd_notify[p][i], event_buf, EVENT_BUF_LEN); + if (ret < 0) { + if (errno == EAGAIN) { + tst_res(TFAIL, "group %d (prio %d) " + "with %s did not get event", + i, p, mark->name); + } + tst_brk(TBROK | TERRNO, + "reading fanotify events failed"); + } + if (ret < (int)FAN_EVENT_METADATA_LEN) { + tst_brk(TBROK, + "short read when reading fanotify " + "events (%d < %d)", ret, + (int)EVENT_BUF_LEN); + } + event = (struct fanotify_event_metadata *)event_buf; + if (ret > (int)event->event_len) { + tst_res(TFAIL, "group %d (prio %d) with %s " + "got more than one event (%d > %d)", + i, p, mark->name, ret, + event->event_len); + } else { + verify_event(i, event); + } + if (event->fd != FAN_NOFD) + SAFE_CLOSE(event->fd); + } + } + /* Then verify all groups with matching ignore mask did got the event */ + for (p = 1; p < FANOTIFY_PRIORITIES && !tc->expect_event; p++) { + for (i = 0; i < GROUPS_PER_PRIO; i++) { + ret = read(fd_notify[p][i], event_buf, EVENT_BUF_LEN); + if (ret == 0) { + tst_brk(TBROK, + "zero length read from fanotify fd"); + } + if (ret > 0) { + tst_res(TFAIL, "group %d (prio %d) with %s and " + "%s ignore mask got event", + i, p, mark->name, ignore_mark->name); + if (event->fd != FAN_NOFD) + SAFE_CLOSE(event->fd); + } else if (errno == EAGAIN) { + tst_res(TPASS, "group %d (prio %d) with %s and " + "%s ignore mask got no event", + i, p, mark->name, ignore_mark->name); + } else { + tst_brk(TBROK | TERRNO, + "reading fanotify events failed"); + } + } + } + cleanup_fanotify_groups(); +} + +static void setup(void) +{ + /* Mount the filesystem at one path for watching events */ + SAFE_MKDIR(MOUNT_PATH, 0755); + SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL); + mount_created = 1; + + /* Create another bind mount at another path for generating events */ + SAFE_MKDIR(MNT2_PATH, 0755); + SAFE_MOUNT(MOUNT_PATH, MNT2_PATH, "none", MS_BIND, NULL); + bind_mount_created = 1; + + SAFE_FILE_PRINTF(FILE_PATH, "1"); + SAFE_FILE_PRINTF(FILE2_PATH, "1"); +} + +static void cleanup(void) +{ + cleanup_fanotify_groups(); + + if (bind_mount_created && tst_umount(MNT2_PATH) < 0) + tst_brk(TBROK | TERRNO, "bind umount failed"); + + if (mount_created && tst_umount(MOUNT_PATH) < 0) + tst_brk(TBROK | TERRNO, "fs umount failed"); +} + +static struct tst_test test = { + .test = test_fanotify, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .format_device = 1, + .needs_tmpdir = 1, + .needs_root = 1 +}; + +#else + TST_TEST_TCONF("system doesn't have required fanotify support"); +#endif