diff mbox series

[v2,2/9] fanotify: define the structures to report a unique file identifier

Message ID 20181115184544.30681-3-amir73il@gmail.com (mailing list archive)
State New, archived
Headers show
Series fanotify: add support for more event types | expand

Commit Message

Amir Goldstein Nov. 15, 2018, 6:45 p.m. UTC
When user requests the flag FAN_REPORT_FID in fanotify_init(),
a unique file indetifier of the event target object will be reported
with the event.

This commit only defines the internal and user visible structures used
to store and report the unique file identifier.

The file identifier includes the filesystem's fsid (i.e. from statfs(2))
and an NFS file handle of the file (i.e. from name_to_handle_at(2)).

The file identifier makes holding the path reference and passing a file
descriptor to user redundant, so those are disabled in a group with
FAN_REPORT_FID.

Cc: <linux-api@vger.kernel.org>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/notify/fanotify/fanotify.c      |  2 +-
 fs/notify/fanotify/fanotify.h      | 26 ++++++++++++++++----
 fs/notify/fanotify/fanotify_user.c |  5 ++--
 include/uapi/linux/fanotify.h      | 38 +++++++++++++++++++++++++-----
 4 files changed, 57 insertions(+), 14 deletions(-)
diff mbox series

Patch

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index ecd5f4aec624..59d093923c97 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -178,7 +178,7 @@  init: __maybe_unused
 		event->pid = get_pid(task_pid(current));
 	else
 		event->pid = get_pid(task_tgid(current));
-	if (path) {
+	if (path && !FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
 		event->path = *path;
 		path_get(&event->path);
 	} else {
diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h
index fb84dd3289f8..2e4fca30afda 100644
--- a/fs/notify/fanotify/fanotify.h
+++ b/fs/notify/fanotify/fanotify.h
@@ -7,6 +7,14 @@  extern struct kmem_cache *fanotify_mark_cache;
 extern struct kmem_cache *fanotify_event_cachep;
 extern struct kmem_cache *fanotify_perm_event_cachep;
 
+/* The size of the variable length buffer storing fsid and file handle */
+#define FANOTIFY_FID_LEN(handle_bytes)	\
+	(sizeof(struct fanotify_event_fid) + (handle_bytes))
+
+struct fanotify_info {
+	struct fanotify_event_fid *fid;
+};
+
 /*
  * Structure for normal fanotify events. It gets allocated in
  * fanotify_handle_event() and freed when the information is retrieved by
@@ -14,11 +22,19 @@  extern struct kmem_cache *fanotify_perm_event_cachep;
  */
 struct fanotify_event {
 	struct fsnotify_event fse;
-	/*
-	 * We hold ref to this path so it may be dereferenced at any point
-	 * during this object's lifetime
-	 */
-	struct path path;
+	union {
+		/*
+		 * We hold ref to this path so it may be dereferenced at any
+		 * point during this object's lifetime
+		 */
+		struct path path;
+		/*
+		 * With FAN_REPORT_FID, we do not hold any reference on the
+		 * victim object. Instead we store its NFS file handle and its
+		 * filesystem's fsid as a unique identifier.
+		 */
+		struct fanotify_info info;
+	};
 	struct pid *pid;
 };
 
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 2dbb2662a92f..93e1aa2a389f 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -133,9 +133,10 @@  static int fill_event_metadata(struct fsnotify_group *group,
 	metadata->reserved = 0;
 	metadata->mask = fsn_event->mask & FANOTIFY_OUTGOING_EVENTS;
 	metadata->pid = pid_vnr(event->pid);
-	if (unlikely(fsn_event->mask & FAN_Q_OVERFLOW))
+	if (FAN_GROUP_FLAG(group, FAN_REPORT_FID) ||
+	    unlikely(fsn_event->mask & FAN_Q_OVERFLOW)) {
 		metadata->fd = FAN_NOFD;
-	else {
+	} else {
 		metadata->fd = create_fd(group, event, file);
 		if (metadata->fd < 0)
 			ret = metadata->fd;
diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h
index 909c98fcace2..aa510aec7968 100644
--- a/include/uapi/linux/fanotify.h
+++ b/include/uapi/linux/fanotify.h
@@ -44,6 +44,7 @@ 
 
 /* Flags to determine fanotify event format */
 #define FAN_REPORT_TID		0x00000100	/* event->pid is thread id */
+#define FAN_REPORT_FID		0x00000200	/* Report unique file id */
 
 /* Deprecated - do not use this in programs and do not add new flags here! */
 #define FAN_ALL_INIT_FLAGS	(FAN_CLOEXEC | FAN_NONBLOCK | \
@@ -106,6 +107,24 @@  struct fanotify_event_metadata {
 	__s32 pid;
 };
 
+#define FAN_EVENT_INFO_TYPE_FID		1
+
+/* Variable length info record header following event metadata */
+struct fanotify_event_info {
+	__u8 info_type;
+	__u8 reserved;
+	__u16 info_len;
+	unsigned char info[0];
+};
+
+/* Unique file identifier info record */
+struct fanotify_event_fid {
+	__kernel_fsid_t fsid;
+	__u32 handle_bytes;
+	__s32 handle_type;
+	unsigned char f_handle[0];
+};
+
 struct fanotify_response {
 	__s32 fd;
 	__u32 response;
@@ -122,12 +141,19 @@  struct fanotify_response {
 /* Helper functions to deal with fanotify_event_metadata buffers */
 #define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata))
 
-#define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \
-				   (struct fanotify_event_metadata*)(((char *)(meta)) + \
-				   (meta)->event_len))
+#define FAN_EVENT_NEXT(meta, len) \
+	((len) -= (meta)->event_len, \
+	 (struct fanotify_event_metadata *)(((char *)(meta)) + \
+					   (meta)->event_len))
+
+#define FAN_EVENT_OK(meta, len)	\
+	((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \
+	 (long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \
+	 (long)(meta)->event_len <= (long)(len))
 
-#define FAN_EVENT_OK(meta, len)	((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \
-				(long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \
-				(long)(meta)->event_len <= (long)(len))
+/* Get the first event info record if one exists */
+#define FAN_EVENT_INFO(meta)	\
+	((long)(meta)->event_len > (long)FAN_EVENT_METADATA_LEN ? \
+	 (struct fanotify_event_info *)((meta) + 1) : NULL)
 
 #endif /* _UAPI_LINUX_FANOTIFY_H */