Skip to content

Commit baa23a8

Browse files
committed
tracefs: Reset permissions on remount if permissions are options
There's an inconsistency with the way permissions are handled in tracefs. Because the permissions are generated when accessed, they default to the root inode's permission if they were never set by the user. If the user sets the permissions, then a flag is set and the permissions are saved via the inode (for tracefs files) or an internal attribute field (for eventfs). But if a remount happens that specify the permissions, all the files that were not changed by the user gets updated, but the ones that were are not. If the user were to remount the file system with a given permission, then all files and directories within that file system should be updated. This can cause security issues if a file's permission was updated but the admin forgot about it. They could incorrectly think that remounting with permissions set would update all files, but miss some. For example: # cd /sys/kernel/tracing # chgrp 1002 current_tracer # ls -l [..] -rw-r----- 1 root root 0 May 1 21:25 buffer_size_kb -rw-r----- 1 root root 0 May 1 21:25 buffer_subbuf_size_kb -r--r----- 1 root root 0 May 1 21:25 buffer_total_size_kb -rw-r----- 1 root lkp 0 May 1 21:25 current_tracer -rw-r----- 1 root root 0 May 1 21:25 dynamic_events -r--r----- 1 root root 0 May 1 21:25 dyn_ftrace_total_info -r--r----- 1 root root 0 May 1 21:25 enabled_functions Where current_tracer now has group "lkp". # mount -o remount,gid=1001 . # ls -l -rw-r----- 1 root tracing 0 May 1 21:25 buffer_size_kb -rw-r----- 1 root tracing 0 May 1 21:25 buffer_subbuf_size_kb -r--r----- 1 root tracing 0 May 1 21:25 buffer_total_size_kb -rw-r----- 1 root lkp 0 May 1 21:25 current_tracer -rw-r----- 1 root tracing 0 May 1 21:25 dynamic_events -r--r----- 1 root tracing 0 May 1 21:25 dyn_ftrace_total_info -r--r----- 1 root tracing 0 May 1 21:25 enabled_functions Everything changed but the "current_tracer". Add a new link list that keeps track of all the tracefs_inodes which has the permission flags that tell if the file/dir should use the root inode's permission or not. Then on remount, clear all the flags so that the default behavior of using the root inode's permission is done for all files and directories. Link: https://lore.kernel.org/linux-trace-kernel/[email protected] Cc: [email protected] Cc: Masami Hiramatsu <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Cc: Andrew Morton <[email protected]> Fixes: 8186fff ("tracefs/eventfs: Use root and instance inodes as default ownership") Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent ee4e037 commit baa23a8

File tree

3 files changed

+99
-2
lines changed

3 files changed

+99
-2
lines changed

fs/tracefs/event_inode.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,35 @@ static const struct file_operations eventfs_file_operations = {
308308
.llseek = generic_file_llseek,
309309
};
310310

