The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/fhandle.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include <linux/syscalls.h>
    2 #include <linux/slab.h>
    3 #include <linux/fs.h>
    4 #include <linux/file.h>
    5 #include <linux/mount.h>
    6 #include <linux/namei.h>
    7 #include <linux/exportfs.h>
    8 #include <linux/fs_struct.h>
    9 #include <linux/fsnotify.h>
   10 #include <linux/personality.h>
   11 #include <asm/uaccess.h>
   12 #include "internal.h"
   13 #include "mount.h"
   14 
   15 static long do_sys_name_to_handle(struct path *path,
   16                                   struct file_handle __user *ufh,
   17                                   int __user *mnt_id)
   18 {
   19         long retval;
   20         struct file_handle f_handle;
   21         int handle_dwords, handle_bytes;
   22         struct file_handle *handle = NULL;
   23 
   24         /*
   25          * We need to make sure whether the file system
   26          * support decoding of the file handle
   27          */
   28         if (!path->dentry->d_sb->s_export_op ||
   29             !path->dentry->d_sb->s_export_op->fh_to_dentry)
   30                 return -EOPNOTSUPP;
   31 
   32         if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
   33                 return -EFAULT;
   34 
   35         if (f_handle.handle_bytes > MAX_HANDLE_SZ)
   36                 return -EINVAL;
   37 
   38         handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
   39                          GFP_KERNEL);
   40         if (!handle)
   41                 return -ENOMEM;
   42 
   43         /* convert handle size to multiple of sizeof(u32) */
   44         handle_dwords = f_handle.handle_bytes >> 2;
   45 
   46         /* we ask for a non connected handle */
   47         retval = exportfs_encode_fh(path->dentry,
   48                                     (struct fid *)handle->f_handle,
   49                                     &handle_dwords,  0);
   50         handle->handle_type = retval;
   51         /* convert handle size to bytes */
   52         handle_bytes = handle_dwords * sizeof(u32);
   53         handle->handle_bytes = handle_bytes;
   54         if ((handle->handle_bytes > f_handle.handle_bytes) ||
   55             (retval == FILEID_INVALID) || (retval == -ENOSPC)) {
   56                 /* As per old exportfs_encode_fh documentation
   57                  * we could return ENOSPC to indicate overflow
   58                  * But file system returned 255 always. So handle
   59                  * both the values
   60                  */
   61                 /*
   62                  * set the handle size to zero so we copy only
   63                  * non variable part of the file_handle
   64                  */
   65                 handle_bytes = 0;
   66                 retval = -EOVERFLOW;
   67         } else
   68                 retval = 0;
   69         /* copy the mount id */
   70         if (copy_to_user(mnt_id, &real_mount(path->mnt)->mnt_id,
   71                          sizeof(*mnt_id)) ||
   72             copy_to_user(ufh, handle,
   73                          sizeof(struct file_handle) + handle_bytes))
   74                 retval = -EFAULT;
   75         kfree(handle);
   76         return retval;
   77 }
   78 
   79 /**
   80  * sys_name_to_handle_at: convert name to handle
   81  * @dfd: directory relative to which name is interpreted if not absolute
   82  * @name: name that should be converted to handle.
   83  * @handle: resulting file handle
   84  * @mnt_id: mount id of the file system containing the file
   85  * @flag: flag value to indicate whether to follow symlink or not
   86  *
   87  * @handle->handle_size indicate the space available to store the
   88  * variable part of the file handle in bytes. If there is not
   89  * enough space, the field is updated to return the minimum
   90  * value required.
   91  */
   92 SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
   93                 struct file_handle __user *, handle, int __user *, mnt_id,
   94                 int, flag)
   95 {
   96         struct path path;
   97         int lookup_flags;
   98         int err;
   99 
  100         if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
  101                 return -EINVAL;
  102 
  103         lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
  104         if (flag & AT_EMPTY_PATH)
  105                 lookup_flags |= LOOKUP_EMPTY;
  106         err = user_path_at(dfd, name, lookup_flags, &path);
  107         if (!err) {
  108                 err = do_sys_name_to_handle(&path, handle, mnt_id);
  109                 path_put(&path);
  110         }
  111         return err;
  112 }
  113 
  114 static struct vfsmount *get_vfsmount_from_fd(int fd)
  115 {
  116         struct vfsmount *mnt;
  117 
  118         if (fd == AT_FDCWD) {
  119                 struct fs_struct *fs = current->fs;
  120                 spin_lock(&fs->lock);
  121                 mnt = mntget(fs->pwd.mnt);
  122                 spin_unlock(&fs->lock);
  123         } else {
  124                 struct fd f = fdget(fd);
  125                 if (!f.file)
  126                         return ERR_PTR(-EBADF);
  127                 mnt = mntget(f.file->f_path.mnt);
  128                 fdput(f);
  129         }
  130         return mnt;
  131 }
  132 
  133 static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
  134 {
  135         return 1;
  136 }
  137 
  138 static int do_handle_to_path(int mountdirfd, struct file_handle *handle,
  139                              struct path *path)
  140 {
  141         int retval = 0;
  142         int handle_dwords;
  143 
  144         path->mnt = get_vfsmount_from_fd(mountdirfd);
  145         if (IS_ERR(path->mnt)) {
  146                 retval = PTR_ERR(path->mnt);
  147                 goto out_err;
  148         }
  149         /* change the handle size to multiple of sizeof(u32) */
  150         handle_dwords = handle->handle_bytes >> 2;
  151         path->dentry = exportfs_decode_fh(path->mnt,
  152                                           (struct fid *)handle->f_handle,
  153                                           handle_dwords, handle->handle_type,
  154                                           vfs_dentry_acceptable, NULL);
  155         if (IS_ERR(path->dentry)) {
  156                 retval = PTR_ERR(path->dentry);
  157                 goto out_mnt;
  158         }
  159         return 0;
  160 out_mnt:
  161         mntput(path->mnt);
  162 out_err:
  163         return retval;
  164 }
  165 
  166 static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
  167                    struct path *path)
  168 {
  169         int retval = 0;
  170         struct file_handle f_handle;
  171         struct file_handle *handle = NULL;
  172 
  173         /*
  174          * With handle we don't look at the execute bit on the
  175          * the directory. Ideally we would like CAP_DAC_SEARCH.
  176          * But we don't have that
  177          */
  178         if (!capable(CAP_DAC_READ_SEARCH)) {
  179                 retval = -EPERM;
  180                 goto out_err;
  181         }
  182         if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) {
  183                 retval = -EFAULT;
  184                 goto out_err;
  185         }
  186         if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
  187             (f_handle.handle_bytes == 0)) {
  188                 retval = -EINVAL;
  189                 goto out_err;
  190         }
  191         handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
  192                          GFP_KERNEL);
  193         if (!handle) {
  194                 retval = -ENOMEM;
  195                 goto out_err;
  196         }
  197         /* copy the full handle */
  198         if (copy_from_user(handle, ufh,
  199                            sizeof(struct file_handle) +
  200                            f_handle.handle_bytes)) {
  201                 retval = -EFAULT;
  202                 goto out_handle;
  203         }
  204 
  205         retval = do_handle_to_path(mountdirfd, handle, path);
  206 
  207 out_handle:
  208         kfree(handle);
  209 out_err:
  210         return retval;
  211 }
  212 
  213 long do_handle_open(int mountdirfd,
  214                     struct file_handle __user *ufh, int open_flag)
  215 {
  216         long retval = 0;
  217         struct path path;
  218         struct file *file;
  219         int fd;
  220 
  221         retval = handle_to_path(mountdirfd, ufh, &path);
  222         if (retval)
  223                 return retval;
  224 
  225         fd = get_unused_fd_flags(open_flag);
  226         if (fd < 0) {
  227                 path_put(&path);
  228                 return fd;
  229         }
  230         file = file_open_root(path.dentry, path.mnt, "", open_flag);
  231         if (IS_ERR(file)) {
  232                 put_unused_fd(fd);
  233                 retval =  PTR_ERR(file);
  234         } else {
  235                 retval = fd;
  236                 fsnotify_open(file);
  237                 fd_install(fd, file);
  238         }
  239         path_put(&path);
  240         return retval;
  241 }
  242 
  243 /**
  244  * sys_open_by_handle_at: Open the file handle
  245  * @mountdirfd: directory file descriptor
  246  * @handle: file handle to be opened
  247  * @flag: open flags.
  248  *
  249  * @mountdirfd indicate the directory file descriptor
  250  * of the mount point. file handle is decoded relative
  251  * to the vfsmount pointed by the @mountdirfd. @flags
  252  * value is same as the open(2) flags.
  253  */
  254 SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
  255                 struct file_handle __user *, handle,
  256                 int, flags)
  257 {
  258         long ret;
  259 
  260         if (force_o_largefile())
  261                 flags |= O_LARGEFILE;
  262 
  263         ret = do_handle_open(mountdirfd, handle, flags);
  264         return ret;
  265 }

Cache object: 59ced0b82df7807a08c3de3ab39da057


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.