diff mbox series

inotify: disallow watches on unsupported filesystems

Message ID 20250304080044.7623-1-ImanDevel@gmail.com (mailing list archive)
State New
Headers show
Series inotify: disallow watches on unsupported filesystems | expand

Commit Message

Seyediman Seyedarab March 4, 2025, 8 a.m. UTC
currently, inotify_add_watch() allows adding watches on filesystems
where inotify does not work correctly, without returning an explicit
error. This behavior is misleading and can cause confusion for users
expecting inotify to work on a certain filesystem.

This patch explicitly rejects inotify usage on filesystems where it
is known to be unreliable, such as sysfs, procfs, overlayfs, 9p, fuse,
and others.

By returning -EOPNOTSUPP, the limitation is made explicit, preventing
users from making incorrect assumptions about inotify behavior.

Signed-off-by: Seyediman Seyedarab <ImanDevel@gmail.com>
---
 fs/notify/inotify/inotify_user.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

Comments

Amir Goldstein March 4, 2025, 11:57 a.m. UTC | #1
On Tue, Mar 4, 2025 at 8:59 AM Seyediman Seyedarab <imandevel@gmail.com> wrote:
>
> currently, inotify_add_watch() allows adding watches on filesystems
> where inotify does not work correctly, without returning an explicit
> error. This behavior is misleading and can cause confusion for users
> expecting inotify to work on a certain filesystem.

That maybe so, but it's not that inotify does not work at all,
in fact it probably works most of the time for those fs,
so there may be users setting inotify watches on those fs,
so it is not right to regress those users.

>
> This patch explicitly rejects inotify usage on filesystems where it
> is known to be unreliable, such as sysfs, procfs, overlayfs, 9p, fuse,
> and others.

Where did you get this list of fs from?
Why do you claim that inotify does not work on overlayfs?
Specifically, there are two LTP tests inotify07 and inotify08
that test inotify over overlayfs.

This makes me question other fs on your list.

>
> By returning -EOPNOTSUPP, the limitation is made explicit, preventing
> users from making incorrect assumptions about inotify behavior.
>
> Signed-off-by: Seyediman Seyedarab <ImanDevel@gmail.com>
> ---
>  fs/notify/inotify/inotify_user.c | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
>
> diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
> index b372fb2c56bd..9b96438f4d46 100644
> --- a/fs/notify/inotify/inotify_user.c
> +++ b/fs/notify/inotify/inotify_user.c
> @@ -87,6 +87,13 @@ static const struct ctl_table inotify_table[] = {
>         },
>  };
>
> +static const unsigned long unwatchable_fs[] = {
> +       PROC_SUPER_MAGIC,      SYSFS_MAGIC,       TRACEFS_MAGIC,
> +       DEBUGFS_MAGIC,        CGROUP_SUPER_MAGIC, SECURITYFS_MAGIC,
> +       RAMFS_MAGIC,          DEVPTS_SUPER_MAGIC, BPF_FS_MAGIC,
> +       OVERLAYFS_SUPER_MAGIC, FUSE_SUPER_MAGIC,   NFS_SUPER_MAGIC
> +};
> +
>  static void __init inotify_sysctls_init(void)
>  {
>         register_sysctl("fs/inotify", inotify_table);
> @@ -690,6 +697,14 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)
>  }
>
>
> +static inline bool is_unwatchable_fs(struct inode *inode)
> +{
> +       for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
> +               if (inode->i_sb->s_magic == unwatchable_fs[i])
> +                       return true;
> +       return false;
> +}

This is not a good practice for black listing fs.

