linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Josef Bacik <josef@toxicpanda.com>
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 12/19] fanotify: allow to set errno in FAN_DENY permission response
Date: Fri, 15 Nov 2024 10:30:25 -0500	[thread overview]
Message-ID: <1e5fb6af84b69ca96b5c849fa5f10bdf4d1dc414.1731684329.git.josef@toxicpanda.com> (raw)
In-Reply-To: <cover.1731684329.git.josef@toxicpanda.com>

From: Amir Goldstein <amir73il@gmail.com>

With FAN_DENY response, user trying to perform the filesystem operation
gets an error with errno set to EPERM.

It is useful for hierarchical storage management (HSM) service to be able
to deny access for reasons more diverse than EPERM, for example EAGAIN,
if HSM could retry the operation later.

Allow fanotify groups with priority FAN_CLASSS_PRE_CONTENT to responsd
to permission events with the response value FAN_DENY_ERRNO(errno),
instead of FAN_DENY to return a custom error.

Limit custom error values to errors expected on read(2)/write(2) and
open(2) of regular files. This list could be extended in the future.
Userspace can test for legitimate values of FAN_DENY_ERRNO(errno) by
writing a response to an fanotify group fd with a value of FAN_NOFD in
the fd field of the response.

The change in fanotify_response is backward compatible, because errno is
written in the high 8 bits of the 32bit response field and old kernels
reject respose value with high bits set.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/notify/fanotify/fanotify.c      | 19 +++++++++++----
 fs/notify/fanotify/fanotify.h      |  5 ++++
 fs/notify/fanotify/fanotify_user.c | 37 ++++++++++++++++++++++++++----
 include/linux/fanotify.h           |  5 +++-
 include/uapi/linux/fanotify.h      |  7 ++++++
 5 files changed, 62 insertions(+), 11 deletions(-)

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index da6c3c1c7edf..e3d04d77caba 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -223,7 +223,8 @@ static int fanotify_get_response(struct fsnotify_group *group,
 				 struct fanotify_perm_event *event,
 				 struct fsnotify_iter_info *iter_info)
 {
-	int ret;
+	int ret, errno;
+	u32 decision;
 
 	pr_debug("%s: group=%p event=%p\n", __func__, group, event);
 
@@ -256,20 +257,28 @@ static int fanotify_get_response(struct fsnotify_group *group,
 		goto out;
 	}
 
+	decision = event->response &
+		(FANOTIFY_RESPONSE_ACCESS | FANOTIFY_RESPONSE_FLAGS);
 	/* userspace responded, convert to something usable */
-	switch (event->response & FANOTIFY_RESPONSE_ACCESS) {
+	switch (decision & FANOTIFY_RESPONSE_ACCESS) {
 	case FAN_ALLOW:
 		ret = 0;
 		break;
 	case FAN_DENY:
+		/* Check custom errno from pre-content events */
+		errno = fanotify_get_response_errno(event->response);
+		if (errno) {
+			ret = -errno;
+			break;
+		}
+		fallthrough;
 	default:
 		ret = -EPERM;
 	}
 
 	/* Check if the response should be audited */
-	if (event->response & FAN_AUDIT)
-		audit_fanotify(event->response & ~FAN_AUDIT,
-			       &event->audit_rule);
+	if (decision & FAN_AUDIT)
+		audit_fanotify(decision & ~FAN_AUDIT, &event->audit_rule);
 
 	pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
 		 group, event, ret);
diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h
index 7f06355afa1f..9e93aba210c9 100644
--- a/fs/notify/fanotify/fanotify.h
+++ b/fs/notify/fanotify/fanotify.h
@@ -528,3 +528,8 @@ static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark)
 
 	return mflags;
 }
