[PATCH v3 fanotify 1/2] fanotify: Introduce fanotify filter

Song Liu songliubraving at meta.com
Sun Nov 24 19:08:40 UTC 2024



> On Nov 23, 2024, at 10:25 PM, Amir Goldstein <amir73il at gmail.com> wrote:
> 
> On Sat, Nov 23, 2024 at 12:00 AM Song Liu <song at kernel.org> wrote:

[...]

>> 
>> To make fanotify filters more flexible, a filter can take arguments at
>> attach time.
>> 
>> sysfs entry /sys/kernel/fanotify_filter is added to help users know
>> which fanotify filters are available. At the moment, these files are
>> added for each filter: flags, desc, and init_args.
> 
> It's a shame that we have fanotify knobs at /proc/sys/fs/fanotify/ and
> in sysfs, but understand we don't want to make more use of proc for this.
> 
> Still I would add the filter files under a new /sys/fs/fanotify/ dir and not
> directly under /sys/kernel/

I don't have a strong preference either way. We can create it under
/sys/fs/fanotify if that makes more sense. 

> 
>> 
>> Signed-off-by: Song Liu <song at kernel.org>
>> ---
>> fs/notify/fanotify/Kconfig           |  13 ++
>> fs/notify/fanotify/Makefile          |   1 +
>> fs/notify/fanotify/fanotify.c        |  44 +++-
>> fs/notify/fanotify/fanotify_filter.c | 289 +++++++++++++++++++++++++++
>> fs/notify/fanotify/fanotify_user.c   |   7 +
>> include/linux/fanotify.h             | 128 ++++++++++++
>> include/linux/fsnotify_backend.h     |   6 +-
>> include/uapi/linux/fanotify.h        |  36 ++++
>> 8 files changed, 520 insertions(+), 4 deletions(-)
>> create mode 100644 fs/notify/fanotify/fanotify_filter.c
[...]
>> 
>>        BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
>>        BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
>> @@ -921,6 +924,39 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
>>        pr_debug("%s: group=%p mask=%x report_mask=%x\n", __func__,
>>                 group, mask, match_mask);
>> 
>> +       if (FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS))
>> +               fsid = fanotify_get_fsid(iter_info);
>> +
>> +#ifdef CONFIG_FANOTIFY_FILTER
>> +       filter_hook = srcu_dereference(group->fanotify_data.filter_hook, &fsnotify_mark_srcu);
> 
> Do we actually need the sleeping rcu protection for calling the hook?
> Can regular rcu read side be nested inside srcu read side?

I was thinking the filter function can still sleep, for example, to 
read an xattr. 

> 
> Jan,
> 
> I don't remember why srcu is needed since we are not holding it
> when waiting for userspace anymore?
> 
>> +       if (filter_hook) {
>> +               struct fanotify_filter_event filter_event = {
>> +                       .mask = mask,
>> +                       .data = data,
>> +                       .data_type = data_type,
>> +                       .dir = dir,
>> +                       .file_name = file_name,
>> +                       .fsid = &fsid,
>> +                       .match_mask = match_mask,
>> +               };

[...]

>> +
>> +       spin_lock(&filter_list_lock);
>> +       filter_ops = fanotify_filter_find(args.name);
>> +       if (!filter_ops || !try_module_get(filter_ops->owner)) {
>> +               spin_unlock(&filter_list_lock);
>> +               ret = -ENOENT;
>> +               goto err_free_hook;
>> +       }
>> +       spin_unlock(&filter_list_lock);
>> +
>> +       if (!capable(CAP_SYS_ADMIN) && (filter_ops->flags & FAN_FILTER_F_SYS_ADMIN_ONLY)) {
> 
> 1. feels better to opt-in for UNPRIV (and maybe later on) rather than
> make it the default.

Sure. 

> 2. need to check that filter_ops->flags has only "known" flags

Agreed. 

> 3. probably need to add filter_ops->version check in case we want to
> change the ABI

I think we can let the author of the filter handle versioning 
inside filter_init function. Many users may not need any logic
for compatibility. 

> 
>> +               ret = -EPERM;
>> +               goto err_module_put;
>> +       }
>> +

[...]

>> +
>> +/*
>> + * fanotify_filter_del - Delete a filter from fsnotify_group.
>> + */
>> +void fanotify_filter_del(struct fsnotify_group *group)
>> +{
>> +       struct fanotify_filter_hook *filter_hook;
>> +
>> +       fsnotify_group_lock(group);
>> +       filter_hook = group->fanotify_data.filter_hook;
>> +       if (!filter_hook)
>> +               goto out;
>> +
>> +       rcu_assign_pointer(group->fanotify_data.filter_hook, NULL);
>> +       fanotify_filter_hook_free(filter_hook);
> 
> The read side is protected with srcu and there is no srcu/rcu delay of freeing.
> You will either need something along the lines of
> fsnotify_connector_destroy_workfn() with synchronize_srcu()

Yeah, we do need a synchronize_srcu() here. I will fix this in 
the next version. 

> or use regular rcu delay and read side (assuming that it can be nested inside
> srcu read side?).

Thanks for the review!

Song



More information about the Linux-security-module-archive mailing list