Re: [PATCH v2 5/5] fanotify: add pidfd support to the fanotify API
From: Jan Kara <jack@suse.cz>
Date: 2021-06-10 11:23:34
Also in:
linux-fsdevel
Hi Matthew! On Thu 10-06-21 10:21:50, Matthew Bobrowski wrote:
Introduce a new flag FAN_REPORT_PIDFD for fanotify_init(2) which allows userspace applications to control whether a pidfd info record containing a pidfd is to be returned with each event. If FAN_REPORT_PIDFD is enabled for a notification group, an additional struct fanotify_event_info_pidfd object will be supplied alongside the generic struct fanotify_event_metadata within a single event. This functionality is analogous to that of FAN_REPORT_FID in terms of how the event structure is supplied to the userspace application. Usage of FAN_REPORT_PIDFD with FAN_REPORT_FID/FAN_REPORT_DFID_NAME is permitted, and in this case a struct fanotify_event_info_pidfd object will follow any struct fanotify_event_info_fid object. Currently, the usage of FAN_REPORT_TID is not permitted along with FAN_REPORT_PIDFD as the pidfd API only supports the creation of pidfds for thread-group leaders. Additionally, the FAN_REPORT_PIDFD is limited to privileged processes only i.e. listeners that are running with the CAP_SYS_ADMIN capability. Attempting to supply either of these initialisation flags with FAN_REPORT_PIDFD will result with EINVAL being returned to the caller. In the event of a pidfd creation error, there are two types of error values that can be reported back to the listener. There is FAN_NOPIDFD, which will be reported in cases where the process responsible for generating the event has terminated prior to fanotify being able to create pidfd for event->pid via pidfd_create(). The there is FAN_EPIDFD, which will be reported if a more generic pidfd creation error occurred when calling pidfd_create(). Signed-off-by: Matthew Bobrowski <repnop@google.com>
A few comments in addition to what Amir wrote:
quoted hunk ↗ jump to hunk
@@ -524,6 +561,34 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, } metadata.fd = fd; + /* + * Currently, reporting a pidfd to an unprivileged listener is not + * supported. The FANOTIFY_UNPRIV flag is to be kept here so that a + * pidfd is not accidentally leaked to an unprivileged listener. + */ + if (pidfd_mode && !FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV)) {
Hum, you've added FAN_REPORT_PIDFD to FANOTIFY_ADMIN_INIT_FLAGS so this condition should be always true? I don't think we need to be that much defensive and would just drop the check here.
+ /*
+ * The PIDTYPE_TGID check for an event->pid is performed
+ * preemptively in attempt to catch those rare instances
+ * where the process responsible for generating the event has
+ * terminated prior to calling into pidfd_create() and
+ * acquiring a valid pidfd. Report FAN_NOPIDFD to the listener
+ * in those cases.
+ */
+ if (metadata.pid == 0 ||
+ !pid_has_task(event->pid, PIDTYPE_TGID)) {
+ pidfd = FAN_NOPIDFD;
+ } else {
+ pidfd = pidfd_create(event->pid, 0);
+ if (pidfd < 0)
+ /*
+ * All other pidfd creation errors are reported
+ * as FAN_EPIDFD to the listener.
+ */
+ pidfd = FAN_EPIDFD;
+ }
+ }
+
ret = -EFAULT;
/*
* Sanity check copy size in case get_one_event() and...
quoted hunk ↗ jump to hunk
@@ -558,6 +632,10 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, put_unused_fd(fd); fput(f); } + + if (pidfd < 0) + put_unused_fd(pidfd); +
put_unused_fd() is not enough to destroy the pidfd you have. That will just mark 'pidfd' as free in the fd table. You rather need to call close_fd() here to fully close open file. Honza -- Jan Kara [off-list ref] SUSE Labs, CR