See commit 0b3b094ac9a7b ("fanotify: Disallow permission events
for proc filesystem") for a better practice, but again, we cannot just
stop supporting inotify on fs where it was supported.

The assumption with the commit above was that setting permission
events on procfs is possible, but nobody (except for fuzzers) really does that
and if we have found out that there were actual users that do it, we
would have needed to revert that commit.

Thanks,
Amir.
Seyediman Seyedarab March 4, 2025, 4:06 p.m. UTC | #2
On 25/03/04 12:57PM, Amir Goldstein wrote:
> On Tue, Mar 4, 2025 at 8:59 AM Seyediman Seyedarab <imandevel@gmail.com> wrote:
> >
> > currently, inotify_add_watch() allows adding watches on filesystems
> > where inotify does not work correctly, without returning an explicit
> > error. This behavior is misleading and can cause confusion for users
> > expecting inotify to work on a certain filesystem.
> 
> That maybe so, but it's not that inotify does not work at all,
> in fact it probably works most of the time for those fs,
> so there may be users setting inotify watches on those fs,
> so it is not right to regress those users.
> 
> >
> > This patch explicitly rejects inotify usage on filesystems where it
> > is known to be unreliable, such as sysfs, procfs, overlayfs, 9p, fuse,
> > and others.
> 
> Where did you get this list of fs from?
> Why do you claim that inotify does not work on overlayfs?
> Specifically, there are two LTP tests inotify07 and inotify08
> that test inotify over overlayfs.
> 
> This makes me question other fs on your list.

Thanks for the review! I may have overlooked overlayfs, but these
following discussions led me to include it in the blacklist:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/882147
https://github.com/libuv/libuv/issues/1201
https://github.com/moby/moby/issues/11705

Apparently, things have changed in v4.10, so I may have been wrong
about overlayfs. I can test each filesystem and provide a response
instead of blindly relying on various bug reports. However, let's
first discuss whether the patch is necessary in the first place.

> >
> > By returning -EOPNOTSUPP, the limitation is made explicit, preventing
> > users from making incorrect assumptions about inotify behavior.
> >
> > Signed-off-by: Seyediman Seyedarab <ImanDevel@gmail.com>
> > ---
> >  fs/notify/inotify/inotify_user.c | 22 ++++++++++++++++++++++
> >  1 file changed, 22 insertions(+)
> >
> > diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
> > index b372fb2c56bd..9b96438f4d46 100644
> > --- a/fs/notify/inotify/inotify_user.c
> > +++ b/fs/notify/inotify/inotify_user.c
> > @@ -87,6 +87,13 @@ static const struct ctl_table inotify_table[] = {
> >         },
> >  };
> >
> > +static const unsigned long unwatchable_fs[] = {
> > +       PROC_SUPER_MAGIC,      SYSFS_MAGIC,       TRACEFS_MAGIC,
> > +       DEBUGFS_MAGIC,        CGROUP_SUPER_MAGIC, SECURITYFS_MAGIC,
> > +       RAMFS_MAGIC,          DEVPTS_SUPER_MAGIC, BPF_FS_MAGIC,
> > +       OVERLAYFS_SUPER_MAGIC, FUSE_SUPER_MAGIC,   NFS_SUPER_MAGIC
> > +};
> > +
> >  static void __init inotify_sysctls_init(void)
> >  {
> >         register_sysctl("fs/inotify", inotify_table);
> > @@ -690,6 +697,14 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)
> >  }
> >
> >
> > +static inline bool is_unwatchable_fs(struct inode *inode)
> > +{
> > +       for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
> > +               if (inode->i_sb->s_magic == unwatchable_fs[i])
> > +                       return true;
> > +       return false;
> > +}
> 
> This is not a good practice for black listing fs.
> 
> See commit 0b3b094ac9a7b ("fanotify: Disallow permission events
> for proc filesystem") for a better practice, but again, we cannot just
> stop supporting inotify on fs where it was supported.

Following the same approach as 0b3b094ac9a7b ("fanotify: Disallow
permission events for the proc filesystem") would require setting
a specific flag for each fs that isn't supported by inotify. If this
is more suitable, I can work on implementing it.

I understand why it might seem like disallowing users from monitoring
these filesystems could break userspace in some way. BUT, programs
work incorrectly precisely because they do not receive any information
from the kernel, so in other words they are already broken. There is no
way for them to know if the fs is supported or not. I mean, even we are
not sure at the moment, then how would they know.

As an example, 'Waybar' is a userspace program affected by this patch.
Since it relies on monitoring sysfs, it isn't working properly anyway.
This is also due to the issue mentioned earlier... inotify_add_watch()
returns without an error, so the developers haven't realized that
inotify isn't actually supported on sysfs. There are over five
discussions regarding this issue that you can find them here:
https://github.com/Alexays/Waybar/pull/3474

That said, I understand if this isn't the approach you're looking for.

Kindest Regards,
Seyediman
Amir Goldstein March 4, 2025, 4:41 p.m. UTC | #3
On Tue, Mar 4, 2025 at 5:05 PM Seyediman Seyedarab <imandevel@gmail.com> wrote:
>
> On 25/03/04 12:57PM, Amir Goldstein wrote:
> > On Tue, Mar 4, 2025 at 8:59 AM Seyediman Seyedarab <imandevel@gmail.com> wrote:
> > >
> > > currently, inotify_add_watch() allows adding watches on filesystems
> > > where inotify does not work correctly, without returning an explicit
> > > error. This behavior is misleading and can cause confusion for users
> > > expecting inotify to work on a certain filesystem.
> >
> > That maybe so, but it's not that inotify does not work at all,
> > in fact it probably works most of the time for those fs,
> > so there may be users setting inotify watches on those fs,
> > so it is not right to regress those users.
> >
> > >
> > > This patch explicitly rejects inotify usage on filesystems where it
> > > is known to be unreliable, such as sysfs, procfs, overlayfs, 9p, fuse,
> > > and others.
> >
> > Where did you get this list of fs from?
> > Why do you claim that inotify does not work on overlayfs?
> > Specifically, there are two LTP tests inotify07 and inotify08
> > that test inotify over overlayfs.
> >
> > This makes me question other fs on your list.
>
> Thanks for the review! I may have overlooked overlayfs, but these
> following discussions led me to include it in the blacklist:
> https://bugs.launchpad.net/ubuntu/+source/linux/+bug/882147
> https://github.com/libuv/libuv/issues/1201
> https://github.com/moby/moby/issues/11705
>
> Apparently, things have changed in v4.10, so I may have been wrong
> about overlayfs. I can test each filesystem and provide a response
> instead of blindly relying on various bug reports. However, let's
> first discuss whether the patch is necessary in the first place.
>
> > >
> > > By returning -EOPNOTSUPP, the limitation is made explicit, preventing
> > > users from making incorrect assumptions about inotify behavior.
> > >
> > > Signed-off-by: Seyediman Seyedarab <ImanDevel@gmail.com>
> > > ---
> > >  fs/notify/inotify/inotify_user.c | 22 ++++++++++++++++++++++
> > >  1 file changed, 22 insertions(+)
> > >
> > > diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
> > > index b372fb2c56bd..9b96438f4d46 100644
> > > --- a/fs/notify/inotify/inotify_user.c
> > > +++ b/fs/notify/inotify/inotify_user.c
> > > @@ -87,6 +87,13 @@ static const struct ctl_table inotify_table[] = {
> > >         },
> > >  };
> > >
> > > +static const unsigned long unwatchable_fs[] = {
> > > +       PROC_SUPER_MAGIC,      SYSFS_MAGIC,       TRACEFS_MAGIC,
> > > +       DEBUGFS_MAGIC,        CGROUP_SUPER_MAGIC, SECURITYFS_MAGIC,
> > > +       RAMFS_MAGIC,          DEVPTS_SUPER_MAGIC, BPF_FS_MAGIC,
> > > +       OVERLAYFS_SUPER_MAGIC, FUSE_SUPER_MAGIC,   NFS_SUPER_MAGIC
> > > +};
> > > +
> > >  static void __init inotify_sysctls_init(void)
> > >  {
> > >         register_sysctl("fs/inotify", inotify_table);
> > > @@ -690,6 +697,14 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)
> > >  }
> > >
> > >
> > > +static inline bool is_unwatchable_fs(struct inode *inode)
> > > +{
> > > +       for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
> > > +               if (inode->i_sb->s_magic == unwatchable_fs[i])
> > > +                       return true;
> > > +       return false;
> > > +}
> >
> > This is not a good practice for black listing fs.
> >
> > See commit 0b3b094ac9a7b ("fanotify: Disallow permission events
> > for proc filesystem") for a better practice, but again, we cannot just
> > stop supporting inotify on fs where it was supported.
>
> Following the same approach as 0b3b094ac9a7b ("fanotify: Disallow
> permission events for the proc filesystem") would require setting
> a specific flag for each fs that isn't supported by inotify. If this
> is more suitable, I can work on implementing it.
>
> I understand why it might seem like disallowing users from monitoring
> these filesystems could break userspace in some way. BUT, programs
> work incorrectly precisely because they do not receive any information
> from the kernel, so in other words they are already broken. There is no
> way for them to know if the fs is supported or not. I mean, even we are
> not sure at the moment, then how would they know.
>

Programs not knowing is a problem that could be fixed with a new API
or new init flag to fanotify/inotify.

Existing programs that would break due to this change is unacceptable.

> As an example, 'Waybar' is a userspace program affected by this patch.
> Since it relies on monitoring sysfs, it isn't working properly anyway.
> This is also due to the issue mentioned earlier... inotify_add_watch()
> returns without an error, so the developers haven't realized that
> inotify isn't actually supported on sysfs. There are over five
> discussions regarding this issue that you can find them here:
> https://github.com/Alexays/Waybar/pull/3474
>

You need to distinguish "inotify does not work"
from "inotify does not notify on 'remote' changes"
that is changes that happen on the network fs server or inside the
kernel (in sysfs case) vs. changes that happen via vfs syscalls
on the mounted fs, be it p9, cifs, sysfs.

There are several discussions about supporting "remote change"
notifications for network filesystems - this is a more complex problem.

In any case, I believe performing operations on the mounted fs
generated inotify events for all the fs that you listed and without
a claim that nobody is using this facility we cannot regress this
behavior without an opt-in from the application.

Thanks,
Amir.
Seyediman Seyedarab March 4, 2025, 7:07 p.m. UTC | #4
On 25/03/04 05:41PM, Amir Goldstein wrote:
> On Tue, Mar 4, 2025 at 5:05 PM Seyediman Seyedarab <imandevel@gmail.com> wrote:
> >
> > On 25/03/04 12:57PM, Amir Goldstein wrote:
> > > On Tue, Mar 4, 2025 at 8:59 AM Seyediman Seyedarab <imandevel@gmail.com> wrote:

> > I understand why it might seem like disallowing users from monitoring
> > these filesystems could break userspace in some way. BUT, programs
> > work incorrectly precisely because they do not receive any information
> > from the kernel, so in other words they are already broken. There is no
> > way for them to know if the fs is supported or not. I mean, even we are
> > not sure at the moment, then how would they know.
> 
> Programs not knowing is a problem that could be fixed with a new API
> or new init flag to fanotify/inotify.
> 
> Existing programs that would break due to this change is unacceptable.
> 

Maybe something like IN_DISALLOW_REMOTE could work for now, at least
until remote change notifications are properly implemented for those
specific filesystems? Later, if needed, it could evolve into a new API,
and the flag could become the default behavior when passed to that API.

> > As an example, 'Waybar' is a userspace program affected by this patch.
> > Since it relies on monitoring sysfs, it isn't working properly anyway.
> > This is also due to the issue mentioned earlier... inotify_add_watch()
> > returns without an error, so the developers haven't realized that
> > inotify isn't actually supported on sysfs. There are over five
> > discussions regarding this issue that you can find them here:
> > https://github.com/Alexays/Waybar/pull/3474
> >
> 
> You need to distinguish "inotify does not work"
> from "inotify does not notify on 'remote' changes"
> that is changes that happen on the network fs server or inside the
> kernel (in sysfs case) vs. changes that happen via vfs syscalls
> on the mounted fs, be it p9, cifs, sysfs.
> 
> There are several discussions about supporting "remote change"
> notifications for network filesystems - this is a more complex problem.
> 
> In any case, I believe performing operations on the mounted fs
> generated inotify events for all the fs that you listed and without
> a claim that nobody is using this facility we cannot regress this
> behavior without an opt-in from the application.

Understood. So this is what I should work on (correct me if anything
seems off):
1. Carefully list all filesystems where "remote" changes occur.
2. Introduce a flag like FS_DISALLOW_INOTIFY_REMOTE in fs_flags
   for these filesystems.
3. Provide an option for userspace, such as IN_DISALLOW_REMOTE,
   so applications can explicitly handle this behavior.
4. (Possibly later, if it makes sense) Introduce a new syscall where
   FS_DISALLOW_INOTIFY_REMOTE is the default behavior.

Regards,
Seyediman
Amir Goldstein March 4, 2025, 8:04 p.m. UTC | #5
On Tue, Mar 4, 2025 at 8:06 PM Seyediman Seyedarab <imandevel@gmail.com> wrote:
>
> On 25/03/04 05:41PM, Amir Goldstein wrote:
> > On Tue, Mar 4, 2025 at 5:05 PM Seyediman Seyedarab <imandevel@gmail.com> wrote:
> > >
> > > On 25/03/04 12:57PM, Amir Goldstein wrote:
> > > > On Tue, Mar 4, 2025 at 8:59 AM Seyediman Seyedarab <imandevel@gmail.com> wrote:
>
> > > I understand why it might seem like disallowing users from monitoring
> > > these filesystems could break userspace in some way. BUT, programs
> > > work incorrectly precisely because they do not receive any information
> > > from the kernel, so in other words they are already broken. There is no
> > > way for them to know if the fs is supported or not. I mean, even we are
> > > not sure at the moment, then how would they know.
> >
> > Programs not knowing is a problem that could be fixed with a new API
> > or new init flag to fanotify/inotify.
> >
> > Existing programs that would break due to this change is unacceptable.
> >
>
> Maybe something like IN_DISALLOW_REMOTE could work for now, at least
> until remote change notifications are properly implemented for those
> specific filesystems? Later, if needed, it could evolve into a new API,
> and the flag could become the default behavior when passed to that API.
>
> > > As an example, 'Waybar' is a userspace program affected by this patch.
> > > Since it relies on monitoring sysfs, it isn't working properly anyway.
> > > This is also due to the issue mentioned earlier... inotify_add_watch()
> > > returns without an error, so the developers haven't realized that
> > > inotify isn't actually supported on sysfs. There are over five
> > > discussions regarding this issue that you can find them here:
> > > https://github.com/Alexays/Waybar/pull/3474
> > >
> >
> > You need to distinguish "inotify does not work"
> > from "inotify does not notify on 'remote' changes"
> > that is changes that happen on the network fs server or inside the
> > kernel (in sysfs case) vs. changes that happen via vfs syscalls
> > on the mounted fs, be it p9, cifs, sysfs.
> >
> > There are several discussions about supporting "remote change"
> > notifications for network filesystems - this is a more complex problem.
> >
> > In any case, I believe performing operations on the mounted fs
> > generated inotify events for all the fs that you listed and without
> > a claim that nobody is using this facility we cannot regress this
> > behavior without an opt-in from the application.
>
> Understood. So this is what I should work on (correct me if anything
> seems off):
> 1. Carefully list all filesystems where "remote" changes occur.
> 2. Introduce a flag like FS_DISALLOW_INOTIFY_REMOTE in fs_flags
>    for these filesystems.
> 3. Provide an option for userspace, such as IN_DISALLOW_REMOTE,
>    so applications can explicitly handle this behavior.
> 4. (Possibly later, if it makes sense) Introduce a new syscall where
>    FS_DISALLOW_INOTIFY_REMOTE is the default behavior.
>

Generally, this is a correct way to add new functionality,
but I would rather not extend the inotify API.
fanotify API is (mostly) a super set of inotify API, so any extension
of the API better be of fanotify.

If you try to use fanotify API with FAN_REPORT_FID and
FAN_MARK_FILESYSTEM, for example, by running the tool
fsnotifywait --filesystem, I think that you will find out that many of the fs
that you wanted to blacklist already return -EOPNOTSUPP, because they
do not support nfs export and some return -ENODEV (e.g. fuse)
because they do not have an fsid.
So essentially, you (almost) already have the new API that you wanted.

As a matter of fact, before commit a95aef69a740 ("fanotify: support
reporting non-decodeable file handles") in kernel v6.6, FAN_MARK_INODE
would also yield the same result (i.e. fsnotifywait without
--filesystem) and that
is more or less equivalent to inotifywait, because unlike fsnotifywait
--filesystem,
it does not require CAP_SYS_ADMIN.

Please see if fsnotifywait --filesystem is failing to watch the filesystems
that you are interested in blacklisting and list the filesystems that do not
fail and you think should fail to watch.

If there are filesystems that do not fail (e.g. cifs) and you still want to
blacklist them, please argue your reasons.

If the behavior you get from fsnotifywait --filesystem is matching your
expectations and the only problem is that fsnotifywait without --filesystem
on recent kernel does not match your expectations, it would be easy
to add a fanotify_init flag like FAN_REPORT_DECODEABLE_FID,
which enforces the same strict requirements as --filesystem,
but does not require CAP_SYS_ADMIN.

But generally, the relation between the fs that you define as
"unreliable" to the fs that work with --filesystem is circumstantial.
A better way to identify fs that are remote fs is to check if they
implement the d_revalidate() operation.

It's easy to add an fanotify_init flag to disallow those remote fs,
but we really need to first better define what is the desired goal.
Exercise - try to write the man page of the proposed new flag
in a way that is clear to anyone who reads the description.
If you manage to do that, you are far more likely to argue your case.

Thanks,
Amir.
kernel test robot March 5, 2025, 10:28 a.m. UTC | #6
Hi Seyediman,

kernel test robot noticed the following build errors:

[auto build test ERROR on jack-fs/fsnotify]
[also build test ERROR on linus/master v6.14-rc5 next-20250304]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Seyediman-Seyedarab/inotify-disallow-watches-on-unsupported-filesystems/20250304-160213
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git fsnotify
patch link:    https://lore.kernel.org/r/20250304080044.7623-1-ImanDevel%40gmail.com
patch subject: [PATCH] inotify: disallow watches on unsupported filesystems
config: s390-randconfig-002-20250305 (https://download.01.org/0day-ci/archive/20250305/202503051755.5uktuxba-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250305/202503051755.5uktuxba-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202503051755.5uktuxba-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from include/linux/kernel.h:16,
                    from include/linux/cpumask.h:11,
                    from include/linux/smp.h:13,
                    from include/linux/lockdep.h:14,
                    from include/linux/spinlock.h:63,
                    from include/linux/wait.h:9,
                    from include/linux/wait_bit.h:8,
                    from include/linux/fs.h:6,
                    from fs/notify/inotify/inotify_user.c:17:
   fs/notify/inotify/inotify_user.c: In function 'is_unwatchable_fs':
>> fs/notify/inotify/inotify_user.c:702:40: error: 'unwatchable_fs' undeclared (first use in this function); did you mean 'is_unwatchable_fs'?
     702 |         for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
         |                                        ^~~~~~~~~~~~~~
   include/linux/array_size.h:11:33: note: in definition of macro 'ARRAY_SIZE'
      11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
         |                                 ^~~
   fs/notify/inotify/inotify_user.c:702:40: note: each undeclared identifier is reported only once for each function it appears in
     702 |         for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
         |                                        ^~~~~~~~~~~~~~
   include/linux/array_size.h:11:33: note: in definition of macro 'ARRAY_SIZE'
      11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
         |                                 ^~~
   In file included from include/linux/file.h:9,
                    from fs/notify/inotify/inotify_user.c:16:
   include/linux/compiler.h:245:77: error: expression in static assertion is not an integer
     245 | #define __BUILD_BUG_ON_ZERO_MSG(e, msg) ((int)sizeof(struct {_Static_assert(!(e), msg);}))
         |                                                                             ^
   include/linux/compiler.h:249:33: note: in expansion of macro '__BUILD_BUG_ON_ZERO_MSG'
     249 | #define __must_be_array(a)      __BUILD_BUG_ON_ZERO_MSG(__same_type((a), &(a)[0]), "must be array")
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~
   include/linux/array_size.h:11:59: note: in expansion of macro '__must_be_array'
      11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
         |                                                           ^~~~~~~~~~~~~~~
   fs/notify/inotify/inotify_user.c:702:29: note: in expansion of macro 'ARRAY_SIZE'
     702 |         for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
         |                             ^~~~~~~~~~


vim +702 fs/notify/inotify/inotify_user.c

   698	
   699	
   700	static inline bool is_unwatchable_fs(struct inode *inode)
   701	{
 > 702		for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
   703			if (inode->i_sb->s_magic == unwatchable_fs[i])
   704				return true;
   705		return false;
   706	}
   707
kernel test robot March 5, 2025, 3:08 p.m. UTC | #7
Hi Seyediman,

kernel test robot noticed the following build errors:

[auto build test ERROR on jack-fs/fsnotify]
[also build test ERROR on linus/master v6.14-rc5 next-20250305]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Seyediman-Seyedarab/inotify-disallow-watches-on-unsupported-filesystems/20250304-160213
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git fsnotify
patch link:    https://lore.kernel.org/r/20250304080044.7623-1-ImanDevel%40gmail.com
patch subject: [PATCH] inotify: disallow watches on unsupported filesystems
config: powerpc-randconfig-001-20250305 (https://download.01.org/0day-ci/archive/20250305/202503052203.vK0McbRm-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250305/202503052203.vK0McbRm-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202503052203.vK0McbRm-lkp@intel.com/

All errors (new ones prefixed by >>):

>> fs/notify/inotify/inotify_user.c:702:33: error: use of undeclared identifier 'unwatchable_fs'; did you mean 'is_unwatchable_fs'?
     702 |         for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
         |                                        ^~~~~~~~~~~~~~
         |                                        is_unwatchable_fs
   include/linux/array_size.h:11:33: note: expanded from macro 'ARRAY_SIZE'
      11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
         |                                 ^
   fs/notify/inotify/inotify_user.c:700:20: note: 'is_unwatchable_fs' declared here
     700 | static inline bool is_unwatchable_fs(struct inode *inode)
         |                    ^
>> fs/notify/inotify/inotify_user.c:702:33: error: use of undeclared identifier 'unwatchable_fs'; did you mean 'is_unwatchable_fs'?
     702 |         for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
         |                                        ^~~~~~~~~~~~~~
         |                                        is_unwatchable_fs
   include/linux/array_size.h:11:48: note: expanded from macro 'ARRAY_SIZE'
      11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
         |                                                ^
   fs/notify/inotify/inotify_user.c:700:20: note: 'is_unwatchable_fs' declared here
     700 | static inline bool is_unwatchable_fs(struct inode *inode)
         |                    ^
>> fs/notify/inotify/inotify_user.c:702:22: error: subscript of pointer to function type 'bool (struct inode *)' (aka '_Bool (struct inode *)')
     702 |         for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
         |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/array_size.h:11:47: note: expanded from macro 'ARRAY_SIZE'
      11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
         |                                               ^~~~~
>> fs/notify/inotify/inotify_user.c:702:33: error: use of undeclared identifier 'unwatchable_fs'; did you mean 'is_unwatchable_fs'?
     702 |         for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
         |                                        ^~~~~~~~~~~~~~
         |                                        is_unwatchable_fs
   include/linux/array_size.h:11:75: note: expanded from macro 'ARRAY_SIZE'
      11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
         |                                                                           ^
   include/linux/compiler.h:249:65: note: expanded from macro '__must_be_array'
     249 | #define __must_be_array(a)      __BUILD_BUG_ON_ZERO_MSG(__same_type((a), &(a)[0]), "must be array")
         |                                                                      ^
   include/linux/compiler_types.h:483:63: note: expanded from macro '__same_type'
     483 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
         |                                                               ^
   include/linux/compiler.h:245:79: note: expanded from macro '__BUILD_BUG_ON_ZERO_MSG'
     245 | #define __BUILD_BUG_ON_ZERO_MSG(e, msg) ((int)sizeof(struct {_Static_assert(!(e), msg);}))
         |                                                                               ^
   fs/notify/inotify/inotify_user.c:700:20: note: 'is_unwatchable_fs' declared here
     700 | static inline bool is_unwatchable_fs(struct inode *inode)
         |                    ^
>> fs/notify/inotify/inotify_user.c:702:33: error: use of undeclared identifier 'unwatchable_fs'; did you mean 'is_unwatchable_fs'?
     702 |         for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
         |                                        ^~~~~~~~~~~~~~
         |                                        is_unwatchable_fs
   include/linux/array_size.h:11:75: note: expanded from macro 'ARRAY_SIZE'
      11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
         |                                                                           ^
   include/linux/compiler.h:249:71: note: expanded from macro '__must_be_array'
     249 | #define __must_be_array(a)      __BUILD_BUG_ON_ZERO_MSG(__same_type((a), &(a)[0]), "must be array")
         |                                                                            ^
   include/linux/compiler_types.h:483:74: note: expanded from macro '__same_type'
     483 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
         |                                                                          ^
   include/linux/compiler.h:245:79: note: expanded from macro '__BUILD_BUG_ON_ZERO_MSG'
     245 | #define __BUILD_BUG_ON_ZERO_MSG(e, msg) ((int)sizeof(struct {_Static_assert(!(e), msg);}))
         |                                                                               ^
   fs/notify/inotify/inotify_user.c:700:20: note: 'is_unwatchable_fs' declared here
     700 | static inline bool is_unwatchable_fs(struct inode *inode)
         |                    ^
>> fs/notify/inotify/inotify_user.c:702:22: error: subscript of pointer to function type 'bool (struct inode *)' (aka '_Bool (struct inode *)')
     702 |         for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
         |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/array_size.h:11:59: note: expanded from macro 'ARRAY_SIZE'
      11 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
         |                                                           ^~~~~~~~~~~~~~~~~~~~
   include/linux/compiler.h:249:70: note: expanded from macro '__must_be_array'
     249 | #define __must_be_array(a)      __BUILD_BUG_ON_ZERO_MSG(__same_type((a), &(a)[0]), "must be array")
         |                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/compiler_types.h:483:74: note: expanded from macro '__same_type'
     483 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
         |                                                                          ^
   include/linux/compiler.h:245:79: note: expanded from macro '__BUILD_BUG_ON_ZERO_MSG'
     245 | #define __BUILD_BUG_ON_ZERO_MSG(e, msg) ((int)sizeof(struct {_Static_assert(!(e), msg);}))
         |                                                                               ^
   fs/notify/inotify/inotify_user.c:703:31: error: use of undeclared identifier 'unwatchable_fs'; did you mean 'is_unwatchable_fs'?
     703 |                 if (inode->i_sb->s_magic == unwatchable_fs[i])
         |                                             ^~~~~~~~~~~~~~
         |                                             is_unwatchable_fs
   fs/notify/inotify/inotify_user.c:700:20: note: 'is_unwatchable_fs' declared here
     700 | static inline bool is_unwatchable_fs(struct inode *inode)
         |                    ^
   fs/notify/inotify/inotify_user.c:703:31: error: subscript of pointer to function type 'bool (struct inode *)' (aka '_Bool (struct inode *)')
     703 |                 if (inode->i_sb->s_magic == unwatchable_fs[i])
         |                                             ^~~~~~~~~~~~~~
   8 errors generated.


vim +702 fs/notify/inotify/inotify_user.c

   698	
   699	
   700	static inline bool is_unwatchable_fs(struct inode *inode)
   701	{
 > 702		for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
   703			if (inode->i_sb->s_magic == unwatchable_fs[i])
   704				return true;
   705		return false;
   706	}
   707
diff mbox series

Patch

diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index b372fb2c56bd..9b96438f4d46 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -87,6 +87,13 @@  static const struct ctl_table inotify_table[] = {
 	},
 };
 
+static const unsigned long unwatchable_fs[] = {
+	PROC_SUPER_MAGIC,      SYSFS_MAGIC,	  TRACEFS_MAGIC,
+	DEBUGFS_MAGIC,	      CGROUP_SUPER_MAGIC, SECURITYFS_MAGIC,
+	RAMFS_MAGIC,	      DEVPTS_SUPER_MAGIC, BPF_FS_MAGIC,
+	OVERLAYFS_SUPER_MAGIC, FUSE_SUPER_MAGIC,   NFS_SUPER_MAGIC
+};
+
 static void __init inotify_sysctls_init(void)
 {
 	register_sysctl("fs/inotify", inotify_table);
@@ -690,6 +697,14 @@  static struct fsnotify_group *inotify_new_group(unsigned int max_events)
 }
 
 
+static inline bool is_unwatchable_fs(struct inode *inode)
+{
+	for (int i = 0; i < ARRAY_SIZE(unwatchable_fs); i++)
+		if (inode->i_sb->s_magic == unwatchable_fs[i])
+			return true;
+	return false;
+}
+
 /* inotify syscalls */
 static int do_inotify_init(int flags)
 {
@@ -777,6 +792,13 @@  SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
 	inode = path.dentry->d_inode;
 	group = fd_file(f)->private_data;
 
+	/* ensure that inotify is only used on supported filesystems */
+	if (is_unwatchable_fs(inode)) {
+		pr_debug("%s: inotify is not supported on filesystem with s_magic=0x%lx\n",
+				__func__, inode->i_sb->s_magic);
+		return -EOPNOTSUPP;
+	}
+
 	/* create/update an inode mark */
 	ret = inotify_update_watch(group, inode, mask);
 	path_put(&path);