1 // SPDX-License-Identifier: GPL-2.0 1 2 #include <linux/syscalls.h> 3 #include <linux/slab.h> 4 #include <linux/fs.h> 5 #include <linux/file.h> 6 #include <linux/mount.h> 7 #include <linux/namei.h> 8 #include <linux/exportfs.h> 9 #include <linux/fs_struct.h> 10 #include <linux/fsnotify.h> 11 #include <linux/personality.h> 12 #include <linux/uaccess.h> 13 #include <linux/compat.h> 14 #include "internal.h" 15 #include "mount.h" 16 17 static long do_sys_name_to_handle(const struct 18 struct file_ 19 void __user 20 int fh_flags 21 { 22 long retval; 23 struct file_handle f_handle; 24 int handle_dwords, handle_bytes; 25 struct file_handle *handle = NULL; 26 27 /* 28 * We need to make sure whether the fi 29 * the file handle if decodeable file 30 */ 31 if (!exportfs_can_encode_fh(path->dent 32 return -EOPNOTSUPP; 33 34 if (copy_from_user(&f_handle, ufh, siz 35 return -EFAULT; 36 37 if (f_handle.handle_bytes > MAX_HANDLE 38 return -EINVAL; 39 40 handle = kzalloc(struct_size(handle, f 41 GFP_KERNEL); 42 if (!handle) 43 return -ENOMEM; 44 45 /* convert handle size to multiple of 46 handle_dwords = f_handle.handle_bytes 47 48 /* we ask for a non connectable maybe 49 retval = exportfs_encode_fh(path->dent 50 (struct fi 51 &handle_dw 52 handle->handle_type = retval; 53 /* convert handle size to bytes */ 54 handle_bytes = handle_dwords * sizeof( 55 handle->handle_bytes = handle_bytes; 56 if ((handle->handle_bytes > f_handle.h 57 (retval == FILEID_INVALID) || (ret 58 /* As per old exportfs_encode_ 59 * we could return ENOSPC to i 60 * But file system returned 25 61 * both the values 62 */ 63 if (retval == FILEID_INVALID | 64 retval = -EOVERFLOW; 65 /* 66 * set the handle size to zero 67 * non variable part of the fi 68 */ 69 handle_bytes = 0; 70 } else 71 retval = 0; 72 /* copy the mount id */ 73 if (unique_mntid) { 74 if (put_user(real_mount(path-> 75 (u64 __user *) mn 76 retval = -EFAULT; 77 } else { 78 if (put_user(real_mount(path-> 79 (int __user *) mn 80 retval = -EFAULT; 81 } 82 /* copy the handle */ 83 if (retval != -EFAULT && 84 copy_to_user(ufh, handle, 85 struct_size(handl 86 retval = -EFAULT; 87 kfree(handle); 88 return retval; 89 } 90 91 /** 92 * sys_name_to_handle_at: convert name to hand 93 * @dfd: directory relative to which name is i 94 * @name: name that should be converted to han 95 * @handle: resulting file handle 96 * @mnt_id: mount id of the file system contai 97 * (u64 if AT_HANDLE_MNT_ID_UNIQUE, o 98 * @flag: flag value to indicate whether to fo 99 * and whether a decodable file handle 100 * 101 * @handle->handle_size indicate the space ava 102 * variable part of the file handle in bytes. 103 * enough space, the field is updated to retur 104 * value required. 105 */ 106 SYSCALL_DEFINE5(name_to_handle_at, int, dfd, c 107 struct file_handle __user *, h 108 int, flag) 109 { 110 struct path path; 111 int lookup_flags; 112 int fh_flags; 113 int err; 114 115 if (flag & ~(AT_SYMLINK_FOLLOW | AT_EM 116 AT_HANDLE_MNT_ID_UNIQUE)) 117 return -EINVAL; 118 119 lookup_flags = (flag & AT_SYMLINK_FOLL 120 fh_flags = (flag & AT_HANDLE_FID) ? EX 121 if (flag & AT_EMPTY_PATH) 122 lookup_flags |= LOOKUP_EMPTY; 123 err = user_path_at(dfd, name, lookup_f 124 if (!err) { 125 err = do_sys_name_to_handle(&p 126 fl 127 fh 128 path_put(&path); 129 } 130 return err; 131 } 132 133 static int get_path_from_fd(int fd, struct pat 134 { 135 if (fd == AT_FDCWD) { 136 struct fs_struct *fs = current 137 spin_lock(&fs->lock); 138 *root = fs->pwd; 139 path_get(root); 140 spin_unlock(&fs->lock); 141 } else { 142 struct fd f = fdget(fd); 143 if (!fd_file(f)) 144 return -EBADF; 145 *root = fd_file(f)->f_path; 146 path_get(root); 147 fdput(f); 148 } 149 150 return 0; 151 } 152 153 enum handle_to_path_flags { 154 HANDLE_CHECK_PERMS = (1 << 0), 155 HANDLE_CHECK_SUBTREE = (1 << 1), 156 }; 157 158 struct handle_to_path_ctx { 159 struct path root; 160 enum handle_to_path_flags flags; 161 unsigned int fh_flags; 162 }; 163 164 static int vfs_dentry_acceptable(void *context 165 { 166 struct handle_to_path_ctx *ctx = conte 167 struct user_namespace *user_ns = curre 168 struct dentry *d, *root = ctx->root.de 169 struct mnt_idmap *idmap = mnt_idmap(ct 170 int retval = 0; 171 172 if (!root) 173 return 1; 174 175 /* Old permission model with global CA 176 if (!ctx->flags) 177 return 1; 178 179 /* 180 * It's racy as we're not taking renam 181 * permissions and we just need an app 182 * to follow a path to the file. 183 * 184 * It's also potentially expensive on 185 * there is a deep path. 186 */ 187 d = dget(dentry); 188 while (d != root && !IS_ROOT(d)) { 189 struct dentry *parent = dget_p 190 191 /* 192 * We know that we have the ab 193 * as we've verified this earl 194 * we also need to make sure t 195 * inodes in the path that wou 196 * file. 197 */ 198 if (!privileged_wrt_inode_uidg 199 200 dput(d); 201 dput(parent); 202 return retval; 203 } 204 205 dput(d); 206 d = parent; 207 } 208 209 if (!(ctx->flags & HANDLE_CHECK_SUBTRE 210 retval = 1; 211 WARN_ON_ONCE(d != root && d != root->d 212 dput(d); 213 return retval; 214 } 215 216 static int do_handle_to_path(struct file_handl 217 struct handle_to_ 218 { 219 int handle_dwords; 220 struct vfsmount *mnt = ctx->root.mnt; 221 222 /* change the handle size to multiple 223 handle_dwords = handle->handle_bytes > 224 path->dentry = exportfs_decode_fh_raw( 225 (str 226 hand 227 ctx- 228 vfs_ 229 if (IS_ERR_OR_NULL(path->dentry)) { 230 if (path->dentry == ERR_PTR(-E 231 return -ENOMEM; 232 return -ESTALE; 233 } 234 path->mnt = mntget(mnt); 235 return 0; 236 } 237 238 /* 239 * Allow relaxed permissions of file handles i 240 * ability to mount the filesystem or create a 241 * provided @mountdirfd. 242 * 243 * In both cases the caller may be able to get 244 * the encoded file handle. If the caller is o 245 * bind-mount we need to verify that there are 246 * of it that could prevent us from getting to 247 * 248 * In principle, locked mounts can prevent the 249 * filesystem but that only applies to procfs 250 * support decoding file handles. 251 */ 252 static inline bool may_decode_fh(struct handle 253 unsigned int 254 { 255 struct path *root = &ctx->root; 256 257 /* 258 * Restrict to O_DIRECTORY to provide 259 * confusing api in the face of discon 260 * 261 * There's only one dentry for each di 262 */ 263 if (!(o_flags & O_DIRECTORY)) 264 return false; 265 266 if (ns_capable(root->mnt->mnt_sb->s_us 267 ctx->flags = HANDLE_CHECK_PERM 268 else if (is_mounted(root->mnt) && 269 ns_capable(real_mount(root->m 270 CAP_SYS_ADMIN) && 271 !has_locked_children(real_mou 272 ctx->flags = HANDLE_CHECK_PERM 273 else 274 return false; 275 276 /* Are we able to override DAC permiss 277 if (!ns_capable(current_user_ns(), CAP 278 return false; 279 280 ctx->fh_flags = EXPORT_FH_DIR_ONLY; 281 return true; 282 } 283 284 static int handle_to_path(int mountdirfd, stru 285 struct path *path, unsigned 286 { 287 int retval = 0; 288 struct file_handle f_handle; 289 struct file_handle *handle = NULL; 290 struct handle_to_path_ctx ctx = {}; 291 292 retval = get_path_from_fd(mountdirfd, 293 if (retval) 294 goto out_err; 295 296 if (!capable(CAP_DAC_READ_SEARCH) && ! 297 retval = -EPERM; 298 goto out_path; 299 } 300 301 if (copy_from_user(&f_handle, ufh, siz 302 retval = -EFAULT; 303 goto out_path; 304 } 305 if ((f_handle.handle_bytes > MAX_HANDL 306 (f_handle.handle_bytes == 0)) { 307 retval = -EINVAL; 308 goto out_path; 309 } 310 handle = kmalloc(struct_size(handle, f 311 GFP_KERNEL); 312 if (!handle) { 313 retval = -ENOMEM; 314 goto out_path; 315 } 316 /* copy the full handle */ 317 *handle = f_handle; 318 if (copy_from_user(&handle->f_handle, 319 &ufh->f_handle, 320 f_handle.handle_byt 321 retval = -EFAULT; 322 goto out_handle; 323 } 324 325 retval = do_handle_to_path(handle, pat 326 327 out_handle: 328 kfree(handle); 329 out_path: 330 path_put(&ctx.root); 331 out_err: 332 return retval; 333 } 334 335 static long do_handle_open(int mountdirfd, str 336 int open_flag) 337 { 338 long retval = 0; 339 struct path path; 340 struct file *file; 341 int fd; 342 343 retval = handle_to_path(mountdirfd, uf 344 if (retval) 345 return retval; 346 347 fd = get_unused_fd_flags(open_flag); 348 if (fd < 0) { 349 path_put(&path); 350 return fd; 351 } 352 file = file_open_root(&path, "", open_ 353 if (IS_ERR(file)) { 354 put_unused_fd(fd); 355 retval = PTR_ERR(file); 356 } else { 357 retval = fd; 358 fd_install(fd, file); 359 } 360 path_put(&path); 361 return retval; 362 } 363 364 /** 365 * sys_open_by_handle_at: Open the file handle 366 * @mountdirfd: directory file descriptor 367 * @handle: file handle to be opened 368 * @flags: open flags. 369 * 370 * @mountdirfd indicate the directory file des 371 * of the mount point. file handle is decoded 372 * to the vfsmount pointed by the @mountdirfd. 373 * value is same as the open(2) flags. 374 */ 375 SYSCALL_DEFINE3(open_by_handle_at, int, mountd 376 struct file_handle __user *, h 377 int, flags) 378 { 379 long ret; 380 381 if (force_o_largefile()) 382 flags |= O_LARGEFILE; 383 384 ret = do_handle_open(mountdirfd, handl 385 return ret; 386 } 387 388 #ifdef CONFIG_COMPAT 389 /* 390 * Exactly like fs/open.c:sys_open_by_handle_a 391 * doesn't set the O_LARGEFILE flag. 392 */ 393 COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, 394 struct file_handl 395 { 396 return do_handle_open(mountdirfd, hand 397 } 398 #endif 399
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.