Skip to content

Commit 7cea2a3

Browse files
amir73iljankara
authored andcommitted
fanotify: support limited functionality for unprivileged users
Add limited support for unprivileged fanotify groups. An unprivileged users is not allowed to get an open file descriptor in the event nor the process pid of another process. An unprivileged user cannot request permission events, cannot set mount/filesystem marks and cannot request unlimited queue/marks. This enables the limited functionality similar to inotify when watching a set of files and directories for OPEN/ACCESS/MODIFY/CLOSE events, without requiring SYS_CAP_ADMIN privileges. The FAN_REPORT_DFID_NAME init flag, provide a method for an unprivileged listener watching a set of directories (with FAN_EVENT_ON_CHILD) to monitor all changes inside those directories. This typically requires that the listener keeps a map of watched directory fid to dirfd (O_PATH), where fid is obtained with name_to_handle_at() before starting to watch for changes. When getting an event, the reported fid of the parent should be resolved to dirfd and fstatsat(2) with dirfd and name should be used to query the state of the filesystem entry. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent 5b8fea6 commit 7cea2a3

File tree

3 files changed

+57
-8
lines changed

3 files changed

+57
-8
lines changed

fs/notify/fanotify/fanotify_user.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,14 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
419419
metadata.reserved = 0;
420420
metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS;
421421
metadata.pid = pid_vnr(event->pid);
422+
/*
423+
* For an unprivileged listener, event->pid can be used to identify the
424+
* events generated by the listener process itself, without disclosing
425+
* the pids of other processes.
426+
*/
427+
if (!capable(CAP_SYS_ADMIN) &&
428+
task_tgid(current) != event->pid)
429+
metadata.pid = 0;
422430

423431
if (path && path->mnt && path->dentry) {
424432
fd = create_fd(group, path, &f);
@@ -1036,8 +1044,16 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
10361044
pr_debug("%s: flags=%x event_f_flags=%x\n",
10371045
__func__, flags, event_f_flags);
10381046

1039-
if (!capable(CAP_SYS_ADMIN))
1040-
return -EPERM;
1047+
if (!capable(CAP_SYS_ADMIN)) {
1048+
/*
1049+
* An unprivileged user can setup an fanotify group with
1050+
* limited functionality - an unprivileged group is limited to
1051+
* notification events with file handles and it cannot use
1052+
* unlimited queue/marks.
1053+
*/
1054+
if ((flags & FANOTIFY_ADMIN_INIT_FLAGS) || !fid_mode)
1055+
return -EPERM;
1056+
}
10411057

10421058
#ifdef CONFIG_AUDITSYSCALL
10431059
if (flags & ~(FANOTIFY_INIT_FLAGS | FAN_ENABLE_AUDIT))
@@ -1288,6 +1304,15 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
12881304
goto fput_and_out;
12891305
group = f.file->private_data;
12901306

1307+
/*
1308+
* An unprivileged user is not allowed to watch a mount point nor
1309+
* a filesystem.
1310+
*/
1311+
ret = -EPERM;
1312+
if (!capable(CAP_SYS_ADMIN) &&
1313+
mark_type != FAN_MARK_INODE)
1314+
goto fput_and_out;
1315+
12911316
/*
12921317
* group->priority == FS_PRIO_0 == FAN_CLASS_NOTIF. These are not
12931318
* allowed to set permissions events.

fs/notify/fdinfo.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ void fanotify_show_fdinfo(struct seq_file *m, struct file *f)
144144
struct fsnotify_group *group = f->private_data;
145145

146146
seq_printf(m, "fanotify flags:%x event-flags:%x\n",
147-
group->fanotify_data.flags, group->fanotify_data.f_flags);
147+
group->fanotify_data.flags,
148+
group->fanotify_data.f_flags);
148149

149150
show_fdinfo(m, f, fanotify_fdinfo);
150151
}

include/linux/fanotify.h

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,38 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */
1818
* these constant, the programs may break if re-compiled with new uapi headers
1919
* and then run on an old kernel.
2020
*/
21-
#define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \
21+
22+
/* Group classes where permission events are allowed */
23+
#define FANOTIFY_PERM_CLASSES (FAN_CLASS_CONTENT | \
2224
FAN_CLASS_PRE_CONTENT)
2325

26+
#define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FANOTIFY_PERM_CLASSES)
27+
2428
#define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME)
2529

26-
#define FANOTIFY_INIT_FLAGS (FANOTIFY_CLASS_BITS | FANOTIFY_FID_BITS | \
27-
FAN_REPORT_TID | \
28-
FAN_CLOEXEC | FAN_NONBLOCK | \
29-
FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS)
30+
/*
31+
* fanotify_init() flags that require CAP_SYS_ADMIN.
32+
* We do not allow unprivileged groups to request permission events.
33+
* We do not allow unprivileged groups to get other process pid in events.
34+
* We do not allow unprivileged groups to use unlimited resources.
35+
*/
36+
#define FANOTIFY_ADMIN_INIT_FLAGS (FANOTIFY_PERM_CLASSES | \
37+
FAN_REPORT_TID | \
38+
FAN_UNLIMITED_QUEUE | \
39+
FAN_UNLIMITED_MARKS)
40+
41+
/*
42+
* fanotify_init() flags that are allowed for user without CAP_SYS_ADMIN.
43+
* FAN_CLASS_NOTIF is the only class we allow for unprivileged group.
44+
* We do not allow unprivileged groups to get file descriptors in events,
45+
* so one of the flags for reporting file handles is required.
46+
*/
47+
#define FANOTIFY_USER_INIT_FLAGS (FAN_CLASS_NOTIF | \
48+
FANOTIFY_FID_BITS | \
49+
FAN_CLOEXEC | FAN_NONBLOCK)
50+
51+
#define FANOTIFY_INIT_FLAGS (FANOTIFY_ADMIN_INIT_FLAGS | \
52+
FANOTIFY_USER_INIT_FLAGS)
3053

3154
#define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \
3255
FAN_MARK_FILESYSTEM)

0 commit comments

Comments
 (0)