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