LCOV - code coverage report
Current view: top level - fs/configfs - symlink.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 134 0.0 %
Date: 2022-03-28 13:20:08 Functions: 0 7 0.0 %
Branches: 0 64 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /* -*- mode: c; c-basic-offset: 8; -*-
       3                 :            :  * vim: noexpandtab sw=8 ts=8 sts=0:
       4                 :            :  *
       5                 :            :  * symlink.c - operations for configfs symlinks.
       6                 :            :  *
       7                 :            :  * Based on sysfs:
       8                 :            :  *      sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
       9                 :            :  *
      10                 :            :  * configfs Copyright (C) 2005 Oracle.  All rights reserved.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include <linux/fs.h>
      14                 :            : #include <linux/module.h>
      15                 :            : #include <linux/namei.h>
      16                 :            : #include <linux/slab.h>
      17                 :            : 
      18                 :            : #include <linux/configfs.h>
      19                 :            : #include "configfs_internal.h"
      20                 :            : 
      21                 :            : /* Protects attachments of new symlinks */
      22                 :            : DEFINE_MUTEX(configfs_symlink_mutex);
      23                 :            : 
      24                 :          0 : static int item_depth(struct config_item * item)
      25                 :            : {
      26                 :          0 :         struct config_item * p = item;
      27                 :          0 :         int depth = 0;
      28   [ #  #  #  # ]:          0 :         do { depth++; } while ((p = p->ci_parent) && !configfs_is_root(p));
      29                 :          0 :         return depth;
      30                 :            : }
      31                 :            : 
      32                 :          0 : static int item_path_length(struct config_item * item)
      33                 :            : {
      34                 :          0 :         struct config_item * p = item;
      35                 :          0 :         int length = 1;
      36                 :          0 :         do {
      37         [ #  # ]:          0 :                 length += strlen(config_item_name(p)) + 1;
      38                 :          0 :                 p = p->ci_parent;
      39   [ #  #  #  # ]:          0 :         } while (p && !configfs_is_root(p));
      40                 :          0 :         return length;
      41                 :            : }
      42                 :            : 
      43                 :          0 : static void fill_item_path(struct config_item * item, char * buffer, int length)
      44                 :            : {
      45                 :          0 :         struct config_item * p;
      46                 :            : 
      47                 :          0 :         --length;
      48   [ #  #  #  # ]:          0 :         for (p = item; p && !configfs_is_root(p); p = p->ci_parent) {
      49                 :          0 :                 int cur = strlen(config_item_name(p));
      50                 :            : 
      51                 :            :                 /* back up enough to print this bus id with '/' */
      52                 :          0 :                 length -= cur;
      53                 :          0 :                 memcpy(buffer + length, config_item_name(p), cur);
      54                 :          0 :                 *(buffer + --length) = '/';
      55                 :            :         }
      56                 :          0 : }
      57                 :            : 
      58                 :          0 : static int configfs_get_target_path(struct config_item *item,
      59                 :            :                 struct config_item *target, char *path)
      60                 :            : {
      61                 :          0 :         int depth, size;
      62                 :          0 :         char *s;
      63                 :            : 
      64                 :          0 :         depth = item_depth(item);
      65                 :          0 :         size = item_path_length(target) + depth * 3 - 1;
      66         [ #  # ]:          0 :         if (size > PATH_MAX)
      67                 :            :                 return -ENAMETOOLONG;
      68                 :            : 
      69                 :            :         pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size);
      70                 :            : 
      71         [ #  # ]:          0 :         for (s = path; depth--; s += 3)
      72                 :          0 :                 strcpy(s,"../");
      73                 :            : 
      74                 :          0 :         fill_item_path(target, path, size);
      75                 :          0 :         pr_debug("%s: path = '%s'\n", __func__, path);
      76                 :          0 :         return 0;
      77                 :            : }
      78                 :            : 
      79                 :          0 : static int create_link(struct config_item *parent_item,
      80                 :            :                        struct config_item *item,
      81                 :            :                        struct dentry *dentry)
      82                 :            : {
      83                 :          0 :         struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata;
      84                 :          0 :         char *body;
      85                 :          0 :         int ret;
      86                 :            : 
      87         [ #  # ]:          0 :         if (!configfs_dirent_is_ready(target_sd))
      88                 :            :                 return -ENOENT;
      89                 :            : 
      90                 :          0 :         body = kzalloc(PAGE_SIZE, GFP_KERNEL);
      91         [ #  # ]:          0 :         if (!body)
      92                 :            :                 return -ENOMEM;
      93                 :            : 
      94                 :          0 :         configfs_get(target_sd);
      95                 :          0 :         spin_lock(&configfs_dirent_lock);
      96         [ #  # ]:          0 :         if (target_sd->s_type & CONFIGFS_USET_DROPPING) {
      97                 :          0 :                 spin_unlock(&configfs_dirent_lock);
      98                 :          0 :                 configfs_put(target_sd);
      99                 :          0 :                 kfree(body);
     100                 :          0 :                 return -ENOENT;
     101                 :            :         }
     102                 :          0 :         target_sd->s_links++;
     103                 :          0 :         spin_unlock(&configfs_dirent_lock);
     104                 :          0 :         ret = configfs_get_target_path(parent_item, item, body);
     105         [ #  # ]:          0 :         if (!ret)
     106                 :          0 :                 ret = configfs_create_link(target_sd, parent_item->ci_dentry,
     107                 :            :                                            dentry, body);
     108         [ #  # ]:          0 :         if (ret) {
     109                 :          0 :                 spin_lock(&configfs_dirent_lock);
     110                 :          0 :                 target_sd->s_links--;
     111                 :          0 :                 spin_unlock(&configfs_dirent_lock);
     112                 :          0 :                 configfs_put(target_sd);
     113                 :          0 :                 kfree(body);
     114                 :            :         }
     115                 :            :         return ret;
     116                 :            : }
     117                 :            : 
     118                 :            : 
     119                 :          0 : static int get_target(const char *symname, struct path *path,
     120                 :            :                       struct config_item **target, struct super_block *sb)
     121                 :            : {
     122                 :          0 :         int ret;
     123                 :            : 
     124                 :          0 :         ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
     125         [ #  # ]:          0 :         if (!ret) {
     126         [ #  # ]:          0 :                 if (path->dentry->d_sb == sb) {
     127                 :          0 :                         *target = configfs_get_config_item(path->dentry);
     128         [ #  # ]:          0 :                         if (!*target) {
     129                 :          0 :                                 ret = -ENOENT;
     130                 :          0 :                                 path_put(path);
     131                 :            :                         }
     132                 :            :                 } else {
     133                 :          0 :                         ret = -EPERM;
     134                 :          0 :                         path_put(path);
     135                 :            :                 }
     136                 :            :         }
     137                 :            : 
     138                 :          0 :         return ret;
     139                 :            : }
     140                 :            : 
     141                 :            : 
     142                 :          0 : int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
     143                 :            : {
     144                 :          0 :         int ret;
     145                 :          0 :         struct path path;
     146                 :          0 :         struct configfs_dirent *sd;
     147                 :          0 :         struct config_item *parent_item;
     148                 :          0 :         struct config_item *target_item = NULL;
     149                 :          0 :         const struct config_item_type *type;
     150                 :            : 
     151                 :          0 :         sd = dentry->d_parent->d_fsdata;
     152                 :            :         /*
     153                 :            :          * Fake invisibility if dir belongs to a group/default groups hierarchy
     154                 :            :          * being attached
     155                 :            :          */
     156         [ #  # ]:          0 :         if (!configfs_dirent_is_ready(sd))
     157                 :            :                 return -ENOENT;
     158                 :            : 
     159                 :          0 :         parent_item = configfs_get_config_item(dentry->d_parent);
     160                 :          0 :         type = parent_item->ci_type;
     161                 :            : 
     162                 :          0 :         ret = -EPERM;
     163   [ #  #  #  # ]:          0 :         if (!type || !type->ct_item_ops ||
     164         [ #  # ]:          0 :             !type->ct_item_ops->allow_link)
     165                 :          0 :                 goto out_put;
     166                 :            : 
     167                 :            :         /*
     168                 :            :          * This is really sick.  What they wanted was a hybrid of
     169                 :            :          * link(2) and symlink(2) - they wanted the target resolved
     170                 :            :          * at syscall time (as link(2) would've done), be a directory
     171                 :            :          * (which link(2) would've refused to do) *AND* be a deep
     172                 :            :          * fucking magic, making the target busy from rmdir POV.
     173                 :            :          * symlink(2) is nothing of that sort, and the locking it
     174                 :            :          * gets matches the normal symlink(2) semantics.  Without
     175                 :            :          * attempts to resolve the target (which might very well
     176                 :            :          * not even exist yet) done prior to locking the parent
     177                 :            :          * directory.  This perversion, OTOH, needs to resolve
     178                 :            :          * the target, which would lead to obvious deadlocks if
     179                 :            :          * attempted with any directories locked.
     180                 :            :          *
     181                 :            :          * Unfortunately, that garbage is userland ABI and we should've
     182                 :            :          * said "no" back in 2005.  Too late now, so we get to
     183                 :            :          * play very ugly games with locking.
     184                 :            :          *
     185                 :            :          * Try *ANYTHING* of that sort in new code, and you will
     186                 :            :          * really regret it.  Just ask yourself - what could a BOFH
     187                 :            :          * do to me and do I want to find it out first-hand?
     188                 :            :          *
     189                 :            :          *  AV, a thoroughly annoyed bastard.
     190                 :            :          */
     191                 :          0 :         inode_unlock(dir);
     192                 :          0 :         ret = get_target(symname, &path, &target_item, dentry->d_sb);
     193                 :          0 :         inode_lock(dir);
     194         [ #  # ]:          0 :         if (ret)
     195                 :          0 :                 goto out_put;
     196                 :            : 
     197   [ #  #  #  # ]:          0 :         if (dentry->d_inode || d_unhashed(dentry))
     198                 :            :                 ret = -EEXIST;
     199                 :            :         else
     200                 :          0 :                 ret = inode_permission(dir, MAY_WRITE | MAY_EXEC);
     201         [ #  # ]:          0 :         if (!ret)
     202                 :          0 :                 ret = type->ct_item_ops->allow_link(parent_item, target_item);
     203         [ #  # ]:          0 :         if (!ret) {
     204                 :          0 :                 mutex_lock(&configfs_symlink_mutex);
     205                 :          0 :                 ret = create_link(parent_item, target_item, dentry);
     206                 :          0 :                 mutex_unlock(&configfs_symlink_mutex);
     207   [ #  #  #  # ]:          0 :                 if (ret && type->ct_item_ops->drop_link)
     208                 :          0 :                         type->ct_item_ops->drop_link(parent_item,
     209                 :            :                                                      target_item);
     210                 :            :         }
     211                 :            : 
     212                 :          0 :         config_item_put(target_item);
     213                 :          0 :         path_put(&path);
     214                 :            : 
     215                 :          0 : out_put:
     216                 :          0 :         config_item_put(parent_item);
     217                 :          0 :         return ret;
     218                 :            : }
     219                 :            : 
     220                 :          0 : int configfs_unlink(struct inode *dir, struct dentry *dentry)
     221                 :            : {
     222                 :          0 :         struct configfs_dirent *sd = dentry->d_fsdata, *target_sd;
     223                 :          0 :         struct config_item *parent_item;
     224                 :          0 :         const struct config_item_type *type;
     225                 :          0 :         int ret;
     226                 :            : 
     227                 :          0 :         ret = -EPERM;  /* What lack-of-symlink returns */
     228         [ #  # ]:          0 :         if (!(sd->s_type & CONFIGFS_ITEM_LINK))
     229                 :          0 :                 goto out;
     230                 :            : 
     231                 :          0 :         target_sd = sd->s_element;
     232                 :            : 
     233                 :          0 :         parent_item = configfs_get_config_item(dentry->d_parent);
     234                 :          0 :         type = parent_item->ci_type;
     235                 :            : 
     236                 :          0 :         spin_lock(&configfs_dirent_lock);
     237                 :          0 :         list_del_init(&sd->s_sibling);
     238                 :          0 :         spin_unlock(&configfs_dirent_lock);
     239                 :          0 :         configfs_drop_dentry(sd, dentry->d_parent);
     240                 :          0 :         dput(dentry);
     241                 :          0 :         configfs_put(sd);
     242                 :            : 
     243                 :            :         /*
     244                 :            :          * drop_link() must be called before
     245                 :            :          * decrementing target's ->s_links, so that the order of
     246                 :            :          * drop_link(this, target) and drop_item(target) is preserved.
     247                 :            :          */
     248   [ #  #  #  # ]:          0 :         if (type && type->ct_item_ops &&
     249         [ #  # ]:          0 :             type->ct_item_ops->drop_link)
     250                 :          0 :                 type->ct_item_ops->drop_link(parent_item,
     251                 :          0 :                                                target_sd->s_element);
     252                 :            : 
     253                 :          0 :         spin_lock(&configfs_dirent_lock);
     254                 :          0 :         target_sd->s_links--;
     255                 :          0 :         spin_unlock(&configfs_dirent_lock);
     256                 :          0 :         configfs_put(target_sd);
     257                 :            : 
     258                 :          0 :         config_item_put(parent_item);
     259                 :            : 
     260                 :          0 :         ret = 0;
     261                 :            : 
     262                 :          0 : out:
     263                 :          0 :         return ret;
     264                 :            : }
     265                 :            : 
     266                 :            : const struct inode_operations configfs_symlink_inode_operations = {
     267                 :            :         .get_link = simple_get_link,
     268                 :            :         .setattr = configfs_setattr,
     269                 :            : };
     270                 :            : 

Generated by: LCOV version 1.14