+
+static inline u32 fanotify_get_response_errno(int res)
+{
+	return res >> FAN_ERRNO_SHIFT;
+}
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index c7938d9e8101..28aac467c7e2 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -327,11 +327,14 @@ static int process_access_response(struct fsnotify_group *group,
 	struct fanotify_perm_event *event;
 	int fd = response_struct->fd;
 	u32 response = response_struct->response;
+	u32 decision = response &
+		(FANOTIFY_RESPONSE_ACCESS | FANOTIFY_RESPONSE_FLAGS);
+	int errno = fanotify_get_response_errno(response);
 	int ret = info_len;
 	struct fanotify_response_info_audit_rule friar;
 
-	pr_debug("%s: group=%p fd=%d response=%u buf=%p size=%zu\n", __func__,
-		 group, fd, response, info, info_len);
+	pr_debug("%s: group=%p fd=%d response=%x errno=%d buf=%p size=%zu\n",
+		 __func__, group, fd, response, errno, info, info_len);
 	/*
 	 * make sure the response is valid, if invalid we do nothing and either
 	 * userspace can send a valid response or we will clean it up after the
@@ -340,18 +343,42 @@ static int process_access_response(struct fsnotify_group *group,
 	if (response & ~FANOTIFY_RESPONSE_VALID_MASK)
 		return -EINVAL;
 
-	switch (response & FANOTIFY_RESPONSE_ACCESS) {
+	switch (decision & FANOTIFY_RESPONSE_ACCESS) {
 	case FAN_ALLOW:
+		if (errno)
+			return -EINVAL;
+		break;
 	case FAN_DENY:
+		/* Custom errno is supported only for pre-content groups */
+		if (errno && group->priority != FSNOTIFY_PRIO_PRE_CONTENT)
+			return -EINVAL;
+
+		/*
+		 * Limit errno to values expected on open(2)/read(2)/write(2)
+		 * of regular files.
+		 */
+		switch (errno) {
+		case 0:
+		case EIO:
+		case EPERM:
+		case EBUSY:
+		case ETXTBSY:
+		case EAGAIN:
+		case ENOSPC:
+		case EDQUOT:
+			break;
+		default:
+			return -EINVAL;
+		}
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	if ((response & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT))
+	if ((decision & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT))
 		return -EINVAL;
 
-	if (response & FAN_INFO) {
+	if (decision & FAN_INFO) {
 		ret = process_access_response_info(info, info_len, &friar);
 		if (ret < 0)
 			return ret;
diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
index c747af064d2c..d9bb48976b53 100644
--- a/include/linux/fanotify.h
+++ b/include/linux/fanotify.h
@@ -132,7 +132,10 @@
 /* These masks check for invalid bits in permission responses. */
 #define FANOTIFY_RESPONSE_ACCESS (FAN_ALLOW | FAN_DENY)
 #define FANOTIFY_RESPONSE_FLAGS (FAN_AUDIT | FAN_INFO)
-#define FANOTIFY_RESPONSE_VALID_MASK (FANOTIFY_RESPONSE_ACCESS | FANOTIFY_RESPONSE_FLAGS)
+#define FANOTIFY_RESPONSE_ERRNO	(FAN_ERRNO_MASK << FAN_ERRNO_SHIFT)
+#define FANOTIFY_RESPONSE_VALID_MASK \
+	(FANOTIFY_RESPONSE_ACCESS | FANOTIFY_RESPONSE_FLAGS | \
+	 FANOTIFY_RESPONSE_ERRNO)
 
 /* Do not use these old uapi constants internally */
 #undef FAN_ALL_CLASS_BITS
diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h
index 0636a9c85dd0..bd8167979707 100644
--- a/include/uapi/linux/fanotify.h
+++ b/include/uapi/linux/fanotify.h
@@ -235,6 +235,13 @@ struct fanotify_response_info_audit_rule {
 /* Legit userspace responses to a _PERM event */
 #define FAN_ALLOW	0x01
 #define FAN_DENY	0x02
+/* errno other than EPERM can specified in upper byte of deny response */
+#define FAN_ERRNO_BITS	8
+#define FAN_ERRNO_SHIFT (32 - FAN_ERRNO_BITS)
+#define FAN_ERRNO_MASK	((1 << FAN_ERRNO_BITS) - 1)
+#define FAN_DENY_ERRNO(err) \
+	(FAN_DENY | ((((__u32)(err)) & FAN_ERRNO_MASK) << FAN_ERRNO_SHIFT))
+
 #define FAN_AUDIT	0x10	/* Bitmask to create audit record for result */
 #define FAN_INFO	0x20	/* Bitmask to indicate additional information */
 
-- 
2.43.0



  parent reply	other threads:[~2024-11-15 15:31 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-15 15:30 [PATCH v8 00/19] fanotify: add pre-content hooks Josef Bacik
2024-11-15 15:30 ` [PATCH v8 01/19] fs: get rid of __FMODE_NONOTIFY kludge Josef Bacik
2024-11-18 18:14   ` Jan Kara
2024-11-15 15:30 ` [PATCH v8 02/19] fsnotify: opt-in for permission events at file open time Josef Bacik
2024-11-20 15:53   ` Jan Kara
2024-11-20 16:12     ` Amir Goldstein
2024-11-21  9:39       ` Jan Kara
2024-11-21 10:09         ` Christian Brauner
2024-11-21 11:04           ` Amir Goldstein
2024-11-21 11:16             ` Jan Kara
2024-11-21 11:32               ` Amir Goldstein
2024-11-21  9:45     ` Christian Brauner
2024-11-21 11:39       ` Amir Goldstein
2024-11-15 15:30 ` [PATCH v8 03/19] fsnotify: add helper to check if file is actually being watched Josef Bacik
2024-11-20 16:02   ` Jan Kara
2024-11-20 16:42     ` Amir Goldstein
2024-11-21  8:54       ` Jan Kara
2024-11-15 15:30 ` [PATCH v8 04/19] fanotify: don't skip extra event info if no info_mode is set Josef Bacik
2024-11-15 15:30 ` [PATCH v8 05/19] fanotify: rename a misnamed constant Josef Bacik
2024-11-15 15:30 ` [PATCH v8 06/19] fanotify: reserve event bit of deprecated FAN_DIR_MODIFY Josef Bacik
2024-11-15 15:30 ` [PATCH v8 07/19] fsnotify: introduce pre-content permission events Josef Bacik
2024-11-15 15:30 ` [PATCH v8 08/19] fsnotify: pass optional file access range in pre-content event Josef Bacik
2024-11-15 15:30 ` [PATCH v8 09/19] fsnotify: generate pre-content permission event on truncate Josef Bacik
2024-11-20 15:23   ` Jan Kara
2024-11-20 15:57     ` Amir Goldstein
2024-11-20 16:16       ` Jan Kara
2024-11-15 15:30 ` [PATCH v8 10/19] fanotify: introduce FAN_PRE_ACCESS permission event Josef Bacik
2024-11-15 15:59   ` Amir Goldstein
2024-11-21 10:44   ` Jan Kara
2024-11-21 14:18     ` Amir Goldstein
2024-11-21 16:36       ` Jan Kara
2024-11-21 18:31         ` Amir Goldstein
2024-11-21 18:37           ` Amir Goldstein
2024-11-22 12:42             ` Jan Kara
2024-11-22 13:51               ` Amir Goldstein
2024-11-27 12:18                 ` Jan Kara
2024-11-27 12:20                   ` Amir Goldstein
2024-11-15 15:30 ` [PATCH v8 11/19] fanotify: report file range info with pre-content events Josef Bacik
2024-11-15 15:30 ` Josef Bacik [this message]
2024-11-15 15:30 ` [PATCH v8 13/19] fanotify: add a helper to check for pre content events Josef Bacik
2024-11-20 15:44   ` Jan Kara
2024-11-20 16:43     ` Amir Goldstein
2024-11-15 15:30 ` [PATCH v8 14/19] fanotify: disable readahead if we have pre-content watches Josef Bacik
2024-11-15 15:30 ` [PATCH v8 15/19] mm: don't allow huge faults for files with pre content watches Josef Bacik
2025-01-31 19:17   ` [REGRESSION] " Alex Williamson
2025-01-31 19:59     ` Linus Torvalds
2025-02-01  1:19       ` Peter Xu
2025-02-01 14:38         ` Christian Brauner
2025-02-02  0:58           ` Linus Torvalds
2025-02-02  7:46             ` Amir Goldstein
2025-02-02 10:04               ` Christian Brauner
2025-02-03 12:41                 ` Jan Kara
2025-02-03 20:39                   ` Amir Goldstein
2025-02-03 21:41                     ` Alex Williamson
2025-02-03 22:04                       ` Amir Goldstein
2024-11-15 15:30 ` [PATCH v8 16/19] fsnotify: generate pre-content permission event on page fault Josef Bacik
2024-12-08 16:58   ` Klara Modin
2024-12-09 10:45     ` Aithal, Srikanth
2024-12-09 12:34       ` Jan Kara
2024-12-09 12:31     ` Jan Kara
2024-12-09 12:56       ` Klara Modin
2024-12-09 14:16         ` Jan Kara
2024-12-10 21:12     ` Randy Dunlap
2024-12-11 16:30       ` Jan Kara
2024-11-15 15:30 ` [PATCH v8 17/19] xfs: add pre-content fsnotify hook for write faults Josef Bacik
2024-11-21 10:22   ` Jan Kara
2024-11-15 15:30 ` [PATCH v8 18/19] btrfs: disable defrag on pre-content watched files Josef Bacik
2024-11-15 15:30 ` [PATCH v8 19/19] fs: enable pre-content events on supported file systems Josef Bacik
2024-11-21 11:29 ` [PATCH v8 00/19] fanotify: add pre-content hooks Jan Kara

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1e5fb6af84b69ca96b5c849fa5f10bdf4d1dc414.1731684329.git.josef@toxicpanda.com \
    --to=josef@toxicpanda.com \
    --cc=amir73il@gmail.com \
    --cc=brauner@kernel.org \
    --cc=jack@suse.cz \
    --cc=kernel-team@fb.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-xfs@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox