tracefs: Only clobber mode/uid/gid on remount if asked
authorBrian Norris <briannorris@chromium.org>
Sat, 27 Aug 2022 00:44:17 +0000 (17:44 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 20 Sep 2022 09:50:16 +0000 (11:50 +0200)
commit 47311db8e8f33011d90dee76b39c8886120cdda4 upstream.

Users may have explicitly configured their tracefs permissions; we
shouldn't overwrite those just because a second mount appeared.

Only clobber if the options were provided at mount time.

Note: the previous behavior was especially surprising in the presence of
automounted /sys/kernel/debug/tracing/.

Existing behavior:

  ## Pre-existing status: tracefs is 0755.
  # stat -c '%A' /sys/kernel/tracing/
  drwxr-xr-x

  ## (Re)trigger the automount.
  # umount /sys/kernel/debug/tracing
  # stat -c '%A' /sys/kernel/debug/tracing/.
  drwx------

  ## Unexpected: the automount changed mode for other mount instances.
  # stat -c '%A' /sys/kernel/tracing/
  drwx------

New behavior (after this change):

  ## Pre-existing status: tracefs is 0755.
  # stat -c '%A' /sys/kernel/tracing/
  drwxr-xr-x

  ## (Re)trigger the automount.
  # umount /sys/kernel/debug/tracing
  # stat -c '%A' /sys/kernel/debug/tracing/.
  drwxr-xr-x

  ## Expected: the automount does not change other mount instances.
  # stat -c '%A' /sys/kernel/tracing/
  drwxr-xr-x

Link: https://lkml.kernel.org/r/20220826174353.2.Iab6e5ea57963d6deca5311b27fb7226790d44406@changeid
Cc: stable@vger.kernel.org
Fixes: 4282d60689d4f ("tracefs: Add new tracefs file system")
Signed-off-by: Brian Norris <briannorris@chromium.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/tracefs/inode.c

index b56d1cfe429e95a118a38756e268a78cbb2ea32e..dd1ad084d24250ed7383e4b9d77c4470372da454 100644 (file)
@@ -142,6 +142,8 @@ struct tracefs_mount_opts {
        kuid_t uid;
        kgid_t gid;
        umode_t mode;
+       /* Opt_* bitfield. */
+       unsigned int opts;
 };
 
 enum {
@@ -242,6 +244,7 @@ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
        kgid_t gid;
        char *p;
 
+       opts->opts = 0;
        opts->mode = TRACEFS_DEFAULT_MODE;
 
        while ((p = strsep(&data, ",")) != NULL) {
@@ -276,24 +279,36 @@ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
                 * but traditionally tracefs has ignored all mount options
                 */
                }
+
+               opts->opts |= BIT(token);
        }
 
        return 0;
 }
 
-static int tracefs_apply_options(struct super_block *sb)
+static int tracefs_apply_options(struct super_block *sb, bool remount)
 {
        struct tracefs_fs_info *fsi = sb->s_fs_info;
        struct inode *inode = sb->s_root->d_inode;
        struct tracefs_mount_opts *opts = &fsi->mount_opts;
 
-       inode->i_mode &= ~S_IALLUGO;
-       inode->i_mode |= opts->mode;
+       /*
+        * On remount, only reset mode/uid/gid if they were provided as mount
+        * options.
+        */
+
+       if (!remount || opts->opts & BIT(Opt_mode)) {
+               inode->i_mode &= ~S_IALLUGO;
+               inode->i_mode |= opts->mode;
+       }
 
-       inode->i_uid = opts->uid;
+       if (!remount || opts->opts & BIT(Opt_uid))
+               inode->i_uid = opts->uid;
 
-       /* Set all the group ids to the mount option */
-       set_gid(sb->s_root, opts->gid);
+       if (!remount || opts->opts & BIT(Opt_gid)) {
+               /* Set all the group ids to the mount option */
+               set_gid(sb->s_root, opts->gid);
+       }
 
        return 0;
 }
@@ -308,7 +323,7 @@ static int tracefs_remount(struct super_block *sb, int *flags, char *data)
        if (err)
                goto fail;
 
-       tracefs_apply_options(sb);
+       tracefs_apply_options(sb, true);
 
 fail:
        return err;
@@ -362,7 +377,7 @@ static int trace_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_op = &tracefs_super_operations;
 
-       tracefs_apply_options(sb);
+       tracefs_apply_options(sb, false);
 
        return 0;