From patchwork Thu Nov 21 11:22:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kara X-Patchwork-Id: 13881873 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6E51FD6ED0A for ; Thu, 21 Nov 2024 11:22:44 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 04E936B0095; Thu, 21 Nov 2024 06:22:30 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id CD5DC6B0099; Thu, 21 Nov 2024 06:22:29 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 905FC6B0093; Thu, 21 Nov 2024 06:22:29 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 905116B0088 for ; Thu, 21 Nov 2024 06:22:28 -0500 (EST) Received: from smtpin06.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 21772161283 for ; Thu, 21 Nov 2024 11:22:28 +0000 (UTC) X-FDA: 82809861918.06.029C11E Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.223.131]) by imf08.hostedemail.com (Postfix) with ESMTP id CFFA616000A for ; Thu, 21 Nov 2024 11:21:50 +0000 (UTC) Authentication-Results: imf08.hostedemail.com; dkim=pass header.d=suse.cz header.s=susede2_rsa header.b=VLTdH5Cj; dkim=pass header.d=suse.cz header.s=susede2_ed25519 header.b=BpL5f5Po; dkim=pass header.d=suse.cz header.s=susede2_rsa header.b=VLTdH5Cj; dkim=pass header.d=suse.cz header.s=susede2_ed25519 header.b=BpL5f5Po; spf=pass (imf08.hostedemail.com: domain of jack@suse.cz designates 195.135.223.131 as permitted sender) smtp.mailfrom=jack@suse.cz; dmarc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1732187942; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=sB07Yami3ajewB8RW829tURphzsxA2qRlxADt5yZDjY=; b=FizUcOYpX5+8tzITo1cRKI0FV1EbRChC+bY7cymmKFFDWQZ7Aa2sqVOiDUbQqeNBSCdKzf wQYt31oiPcN7oqXE/BBtzyYbDmwyVuI0yvabO7BIcqknaech+NKE0UvE+CYZKgk5qd7FrQ ZJSd7qHzQ9vL5mHa7EdFg8yhWd9bOwg= ARC-Authentication-Results: i=1; imf08.hostedemail.com; dkim=pass header.d=suse.cz header.s=susede2_rsa header.b=VLTdH5Cj; dkim=pass header.d=suse.cz header.s=susede2_ed25519 header.b=BpL5f5Po; dkim=pass header.d=suse.cz header.s=susede2_rsa header.b=VLTdH5Cj; dkim=pass header.d=suse.cz header.s=susede2_ed25519 header.b=BpL5f5Po; spf=pass (imf08.hostedemail.com: domain of jack@suse.cz designates 195.135.223.131 as permitted sender) smtp.mailfrom=jack@suse.cz; dmarc=none ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1732187942; a=rsa-sha256; cv=none; b=ZmTU0q1SaMVjWPjHKpQrYt5mIz2So4HeVNb/7zaRomlCej1u1NrVBi44ihpUcNJV6ur0kf ehKG0XD0Vr1BgvUnmR457sCl7xDZhJKJBmmKQeb0OfOVLU8d8d/C+KPU2pA2Y07SYi5pTB /2/Xc5zZszM7RLwW9TTzymbQxpZwwwY= Received: from imap1.dmz-prg2.suse.org (unknown [10.150.64.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 361DB1F7F9; Thu, 21 Nov 2024 11:22:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_rsa; t=1732188144; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sB07Yami3ajewB8RW829tURphzsxA2qRlxADt5yZDjY=; b=VLTdH5CjpOfXOlzEqnLNGCjMZFFeKhFVeYrIGWFT6aS5brey5ZxJzhCRMFhjjHc3JcKgK4 h6w5vr30yrdEZ92bx6El7rh5HxG/a7vyjGc/RHqA8w+PHaF+JKvqlVlIvf8yA5DSZz1Xpf LU0coKeEsE2+vXo89yuwnNwEjSaZaok= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_ed25519; t=1732188144; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sB07Yami3ajewB8RW829tURphzsxA2qRlxADt5yZDjY=; b=BpL5f5Pood9Vc4H7sEKXMbbJoBglmI9S7N7aFfAN/tNLn7Fq/3lZfJsmx1a0T784A9sBQE 0hZwrU+Iz+ZO+XAQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_rsa; t=1732188144; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sB07Yami3ajewB8RW829tURphzsxA2qRlxADt5yZDjY=; b=VLTdH5CjpOfXOlzEqnLNGCjMZFFeKhFVeYrIGWFT6aS5brey5ZxJzhCRMFhjjHc3JcKgK4 h6w5vr30yrdEZ92bx6El7rh5HxG/a7vyjGc/RHqA8w+PHaF+JKvqlVlIvf8yA5DSZz1Xpf LU0coKeEsE2+vXo89yuwnNwEjSaZaok= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_ed25519; t=1732188144; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sB07Yami3ajewB8RW829tURphzsxA2qRlxADt5yZDjY=; b=BpL5f5Pood9Vc4H7sEKXMbbJoBglmI9S7N7aFfAN/tNLn7Fq/3lZfJsmx1a0T784A9sBQE 0hZwrU+Iz+ZO+XAQ== Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 2199813A23; Thu, 21 Nov 2024 11:22:24 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id F0nXB/AXP2cUfwAAD6G6ig (envelope-from ); Thu, 21 Nov 2024 11:22:24 +0000 Received: by quack3.suse.cz (Postfix, from userid 1000) id CC6CEA08E0; Thu, 21 Nov 2024 12:22:23 +0100 (CET) From: Jan Kara To: Cc: Amir Goldstein , Josef Bacik , brauner@kernel.org, Linus Torvalds , Al Viro , linux-xfs@vger.kernel.org, linux-btrfs@vger.kernel.org, linux-ext4@vger.kernel.org, linux-mm@kvack.org, Jan Kara Subject: [PATCH 02/19] fsnotify: opt-in for permission events at file open time Date: Thu, 21 Nov 2024 12:22:01 +0100 Message-Id: <20241121112218.8249-3-jack@suse.cz> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20241121112218.8249-1-jack@suse.cz> References: <20241121112218.8249-1-jack@suse.cz> MIME-Version: 1.0 X-Rspamd-Server: rspam07 X-Rspamd-Queue-Id: CFFA616000A X-Stat-Signature: owe5afefjsjn7y1i3n1heoodawnhrbxc X-Rspam-User: X-HE-Tag: 1732188110-222901 X-HE-Meta: U2FsdGVkX1/9ZkshLXTZ4gEfjmxKlQI/0tI9AwqduKF3za81n7DQKlFJia1O0jWGNvynyJX/YcMtZzeMkjOJd7bD/rOKfmB/M/i/fXgOqhbWI3DS5jkvk4b1UTp38NLAEoVPelTVw5/fDNTUwrAh/yg9g6HORcHXOnJLCTGklcYLDr7S0tEJ3tw7qhbMpYkJ/O0WzIRVoCvtEQB8ai0hul+RJSSKpjfqRTfyymiVL5NQxYA5MjN34cZXjkqcDf+Mu8LGrIOTkmvBJwuKlpUFJdrdvcqASidYOxTvPfpAPKmoF3XCVWrB8vh0UjTZCzXDKrWtp6li2jLlUzOYCeyS4ZAJW8bZ3OA8zDd1kD6bqGS/fs+F2SSSgTswCLQ58JMWyhiSwt0wuj5dkILWQpJfc2e2jRHmEQqiiBvoYWUddruzWLGzW6t6MV/eH04chkaPFzQ6pOQU8NFoFfinKIPoEOIS6m8n5N8l1qLPcok79+WlrnzeWDjA9uVF4AIe3uWdEJ7ZurZ6Y2U7metunMhtUOZqmI2ZYqVWWV8JaNtN6EKOuTGELZOTskG6UiP3oWCeYp0J1ri5sNjBnY4UhPUg8iRSpEoheGsOaHJ7Sg2qWC+bC+LiXy0zzyoVpf+3UZpWStvx+KY70oEYoK3TJtL03RZ7B9OLdUAdgqV5MMNIGnB+iEjZm336P8XME27PKi6odEhNB7uUMqIZyNurlwrmIWzhqzWQcDvIPDul+gX+//gg09xYYXXCVJx9tHsAL2+CwGI2QbC5mvYvP+PIhf/gr7BA1LqpEa+d4Qx+PaZ/iKOhn356B6+my/ofN5ZzX5MQbQ2ZeMhv1ynpEc1ElAwSI64JRKBqpkKxoEWXWtVvteAm/VueYrCEOes5jbINx6TG1msrsP6JiknLsHKxSusoU1x0jOEHllRUiGjDpuvZklpdsykN5O/g4fPfPqNLHjm96fmH1QuGZ+jy0veEJeR lb4BAKZ0 y6AGH4WgUEp8pEhHO0QlCvCblBPjwiceWNoxjr+Vy0yhd4uqwIa9cWvpBVdy9TBuhyQtzB40bqtbA6GmjvpcnMQKhTDlsKmqCtFrOXp9BUyf9sARNjk77PgNfnFeKhE9HF8WL1CSk88LVFx467e15beQCMWuM6mMOQ0ov06DMcoAZhcehw4oBIW0bT5DAlTlQz8nTyhEp/RmlLU5bqGoctJGXxEVVLI+pc1JYpUXDOYpNIcU7lWqHlFxXkkAEYCCd8wuaRyzUbVDLraLyr+8jWrQStLcUqk8307NkFtg266FBEbvBBAnO5YKLP7bYST72Dau9Kr1VSkiZ0k9F+LrBfbple2anUvHHN/xOGzDnj9EbbQw/WhAvC0GbIrwlPcyKYnXHJ1qorVgz1YVJdiRhMmfzPlJro+KLxv71iadVyizOFDxPJz2ZQNT7zHE/UQE/Ds9T62vJz2hxh8kqdlAGWz/95UXZB7uajP3kjALAF5Ha6mU= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Amir Goldstein Legacy inotify/fanotify listeners can add watches for events on inode, parent or mount and expect to get events (e.g. FS_MODIFY) on files that were already open at the time of setting up the watches. fanotify permission events are typically used by Anti-malware sofware, that is watching the entire mount and it is not common to have more that one Anti-malware engine installed on a system. To reduce the overhead of the fsnotify_file_perm() hooks on every file access, relax the semantics of the legacy FAN_ACCESS_PERM event to generate events only if there were *any* permission event listeners on the filesystem at the time that the file was opened. The new semantic is implemented by extending the FMODE_NONOTIFY bit into two FMODE_NONOTIFY_* bits, that are used to store a mode for which of the events types to report. This is going to apply to the new fanotify pre-content events in order to reduce the cost of the new pre-content event vfs hooks. Suggested-by: Linus Torvalds Link: https://lore.kernel.org/linux-fsdevel/CAHk-=wj8L=mtcRTi=NECHMGfZQgXOp_uix1YVh04fEmrKaMnXA@mail.gmail.com/ Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara Link: https://patch.msgid.link/5ea5f8e283d1edb55aa79c35187bfe344056af14.1731684329.git.josef@toxicpanda.com --- fs/notify/fsnotify.c | 38 ++++++++++++++++++++++++++++++++++++++ fs/open.c | 8 +++++++- include/linux/fs.h | 37 ++++++++++++++++++++++++++++++++----- include/linux/fsnotify.h | 39 +++++++++++++++++++++++---------------- 4 files changed, 100 insertions(+), 22 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index f976949d2634..569ec356e4ce 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -623,6 +623,44 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, } EXPORT_SYMBOL_GPL(fsnotify); +#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS +/* + * At open time we check fsnotify_sb_has_priority_watchers() and set the + * FMODE_NONOTIFY_ mode bits accordignly. + * Later, fsnotify permission hooks do not check if there are permission event + * watches, but that there were permission event watches at open time. + */ +void file_set_fsnotify_mode(struct file *file) +{ + struct super_block *sb = file->f_path.dentry->d_sb; + + /* Is it a file opened by fanotify? */ + if (FMODE_FSNOTIFY_NONE(file->f_mode)) + return; + + /* + * Permission events is a super set of pre-content events, so if there + * are no permission event watchers, there are also no pre-content event + * watchers and this is implied from the single FMODE_NONOTIFY_PERM bit. + */ + if (likely(!fsnotify_sb_has_priority_watchers(sb, + FSNOTIFY_PRIO_CONTENT))) { + file->f_mode |= FMODE_NONOTIFY_PERM; + return; + } + + /* + * If there are permission event watchers but no pre-content event + * watchers, set FMODE_NONOTIFY | FMODE_NONOTIFY_PERM to indicate that. + */ + if (likely(!fsnotify_sb_has_priority_watchers(sb, + FSNOTIFY_PRIO_PRE_CONTENT))) { + file->f_mode |= FMODE_NONOTIFY | FMODE_NONOTIFY_PERM; + return; + } +} +#endif + static __init int fsnotify_init(void) { int ret; diff --git a/fs/open.c b/fs/open.c index 480c3798da2a..9b1fa59d52bf 100644 --- a/fs/open.c +++ b/fs/open.c @@ -918,7 +918,7 @@ static int do_dentry_open(struct file *f, f->f_sb_err = file_sample_sb_err(f); if (unlikely(f->f_flags & O_PATH)) { - f->f_mode = FMODE_PATH | FMODE_OPENED; + f->f_mode = FMODE_PATH | FMODE_OPENED | FMODE_NONOTIFY; f->f_op = &empty_fops; return 0; } @@ -946,6 +946,12 @@ static int do_dentry_open(struct file *f, if (error) goto cleanup_all; + /* + * Set FMODE_NONOTIFY_* bits according to existing permission watches. + * If FMODE_NONOTIFY was already set for an fanotify fd, this doesn't + * change anything. + */ + file_set_fsnotify_mode(f); error = fsnotify_open_perm(f); if (error) goto cleanup_all; diff --git a/include/linux/fs.h b/include/linux/fs.h index 24598d707578..6a170c2c5326 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -171,13 +171,20 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define FMODE_NOREUSE ((__force fmode_t)(1 << 23)) -/* FMODE_* bit 24 */ - /* File is embedded in backing_file object */ -#define FMODE_BACKING ((__force fmode_t)(1 << 25)) +#define FMODE_BACKING ((__force fmode_t)(1 << 24)) + +/* + * Together with FMODE_NONOTIFY_PERM defines which fsnotify events shouldn't be + * generated (see below) + */ +#define FMODE_NONOTIFY ((__force fmode_t)(1 << 25)) -/* File was opened by fanotify and shouldn't generate fanotify events */ -#define FMODE_NONOTIFY ((__force fmode_t)(1 << 26)) +/* + * Together with FMODE_NONOTIFY defines which fsnotify events shouldn't be + * generated (see below) + */ +#define FMODE_NONOTIFY_PERM ((__force fmode_t)(1 << 26)) /* File is capable of returning -EAGAIN if I/O will block */ #define FMODE_NOWAIT ((__force fmode_t)(1 << 27)) @@ -188,6 +195,26 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, /* File does not contribute to nr_files count */ #define FMODE_NOACCOUNT ((__force fmode_t)(1 << 29)) +/* + * The two FMODE_NONOTIFY* define which fsnotify events should not be generated + * for a file. These are the possible values of (f->f_mode & + * FMODE_FSNOTIFY_MASK) and their meaning: + * + * FMODE_NONOTIFY - suppress all (incl. non-permission) events. + * FMODE_NONOTIFY_PERM - suppress permission (incl. pre-content) events. + * FMODE_NONOTIFY | FMODE_NONOTIFY_PERM - suppress only pre-content events. + */ +#define FMODE_FSNOTIFY_MASK \ + (FMODE_NONOTIFY | FMODE_NONOTIFY_PERM) + +#define FMODE_FSNOTIFY_NONE(mode) \ + ((mode & FMODE_FSNOTIFY_MASK) == FMODE_NONOTIFY) +#define FMODE_FSNOTIFY_PERM(mode) \ + ((mode & FMODE_FSNOTIFY_MASK) == 0 || \ + (mode & FMODE_FSNOTIFY_MASK) == (FMODE_NONOTIFY | FMODE_NONOTIFY_PERM)) +#define FMODE_FSNOTIFY_HSM(mode) \ + ((mode & FMODE_FSNOTIFY_MASK) == 0) + /* * Attribute flags. These should be or-ed together to figure out what * has been changed! diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 278620e063ab..8d1849137a96 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -108,38 +108,35 @@ static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask) fsnotify_parent(dentry, mask, dentry, FSNOTIFY_EVENT_DENTRY); } -static inline int fsnotify_file(struct file *file, __u32 mask) +static inline int fsnotify_path(const struct path *path, __u32 mask) { - const struct path *path; + return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH); +} +static inline int fsnotify_file(struct file *file, __u32 mask) +{ /* * FMODE_NONOTIFY are fds generated by fanotify itself which should not * generate new events. We also don't want to generate events for * FMODE_PATH fds (involves open & close events) as they are just * handle creation / destruction events and not "real" file events. */ - if (file->f_mode & (FMODE_NONOTIFY | FMODE_PATH)) + if (FMODE_FSNOTIFY_NONE(file->f_mode)) return 0; - path = &file->f_path; - /* Permission events require group prio >= FSNOTIFY_PRIO_CONTENT */ - if (mask & ALL_FSNOTIFY_PERM_EVENTS && - !fsnotify_sb_has_priority_watchers(path->dentry->d_sb, - FSNOTIFY_PRIO_CONTENT)) - return 0; - - return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH); + return fsnotify_path(&file->f_path, mask); } #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS + +void file_set_fsnotify_mode(struct file *file); + /* * fsnotify_file_area_perm - permission hook before access to file range */ static inline int fsnotify_file_area_perm(struct file *file, int perm_mask, const loff_t *ppos, size_t count) { - __u32 fsnotify_mask = FS_ACCESS_PERM; - /* * filesystem may be modified in the context of permission events * (e.g. by HSM filling a file on access), so sb freeze protection @@ -150,7 +147,10 @@ static inline int fsnotify_file_area_perm(struct file *file, int perm_mask, if (!(perm_mask & MAY_READ)) return 0; - return fsnotify_file(file, fsnotify_mask); + if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode))) + return 0; + + return fsnotify_path(&file->f_path, FS_ACCESS_PERM); } /* @@ -168,16 +168,23 @@ static inline int fsnotify_open_perm(struct file *file) { int ret; + if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode))) + return 0; + if (file->f_flags & __FMODE_EXEC) { - ret = fsnotify_file(file, FS_OPEN_EXEC_PERM); + ret = fsnotify_path(&file->f_path, FS_OPEN_EXEC_PERM); if (ret) return ret; } - return fsnotify_file(file, FS_OPEN_PERM); + return fsnotify_path(&file->f_path, FS_OPEN_PERM); } #else +static inline void file_set_fsnotify_mode(struct file *file) +{ +} + static inline int fsnotify_file_area_perm(struct file *file, int perm_mask, const loff_t *ppos, size_t count) {