311+
/*
312+
* On a remount of tracefs, if UID or GID options are set, then
313+
* the mount point inode permissions should be used.
314+
* Reset the saved permission flags appropriately.
315+
*/
316+
void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool update_gid)
317+
{
318+
struct eventfs_inode *ei = ti->private;
319+
320+
if (!ei)
321+
return;
322+
323+
if (update_uid)
324+
ei->attr.mode &= ~EVENTFS_SAVE_UID;
325+
326+
if (update_gid)
327+
ei->attr.mode &= ~EVENTFS_SAVE_GID;
328+
329+
if (!ei->entry_attrs)
330+
return;
331+
332+
for (int i = 0; i < ei->nr_entries; i++) {
333+
if (update_uid)
334+
ei->entry_attrs[i].mode &= ~EVENTFS_SAVE_UID;
335+
if (update_gid)
336+
ei->entry_attrs[i].mode &= ~EVENTFS_SAVE_GID;
337+
}
338+
}
339+
311340
/* Return the evenfs_inode of the "events" directory */
312341
static struct eventfs_inode *eventfs_find_events(struct dentry *dentry)
313342
{

fs/tracefs/inode.c

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,47 @@ static struct vfsmount *tracefs_mount;
3030
static int tracefs_mount_count;
3131
static bool tracefs_registered;
3232

33+
/*
34+
* Keep track of all tracefs_inodes in order to update their
35+
* flags if necessary on a remount.
36+
*/
37+
static DEFINE_SPINLOCK(tracefs_inode_lock);
38+
static LIST_HEAD(tracefs_inodes);
39+
3340
static struct inode *tracefs_alloc_inode(struct super_block *sb)
3441
{
3542
struct tracefs_inode *ti;
43+
unsigned long flags;
3644

3745
ti = kmem_cache_alloc(tracefs_inode_cachep, GFP_KERNEL);
3846
if (!ti)
3947
return NULL;
4048

49+
spin_lock_irqsave(&tracefs_inode_lock, flags);
50+
list_add_rcu(&ti->list, &tracefs_inodes);
51+
spin_unlock_irqrestore(&tracefs_inode_lock, flags);
52+
4153
return &ti->vfs_inode;
4254
}
4355

56+
static void tracefs_free_inode_rcu(struct rcu_head *rcu)
57+
{
58+
struct tracefs_inode *ti;
59+
60+
ti = container_of(rcu, struct tracefs_inode, rcu);
61+
kmem_cache_free(tracefs_inode_cachep, ti);
62+
}
63+
4464
static void tracefs_free_inode(struct inode *inode)
4565
{
46-
kmem_cache_free(tracefs_inode_cachep, get_tracefs(inode));
66+
struct tracefs_inode *ti = get_tracefs(inode);
67+
unsigned long flags;
68+
69+
spin_lock_irqsave(&tracefs_inode_lock, flags);
70+
list_del_rcu(&ti->list);
71+
spin_unlock_irqrestore(&tracefs_inode_lock, flags);
72+
73+
call_rcu(&ti->rcu, tracefs_free_inode_rcu);
4774
}
4875

4976
static ssize_t default_read_file(struct file *file, char __user *buf,
@@ -313,6 +340,8 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
313340
struct tracefs_fs_info *fsi = sb->s_fs_info;
314341
struct inode *inode = d_inode(sb->s_root);
315342
struct tracefs_mount_opts *opts = &fsi->mount_opts;
343+
struct tracefs_inode *ti;
344+
bool update_uid, update_gid;
316345
umode_t tmp_mode;
317346

318347
/*
@@ -332,6 +361,25 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
332361
if (!remount || opts->opts & BIT(Opt_gid))
333362
inode->i_gid = opts->gid;
334363

364+
if (remount && (opts->opts & BIT(Opt_uid) || opts->opts & BIT(Opt_gid))) {
365+
366+
update_uid = opts->opts & BIT(Opt_uid);
367+
update_gid = opts->opts & BIT(Opt_gid);
368+
369+
rcu_read_lock();
370+
list_for_each_entry_rcu(ti, &tracefs_inodes, list) {
371+
if (update_uid)
372+
ti->flags &= ~TRACEFS_UID_PERM_SET;
373+
374+
if (update_gid)
375+
ti->flags &= ~TRACEFS_GID_PERM_SET;
376+
377+
if (ti->flags & TRACEFS_EVENT_INODE)
378+
eventfs_remount(ti, update_uid, update_gid);
379+
}
380+
rcu_read_unlock();
381+
}
382+
335383
return 0;
336384
}
337385

@@ -398,7 +446,22 @@ static int tracefs_d_revalidate(struct dentry *dentry, unsigned int flags)
398446
return !(ei && ei->is_freed);
399447
}
400448

449+
static void tracefs_d_iput(struct dentry *dentry, struct inode *inode)
450+
{
451+
struct tracefs_inode *ti = get_tracefs(inode);
452+
453+
/*
454+
* This inode is being freed and cannot be used for
455+
* eventfs. Clear the flag so that it doesn't call into
456+
* eventfs during the remount flag updates. The eventfs_inode
457+
* gets freed after an RCU cycle, so the content will still
458+
* be safe if the iteration is going on now.
459+
*/
460+
ti->flags &= ~TRACEFS_EVENT_INODE;
461+
}
462+
401463
static const struct dentry_operations tracefs_dentry_operations = {
464+
.d_iput = tracefs_d_iput,
402465
.d_revalidate = tracefs_d_revalidate,
403466
.d_release = tracefs_d_release,
404467
};

fs/tracefs/internal.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ enum {
1111
};
1212

1313
struct tracefs_inode {
14-
struct inode vfs_inode;
14+
union {
15+
struct inode vfs_inode;
16+
struct rcu_head rcu;
17+
};
1518
/* The below gets initialized with memset_after(ti, 0, vfs_inode) */
19+
struct list_head list;
1620
unsigned long flags;
1721
void *private;
1822
};
@@ -73,6 +77,7 @@ struct dentry *tracefs_end_creating(struct dentry *dentry);
7377
struct dentry *tracefs_failed_creating(struct dentry *dentry);
7478
struct inode *tracefs_get_inode(struct super_block *sb);
7579

80+
void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool update_gid);
7681
void eventfs_d_release(struct dentry *dentry);
7782

7883
#endif /* _TRACEFS_INTERNAL_H */

0 commit comments

Comments
 (0)