From patchwork Fri Nov 15 15:30:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 13876440 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 91811D68BC8 for ; Fri, 15 Nov 2024 15:31:30 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id DA2156B0088; Fri, 15 Nov 2024 10:31:28 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id D52376B0089; Fri, 15 Nov 2024 10:31:28 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B0B396B008A; Fri, 15 Nov 2024 10:31:28 -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 93EB86B0088 for ; Fri, 15 Nov 2024 10:31:28 -0500 (EST) Received: from smtpin10.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 0EF251418D5 for ; Fri, 15 Nov 2024 15:31:28 +0000 (UTC) X-FDA: 82788717228.10.49F9D4F Received: from mail-yb1-f174.google.com (mail-yb1-f174.google.com [209.85.219.174]) by imf15.hostedemail.com (Postfix) with ESMTP id 9141DA003F for ; Fri, 15 Nov 2024 15:30:39 +0000 (UTC) Authentication-Results: imf15.hostedemail.com; dkim=pass header.d=toxicpanda-com.20230601.gappssmtp.com header.s=20230601 header.b=rpCSgWcD; spf=none (imf15.hostedemail.com: domain of josef@toxicpanda.com has no SPF policy when checking 209.85.219.174) smtp.mailfrom=josef@toxicpanda.com; dmarc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1731684448; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=kj8DHbC84OPYXlyGqV3jogaZDMjK7DzZOpBQs/P23MY=; b=zSAT+SYFhnGM6Qr8wuV2+j5hBvnJD9HErh4zCkuU2GZxT37Cd9lpXdgxztuS27MdUfmtDq NfaIeMo9KUj3B2kq1O5rivCsLwxihYg3YHy+8Gn6gURRukIZBW/iAad50khkFx9otdSz+1 2jkpowIUv5ulfb08TRNgbd/uaLIzTMI= ARC-Authentication-Results: i=1; imf15.hostedemail.com; dkim=pass header.d=toxicpanda-com.20230601.gappssmtp.com header.s=20230601 header.b=rpCSgWcD; spf=none (imf15.hostedemail.com: domain of josef@toxicpanda.com has no SPF policy when checking 209.85.219.174) smtp.mailfrom=josef@toxicpanda.com; dmarc=none ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1731684448; a=rsa-sha256; cv=none; b=mzD2ytQ/hPeAdrDoEtRj2yDACSNFmByoRIp2d5xpnMM4Be1+QTJJXM9pAFM/BYdamqF+eR blghcnSxn1B28DA3uBnGy2tEGW2wZ7r4W350G/DPfE+JieObvbkY2l6aQT4pWJxirc8pS5 HF3x1iZBVVfil/jTWvHfBgnJsjitRsM= Received: by mail-yb1-f174.google.com with SMTP id 3f1490d57ef6-e381cbdd03cso1493131276.1 for ; Fri, 15 Nov 2024 07:31:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20230601.gappssmtp.com; s=20230601; t=1731684685; x=1732289485; darn=kvack.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=kj8DHbC84OPYXlyGqV3jogaZDMjK7DzZOpBQs/P23MY=; b=rpCSgWcDZ7XME+Wb0IE6i27max7Kc2NQxCIe7f5MFJh3J5vHOfL+HMN9GRJ0FugSka Q+FPsUP/1jSaM2KRYbR+f9rJAcJnpdHoVMnTqd0MzKna6xE2JW5JgliCbjHcB2kC1f9o jONru9okm37a2DYTXwCphab5PB0NjfY4OK5Eb/wT5MzqUhkojviiwln81O4y9zbCYZbq UKfEtJJfCcE/ForFOY1vf0XxRr40sbaaEkY62xKa7eLbR02Oow4qvl11i4GHEyn+zJYD gQRux+BVO1AQdrHk+g5f7+iDX/k4QT2u8XSr3XQ7DasK6e8VV/PhI3qm2NBD//2JkJrU u1gA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1731684685; x=1732289485; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=kj8DHbC84OPYXlyGqV3jogaZDMjK7DzZOpBQs/P23MY=; b=q6QUYhv/Htnxx6YW8JQlsX+Qa0ydjV9HQydm+Xo5o9R6GAO6g+3wsJJOtY3aqdSzbj 4xMH1EfOUZuA5c8BT+z9jkOJEplLw+bYzpq9hSG8AGue35ccSFxxs9QKG5Snsxukl1yx gJCaA0uaCzkEhGgAQT24A/Mj3HQZq3Fd0LZisClD/qTTY/HQmbyMDKQDuV6ZNpodX9b9 r+9zR7lQkToKFODI3ScrHIPqUf7SG9k+L0izTT/s3N1/4ELH1T4AjtoZpnptMdauFLkx 31t4Ru9sQe7rhFJZvCjjPmm8tGE3RljmRovoI3/RBvqJbPFtgSBpUyGHerF18HWMLILp bibQ== X-Forwarded-Encrypted: i=1; AJvYcCUt37zbmqAAlsty+RG0jOnXf3h39/dLjItnfSOM/ZrkL3JM2uIhwMUgEbPn4fk2dLBjIBBOGnNIRQ==@kvack.org X-Gm-Message-State: AOJu0YzVZlpw0zxb8Oo3kI68soxIZQeMpRQH4s+cqfvc9MOosH+xQ5IC m3biPgAgeg++BxjjsOPEau3NzDQQIcYafq6Ve60qi2ZiJtIuT8dr/cxaJWaYVxE= X-Google-Smtp-Source: AGHT+IH8WmaESCVDYemYdBxVVvrkUDwhBuFm4p8CVuem1Xk6vUMMQWpt5yAHUnnmjhKyVYoAl9xVug== X-Received: by 2002:a05:690c:46c4:b0:6ea:ebba:3059 with SMTP id 00721157ae682-6ee558d9384mr37985407b3.0.1731684684910; Fri, 15 Nov 2024 07:31:24 -0800 (PST) Received: from localhost (syn-076-182-020-124.res.spectrum.com. [76.182.20.124]) by smtp.gmail.com with ESMTPSA id 00721157ae682-6ee44413490sm7666367b3.95.2024.11.15.07.31.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Nov 2024 07:31:24 -0800 (PST) From: Josef Bacik To: kernel-team@fb.com, linux-fsdevel@vger.kernel.org, jack@suse.cz, amir73il@gmail.com, brauner@kernel.org, torvalds@linux-foundation.org, viro@zeniv.linux.org.uk, linux-xfs@vger.kernel.org, linux-btrfs@vger.kernel.org, linux-mm@kvack.org, linux-ext4@vger.kernel.org Subject: [PATCH v8 02/19] fsnotify: opt-in for permission events at file open time Date: Fri, 15 Nov 2024 10:30:15 -0500 Message-ID: <5ea5f8e283d1edb55aa79c35187bfe344056af14.1731684329.git.josef@toxicpanda.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Server: rspam06 X-Rspamd-Queue-Id: 9141DA003F X-Stat-Signature: kr81m48mcaqjgc8rhpi3b1yg4thr9gpf X-Rspam-User: X-HE-Tag: 1731684639-826337 X-HE-Meta: U2FsdGVkX18Dpq5eDNaCaFm1WP7BEomeWZv7HGU1d23txdjckp7vzi6C9o/jIyS1dXDTk6epNlMBBQNzzXeNVmK8l9kym4zaBmAZeVgNlV/x9CP0AJddt3PqE7iIEccef5yGO9Z4qJgOuJjk/PZkPmP9aM8289jnUwe4Bs2VIHG3Lk4a8EYZq+/I/rGZWVDFndueRFfSAo1iYDhlFi6Nm/h+laWSf0oG1wQQiH0JUNIsanTr/GYFUTsAPwYkOVykON/Q4zyI2BCXHg6CKY8VZyfhWsC4/2cMSIwleaqjLRlvAKMJohlj4ZvfyV4mlHLpQxitGVRlRMvw4Q8JjIwA957JqChDdllZhh3WYvwhB6OtpXE62CFnr+TLDfDO9eedMrT8EmHTjmpkgOr94tl8pUQhteNGBi10HVvYaxxDuRderqsGPX/lnD+dts1B+puDXYo329xYzDryjqIG14wJRRi1eR7ZxXAR7BlTXNcQ6xOXwUn6wsXhAl5ULnxjKdB81S29DSerwoWIbLpdudf40TUoiL28tiWDZhuyDTDHTP9fYShMawqvXBbFE6Td9aIUa3GxwwYOG5bBoCZuzVxJty9HRwWyHVAVcMegXopyLFMFtwaIJvnL60e6//d4nLsq+QO8DiDU0CpEw0ZFO67vt+FKRybyEDG6xiMJRUoHCgDtBnM1N9VjitgG72O82cbo9MEk+QoR1c01Ij98XdkS8alK1NdSvtCm5UznKo8/ZeLc7wRv6XJLcQ9re1nLyNj3Y5uU7On6FSYLVIMFmXOS67QYCeLBFsemqAB262QDyahUIA3lzZzlMj8t9eHn5MD6tMMxyFSFNW7heIafu7GYA6D0NuAj7k89Uti1YylXCfoWoYwXFjkuGdPsYY/HrZdFvjcyzwb/QduD7VCStllwrqXXgzs58JO22taijOyqW7CtGf3i9PY5fSd+T9Q4E+yClLqy2UGlLzvDTRgU0Ze UuDTH1JJ i+bqk2rq+AEkVWT/DedZQS02OQe3FlrezzY4abOhl7MB258N43LTAqiQD2FzhtTbU8g3rBfCB3JN8bswMzAjMKJI4zLBFZRnC2PH7sJbLXHd9FCL/uEghcaykZiWFlP339UlkBp+USDlvmP3vKLRdzvHy9iBXz2aye/Pzeh61j1i7iteCQMkExlFYHMmlMnVe/bfs7a56B5EpKym2MaH/fju2TuYgEOH2+hHJme2F9MDbPOYRxalV/ZnO+1/6hxlHhYght1/rY0Uen3dVmeZaemCNflK4PtT/YaUnCxSVAA0lvGGbpxikmptCYas5k5lO5DOQr/AEdRH1Grb2rAgb554PvOweaMqcjUJGXWccKJAqWpmxy61A+bmKnSXs7PXnked4LiV1T8PcdSRK/uHGpH92HMZt9/+Qoi38 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 --- fs/open.c | 8 ++++- include/linux/fs.h | 35 ++++++++++++++++--- include/linux/fsnotify.h | 72 +++++++++++++++++++++++++++++++--------- 3 files changed, 93 insertions(+), 22 deletions(-) diff --git a/fs/open.c b/fs/open.c index c3490286092e..1a9483872e1f 100644 --- a/fs/open.c +++ b/fs/open.c @@ -901,7 +901,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; } @@ -929,6 +929,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 23bd058576b1..8e5c783013d2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -173,13 +173,14 @@ 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)) -/* File was opened by fanotify and shouldn't generate fanotify events */ -#define FMODE_NONOTIFY ((__force fmode_t)(1 << 26)) +/* File shouldn't generate fanotify pre-content events */ +#define FMODE_NONOTIFY_HSM ((__force fmode_t)(1 << 25)) + +/* File shouldn't generate fanotify permission events */ +#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)) @@ -190,6 +191,30 @@ 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_ bits used together have a special meaning of + * not reporting any events at all including non-permission events. + * These are the possible values of FMODE_FSNOTIFY(f->f_mode) and their meaning: + * + * FMODE_NONOTIFY_HSM - suppress only pre-content events. + * FMODE_NONOTIFY_PERM - suppress permission (incl. pre-content) events. + * FMODE_NONOTIFY - suppress all (incl. non-permission) events. + */ +#define FMODE_FSNOTIFY_MASK \ + (FMODE_NONOTIFY_HSM | FMODE_NONOTIFY_PERM) +#define FMODE_NONOTIFY FMODE_FSNOTIFY_MASK +#define FMODE_FSNOTIFY(mode) \ + ((mode) & FMODE_FSNOTIFY_MASK) + +#define FMODE_FSNOTIFY_NONE(mode) \ + (FMODE_FSNOTIFY(mode) == FMODE_NONOTIFY) +#define FMODE_FSNOTIFY_NORMAL(mode) \ + (FMODE_FSNOTIFY(mode) == FMODE_NONOTIFY_PERM) +#define FMODE_FSNOTIFY_PERM(mode) \ + (!((mode) & FMODE_NONOTIFY_PERM)) +#define FMODE_FSNOTIFY_HSM(mode) \ + (FMODE_FSNOTIFY(mode) == 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..54ec97366d7c 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -108,38 +108,68 @@ static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask) fsnotify_parent(dentry, mask, dentry, FSNOTIFY_EVENT_DENTRY); } +static inline int fsnotify_path(const struct path *path, __u32 mask) +{ + return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH); +} + static inline int fsnotify_file(struct file *file, __u32 mask) { - const struct path *path; - /* * 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 +/* + * 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. + */ +static 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; + } + + /* + * FMODE_NONOTIFY_HSM bit means there are permission event watchers, but + * no pre-content event watchers. + */ + if (likely(!fsnotify_sb_has_priority_watchers(sb, + FSNOTIFY_PRIO_PRE_CONTENT))) { + file->f_mode |= FMODE_NONOTIFY_HSM; + return; + } +} + /* * 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 +180,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(file->f_mode & FMODE_NONOTIFY_PERM)) + return 0; + + return fsnotify_path(&file->f_path, FS_ACCESS_PERM); } /* @@ -168,16 +201,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) {