LCOV - code coverage report
Current view: top level - fs/tracefs - inode.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 107 211 50.7 %
Date: 2021-04-22 12:43:58 Functions: 12 22 54.5 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  *  inode.c - part of tracefs, a pseudo file system for activating tracing
       4             :  *
       5             :  * Based on debugfs by: Greg Kroah-Hartman <greg@kroah.com>
       6             :  *
       7             :  *  Copyright (C) 2014 Red Hat Inc, author: Steven Rostedt <srostedt@redhat.com>
       8             :  *
       9             :  * tracefs is the file system that is used by the tracing infrastructure.
      10             :  */
      11             : 
      12             : #include <linux/module.h>
      13             : #include <linux/fs.h>
      14             : #include <linux/mount.h>
      15             : #include <linux/kobject.h>
      16             : #include <linux/namei.h>
      17             : #include <linux/tracefs.h>
      18             : #include <linux/fsnotify.h>
      19             : #include <linux/security.h>
      20             : #include <linux/seq_file.h>
      21             : #include <linux/parser.h>
      22             : #include <linux/magic.h>
      23             : #include <linux/slab.h>
      24             : 
      25             : #define TRACEFS_DEFAULT_MODE    0700
      26             : 
      27             : static struct vfsmount *tracefs_mount;
      28             : static int tracefs_mount_count;
      29             : static bool tracefs_registered;
      30             : 
      31           0 : static ssize_t default_read_file(struct file *file, char __user *buf,
      32             :                                  size_t count, loff_t *ppos)
      33             : {
      34           0 :         return 0;
      35             : }
      36             : 
      37           0 : static ssize_t default_write_file(struct file *file, const char __user *buf,
      38             :                                    size_t count, loff_t *ppos)
      39             : {
      40           0 :         return count;
      41             : }
      42             : 
      43             : static const struct file_operations tracefs_file_operations = {
      44             :         .read =         default_read_file,
      45             :         .write =        default_write_file,
      46             :         .open =         simple_open,
      47             :         .llseek =       noop_llseek,
      48             : };
      49             : 
      50             : static struct tracefs_dir_ops {
      51             :         int (*mkdir)(const char *name);
      52             :         int (*rmdir)(const char *name);
      53             : } tracefs_ops __ro_after_init;
      54             : 
      55           0 : static char *get_dname(struct dentry *dentry)
      56             : {
      57           0 :         const char *dname;
      58           0 :         char *name;
      59           0 :         int len = dentry->d_name.len;
      60             : 
      61           0 :         dname = dentry->d_name.name;
      62           0 :         name = kmalloc(len + 1, GFP_KERNEL);
      63           0 :         if (!name)
      64             :                 return NULL;
      65           0 :         memcpy(name, dname, len);
      66           0 :         name[len] = 0;
      67           0 :         return name;
      68             : }
      69             : 
      70           0 : static int tracefs_syscall_mkdir(struct user_namespace *mnt_userns,
      71             :                                  struct inode *inode, struct dentry *dentry,
      72             :                                  umode_t mode)
      73             : {
      74           0 :         char *name;
      75           0 :         int ret;
      76             : 
      77           0 :         name = get_dname(dentry);
      78           0 :         if (!name)
      79             :                 return -ENOMEM;
      80             : 
      81             :         /*
      82             :          * The mkdir call can call the generic functions that create
      83             :          * the files within the tracefs system. It is up to the individual
      84             :          * mkdir routine to handle races.
      85             :          */
      86           0 :         inode_unlock(inode);
      87           0 :         ret = tracefs_ops.mkdir(name);
      88           0 :         inode_lock(inode);
      89             : 
      90           0 :         kfree(name);
      91             : 
      92           0 :         return ret;
      93             : }
      94             : 
      95           0 : static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)
      96             : {
      97           0 :         char *name;
      98           0 :         int ret;
      99             : 
     100           0 :         name = get_dname(dentry);
     101           0 :         if (!name)
     102             :                 return -ENOMEM;
     103             : 
     104             :         /*
     105             :          * The rmdir call can call the generic functions that create
     106             :          * the files within the tracefs system. It is up to the individual
     107             :          * rmdir routine to handle races.
     108             :          * This time we need to unlock not only the parent (inode) but
     109             :          * also the directory that is being deleted.
     110             :          */
     111           0 :         inode_unlock(inode);
     112           0 :         inode_unlock(dentry->d_inode);
     113             : 
     114           0 :         ret = tracefs_ops.rmdir(name);
     115             : 
     116           0 :         inode_lock_nested(inode, I_MUTEX_PARENT);
     117           0 :         inode_lock(dentry->d_inode);
     118             : 
     119           0 :         kfree(name);
     120             : 
     121           0 :         return ret;
     122             : }
     123             : 
     124             : static const struct inode_operations tracefs_dir_inode_operations = {
     125             :         .lookup         = simple_lookup,
     126             :         .mkdir          = tracefs_syscall_mkdir,
     127             :         .rmdir          = tracefs_syscall_rmdir,
     128             : };
     129             : 
     130        3450 : static struct inode *tracefs_get_inode(struct super_block *sb)
     131             : {
     132        3450 :         struct inode *inode = new_inode(sb);
     133        3450 :         if (inode) {
     134        3450 :                 inode->i_ino = get_next_ino();
     135        3450 :                 inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
     136             :         }
     137        3450 :         return inode;
     138             : }
     139             : 
     140             : struct tracefs_mount_opts {
     141             :         kuid_t uid;
     142             :         kgid_t gid;
     143             :         umode_t mode;
     144             : };
     145             : 
     146             : enum {
     147             :         Opt_uid,
     148             :         Opt_gid,
     149             :         Opt_mode,
     150             :         Opt_err
     151             : };
     152             : 
     153             : static const match_table_t tokens = {
     154             :         {Opt_uid, "uid=%u"},
     155             :         {Opt_gid, "gid=%u"},
     156             :         {Opt_mode, "mode=%o"},
     157             :         {Opt_err, NULL}
     158             : };
     159             : 
     160             : struct tracefs_fs_info {
     161             :         struct tracefs_mount_opts mount_opts;
     162             : };
     163             : 
     164           1 : static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
     165             : {
     166           1 :         substring_t args[MAX_OPT_ARGS];
     167           1 :         int option;
     168           1 :         int token;
     169           1 :         kuid_t uid;
     170           1 :         kgid_t gid;
     171           1 :         char *p;
     172             : 
     173           1 :         opts->mode = TRACEFS_DEFAULT_MODE;
     174             : 
     175           1 :         while ((p = strsep(&data, ",")) != NULL) {
     176           0 :                 if (!*p)
     177           0 :                         continue;
     178             : 
     179           0 :                 token = match_token(p, tokens, args);
     180           0 :                 switch (token) {
     181           0 :                 case Opt_uid:
     182           0 :                         if (match_int(&args[0], &option))
     183             :                                 return -EINVAL;
     184           0 :                         uid = make_kuid(current_user_ns(), option);
     185           0 :                         if (!uid_valid(uid))
     186             :                                 return -EINVAL;
     187           0 :                         opts->uid = uid;
     188           0 :                         break;
     189           0 :                 case Opt_gid:
     190           0 :                         if (match_int(&args[0], &option))
     191             :                                 return -EINVAL;
     192           0 :                         gid = make_kgid(current_user_ns(), option);
     193           0 :                         if (!gid_valid(gid))
     194             :                                 return -EINVAL;
     195           0 :                         opts->gid = gid;
     196           0 :                         break;
     197           0 :                 case Opt_mode:
     198           0 :                         if (match_octal(&args[0], &option))
     199             :                                 return -EINVAL;
     200           0 :                         opts->mode = option & S_IALLUGO;
     201           0 :                         break;
     202             :                 /*
     203             :                  * We might like to report bad mount options here;
     204             :                  * but traditionally tracefs has ignored all mount options
     205             :                  */
     206             :                 }
     207             :         }
     208             : 
     209             :         return 0;
     210             : }
     211             : 
     212           1 : static int tracefs_apply_options(struct super_block *sb)
     213             : {
     214           1 :         struct tracefs_fs_info *fsi = sb->s_fs_info;
     215           1 :         struct inode *inode = sb->s_root->d_inode;
     216           1 :         struct tracefs_mount_opts *opts = &fsi->mount_opts;
     217             : 
     218           1 :         inode->i_mode &= ~S_IALLUGO;
     219           1 :         inode->i_mode |= opts->mode;
     220             : 
     221           1 :         inode->i_uid = opts->uid;
     222           1 :         inode->i_gid = opts->gid;
     223             : 
     224           1 :         return 0;
     225             : }
     226             : 
     227           0 : static int tracefs_remount(struct super_block *sb, int *flags, char *data)
     228             : {
     229           0 :         int err;
     230           0 :         struct tracefs_fs_info *fsi = sb->s_fs_info;
     231             : 
     232           0 :         sync_filesystem(sb);
     233           0 :         err = tracefs_parse_options(data, &fsi->mount_opts);
     234           0 :         if (err)
     235           0 :                 goto fail;
     236             : 
     237           0 :         tracefs_apply_options(sb);
     238             : 
     239           0 : fail:
     240           0 :         return err;
     241             : }
     242             : 
     243           0 : static int tracefs_show_options(struct seq_file *m, struct dentry *root)
     244             : {
     245           0 :         struct tracefs_fs_info *fsi = root->d_sb->s_fs_info;
     246           0 :         struct tracefs_mount_opts *opts = &fsi->mount_opts;
     247             : 
     248           0 :         if (!uid_eq(opts->uid, GLOBAL_ROOT_UID))
     249           0 :                 seq_printf(m, ",uid=%u",
     250             :                            from_kuid_munged(&init_user_ns, opts->uid));
     251           0 :         if (!gid_eq(opts->gid, GLOBAL_ROOT_GID))
     252           0 :                 seq_printf(m, ",gid=%u",
     253             :                            from_kgid_munged(&init_user_ns, opts->gid));
     254           0 :         if (opts->mode != TRACEFS_DEFAULT_MODE)
     255           0 :                 seq_printf(m, ",mode=%o", opts->mode);
     256             : 
     257           0 :         return 0;
     258             : }
     259             : 
     260             : static const struct super_operations tracefs_super_operations = {
     261             :         .statfs         = simple_statfs,
     262             :         .remount_fs     = tracefs_remount,
     263             :         .show_options   = tracefs_show_options,
     264             : };
     265             : 
     266           1 : static int trace_fill_super(struct super_block *sb, void *data, int silent)
     267             : {
     268           1 :         static const struct tree_descr trace_files[] = {{""}};
     269           1 :         struct tracefs_fs_info *fsi;
     270           1 :         int err;
     271             : 
     272           1 :         fsi = kzalloc(sizeof(struct tracefs_fs_info), GFP_KERNEL);
     273           1 :         sb->s_fs_info = fsi;
     274           1 :         if (!fsi) {
     275           0 :                 err = -ENOMEM;
     276           0 :                 goto fail;
     277             :         }
     278             : 
     279           1 :         err = tracefs_parse_options(data, &fsi->mount_opts);
     280           1 :         if (err)
     281           0 :                 goto fail;
     282             : 
     283           1 :         err  =  simple_fill_super(sb, TRACEFS_MAGIC, trace_files);
     284           1 :         if (err)
     285           0 :                 goto fail;
     286             : 
     287           1 :         sb->s_op = &tracefs_super_operations;
     288             : 
     289           1 :         tracefs_apply_options(sb);
     290             : 
     291           1 :         return 0;
     292             : 
     293           0 : fail:
     294           0 :         kfree(fsi);
     295           0 :         sb->s_fs_info = NULL;
     296           0 :         return err;
     297             : }
     298             : 
     299           1 : static struct dentry *trace_mount(struct file_system_type *fs_type,
     300             :                         int flags, const char *dev_name,
     301             :                         void *data)
     302             : {
     303           1 :         return mount_single(fs_type, flags, data, trace_fill_super);
     304             : }
     305             : 
     306             : static struct file_system_type trace_fs_type = {
     307             :         .owner =        THIS_MODULE,
     308             :         .name =         "tracefs",
     309             :         .mount =        trace_mount,
     310             :         .kill_sb =      kill_litter_super,
     311             : };
     312             : MODULE_ALIAS_FS("tracefs");
     313             : 
     314        3450 : static struct dentry *start_creating(const char *name, struct dentry *parent)
     315             : {
     316        3450 :         struct dentry *dentry;
     317        3450 :         int error;
     318             : 
     319        3450 :         pr_debug("tracefs: creating file '%s'\n",name);
     320             : 
     321        3450 :         error = simple_pin_fs(&trace_fs_type, &tracefs_mount,
     322             :                               &tracefs_mount_count);
     323        3450 :         if (error)
     324           0 :                 return ERR_PTR(error);
     325             : 
     326             :         /* If the parent is not specified, we create it in the root.
     327             :          * We need the root dentry to do this, which is in the super
     328             :          * block. A pointer to that is in the struct vfsmount that we
     329             :          * have around.
     330             :          */
     331        3450 :         if (!parent)
     332          30 :                 parent = tracefs_mount->mnt_root;
     333             : 
     334        3450 :         inode_lock(parent->d_inode);
     335        3450 :         if (unlikely(IS_DEADDIR(parent->d_inode)))
     336        3450 :                 dentry = ERR_PTR(-ENOENT);
     337             :         else
     338        3450 :                 dentry = lookup_one_len(name, parent, strlen(name));
     339        3450 :         if (!IS_ERR(dentry) && dentry->d_inode) {
     340           0 :                 dput(dentry);
     341           0 :                 dentry = ERR_PTR(-EEXIST);
     342             :         }
     343             : 
     344        3450 :         if (IS_ERR(dentry)) {
     345           0 :                 inode_unlock(parent->d_inode);
     346           0 :                 simple_release_fs(&tracefs_mount, &tracefs_mount_count);
     347             :         }
     348             : 
     349             :         return dentry;
     350             : }
     351             : 
     352           0 : static struct dentry *failed_creating(struct dentry *dentry)
     353             : {
     354           0 :         inode_unlock(dentry->d_parent->d_inode);
     355           0 :         dput(dentry);
     356           0 :         simple_release_fs(&tracefs_mount, &tracefs_mount_count);
     357           0 :         return NULL;
     358             : }
     359             : 
     360        3450 : static struct dentry *end_creating(struct dentry *dentry)
     361             : {
     362        3450 :         inode_unlock(dentry->d_parent->d_inode);
     363        3450 :         return dentry;
     364             : }
     365             : 
     366             : /**
     367             :  * tracefs_create_file - create a file in the tracefs filesystem
     368             :  * @name: a pointer to a string containing the name of the file to create.
     369             :  * @mode: the permission that the file should have.
     370             :  * @parent: a pointer to the parent dentry for this file.  This should be a
     371             :  *          directory dentry if set.  If this parameter is NULL, then the
     372             :  *          file will be created in the root of the tracefs filesystem.
     373             :  * @data: a pointer to something that the caller will want to get to later
     374             :  *        on.  The inode.i_private pointer will point to this value on
     375             :  *        the open() call.
     376             :  * @fops: a pointer to a struct file_operations that should be used for
     377             :  *        this file.
     378             :  *
     379             :  * This is the basic "create a file" function for tracefs.  It allows for a
     380             :  * wide range of flexibility in creating a file, or a directory (if you want
     381             :  * to create a directory, the tracefs_create_dir() function is
     382             :  * recommended to be used instead.)
     383             :  *
     384             :  * This function will return a pointer to a dentry if it succeeds.  This
     385             :  * pointer must be passed to the tracefs_remove() function when the file is
     386             :  * to be removed (no automatic cleanup happens if your module is unloaded,
     387             :  * you are responsible here.)  If an error occurs, %NULL will be returned.
     388             :  *
     389             :  * If tracefs is not enabled in the kernel, the value -%ENODEV will be
     390             :  * returned.
     391             :  */
     392        2842 : struct dentry *tracefs_create_file(const char *name, umode_t mode,
     393             :                                    struct dentry *parent, void *data,
     394             :                                    const struct file_operations *fops)
     395             : {
     396        2842 :         struct dentry *dentry;
     397        2842 :         struct inode *inode;
     398             : 
     399        2842 :         if (security_locked_down(LOCKDOWN_TRACEFS))
     400             :                 return NULL;
     401             : 
     402        2842 :         if (!(mode & S_IFMT))
     403        2842 :                 mode |= S_IFREG;
     404        2842 :         BUG_ON(!S_ISREG(mode));
     405        2842 :         dentry = start_creating(name, parent);
     406             : 
     407        2842 :         if (IS_ERR(dentry))
     408             :                 return NULL;
     409             : 
     410        2842 :         inode = tracefs_get_inode(dentry->d_sb);
     411        2842 :         if (unlikely(!inode))
     412           0 :                 return failed_creating(dentry);
     413             : 
     414        2842 :         inode->i_mode = mode;
     415        2842 :         inode->i_fop = fops ? fops : &tracefs_file_operations;
     416        2842 :         inode->i_private = data;
     417        2842 :         d_instantiate(dentry, inode);
     418        2842 :         fsnotify_create(dentry->d_parent->d_inode, dentry);
     419        2842 :         return end_creating(dentry);
     420             : }
     421             : 
     422         608 : static struct dentry *__create_dir(const char *name, struct dentry *parent,
     423             :                                    const struct inode_operations *ops)
     424             : {
     425         608 :         struct dentry *dentry = start_creating(name, parent);
     426         608 :         struct inode *inode;
     427             : 
     428         608 :         if (IS_ERR(dentry))
     429             :                 return NULL;
     430             : 
     431         608 :         inode = tracefs_get_inode(dentry->d_sb);
     432         608 :         if (unlikely(!inode))
     433           0 :                 return failed_creating(dentry);
     434             : 
     435         608 :         inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
     436         608 :         inode->i_op = ops;
     437         608 :         inode->i_fop = &simple_dir_operations;
     438             : 
     439             :         /* directory inodes start off with i_nlink == 2 (for "." entry) */
     440         608 :         inc_nlink(inode);
     441         608 :         d_instantiate(dentry, inode);
     442         608 :         inc_nlink(dentry->d_parent->d_inode);
     443         608 :         fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
     444         608 :         return end_creating(dentry);
     445             : }
     446             : 
     447             : /**
     448             :  * tracefs_create_dir - create a directory in the tracefs filesystem
     449             :  * @name: a pointer to a string containing the name of the directory to
     450             :  *        create.
     451             :  * @parent: a pointer to the parent dentry for this file.  This should be a
     452             :  *          directory dentry if set.  If this parameter is NULL, then the
     453             :  *          directory will be created in the root of the tracefs filesystem.
     454             :  *
     455             :  * This function creates a directory in tracefs with the given name.
     456             :  *
     457             :  * This function will return a pointer to a dentry if it succeeds.  This
     458             :  * pointer must be passed to the tracefs_remove() function when the file is
     459             :  * to be removed. If an error occurs, %NULL will be returned.
     460             :  *
     461             :  * If tracing is not enabled in the kernel, the value -%ENODEV will be
     462             :  * returned.
     463             :  */
     464         607 : struct dentry *tracefs_create_dir(const char *name, struct dentry *parent)
     465             : {
     466         607 :         return __create_dir(name, parent, &simple_dir_inode_operations);
     467             : }
     468             : 
     469             : /**
     470             :  * tracefs_create_instance_dir - create the tracing instances directory
     471             :  * @name: The name of the instances directory to create
     472             :  * @parent: The parent directory that the instances directory will exist
     473             :  * @mkdir: The function to call when a mkdir is performed.
     474             :  * @rmdir: The function to call when a rmdir is performed.
     475             :  *
     476             :  * Only one instances directory is allowed.
     477             :  *
     478             :  * The instances directory is special as it allows for mkdir and rmdir to
     479             :  * to be done by userspace. When a mkdir or rmdir is performed, the inode
     480             :  * locks are released and the methhods passed in (@mkdir and @rmdir) are
     481             :  * called without locks and with the name of the directory being created
     482             :  * within the instances directory.
     483             :  *
     484             :  * Returns the dentry of the instances directory.
     485             :  */
     486           1 : __init struct dentry *tracefs_create_instance_dir(const char *name,
     487             :                                           struct dentry *parent,
     488             :                                           int (*mkdir)(const char *name),
     489             :                                           int (*rmdir)(const char *name))
     490             : {
     491           1 :         struct dentry *dentry;
     492             : 
     493             :         /* Only allow one instance of the instances directory. */
     494           2 :         if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir))
     495             :                 return NULL;
     496             : 
     497           1 :         dentry = __create_dir(name, parent, &tracefs_dir_inode_operations);
     498           1 :         if (!dentry)
     499             :                 return NULL;
     500             : 
     501           1 :         tracefs_ops.mkdir = mkdir;
     502           1 :         tracefs_ops.rmdir = rmdir;
     503             : 
     504           1 :         return dentry;
     505             : }
     506             : 
     507           0 : static void remove_one(struct dentry *victim)
     508             : {
     509           0 :         simple_release_fs(&tracefs_mount, &tracefs_mount_count);
     510           0 : }
     511             : 
     512             : /**
     513             :  * tracefs_remove - recursively removes a directory
     514             :  * @dentry: a pointer to a the dentry of the directory to be removed.
     515             :  *
     516             :  * This function recursively removes a directory tree in tracefs that
     517             :  * was previously created with a call to another tracefs function
     518             :  * (like tracefs_create_file() or variants thereof.)
     519             :  */
     520           0 : void tracefs_remove(struct dentry *dentry)
     521             : {
     522           0 :         if (IS_ERR_OR_NULL(dentry))
     523             :                 return;
     524             : 
     525           0 :         simple_pin_fs(&trace_fs_type, &tracefs_mount, &tracefs_mount_count);
     526           0 :         simple_recursive_removal(dentry, remove_one);
     527           0 :         simple_release_fs(&tracefs_mount, &tracefs_mount_count);
     528             : }
     529             : 
     530             : /**
     531             :  * tracefs_initialized - Tells whether tracefs has been registered
     532             :  */
     533           1 : bool tracefs_initialized(void)
     534             : {
     535           1 :         return tracefs_registered;
     536             : }
     537             : 
     538           1 : static int __init tracefs_init(void)
     539             : {
     540           1 :         int retval;
     541             : 
     542           1 :         retval = sysfs_create_mount_point(kernel_kobj, "tracing");
     543           1 :         if (retval)
     544             :                 return -EINVAL;
     545             : 
     546           1 :         retval = register_filesystem(&trace_fs_type);
     547           1 :         if (!retval)
     548           1 :                 tracefs_registered = true;
     549             : 
     550             :         return retval;
     551             : }
     552             : core_initcall(tracefs_init);

Generated by: LCOV version 1.14