staticlong do_sys_name_to_handle(conststruct path *path, struct file_handle __user *ufh, void __user *mnt_id, bool unique_mntid, int fh_flags)
{ long retval; struct file_handle f_handle; int handle_dwords, handle_bytes; struct file_handle *handle = NULL;
/* * We need to make sure whether the file system support decoding of * the file handle if decodeable file handle was requested.
*/ if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags)) return -EOPNOTSUPP;
/* * A request to encode a connectable handle for a disconnected dentry * is unexpected since AT_EMPTY_PATH is not allowed.
*/ if (fh_flags & EXPORT_FH_CONNECTABLE &&
WARN_ON(path->dentry->d_flags & DCACHE_DISCONNECTED)) return -EINVAL;
if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) return -EFAULT;
if (f_handle.handle_bytes > MAX_HANDLE_SZ) return -EINVAL;
handle = kzalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
GFP_KERNEL); if (!handle) return -ENOMEM;
/* convert handle size to multiple of sizeof(u32) */
handle_dwords = f_handle.handle_bytes >> 2;
/* Encode a possibly decodeable/connectable file handle */
retval = exportfs_encode_fh(path->dentry,
(struct fid *)handle->f_handle,
&handle_dwords, fh_flags);
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) ||
(retval == FILEID_INVALID) || (retval < 0)) { /* 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
*/ if (retval == FILEID_INVALID || retval == -ENOSPC)
retval = -EOVERFLOW; /* * set the handle size to zero so we copy only * non variable part of the file_handle
*/
handle_bytes = 0;
} else { /* * When asked to encode a connectable file handle, encode this * property in the file handle itself, so that we later know * how to decode it. * For sanity, also encode in the file handle if the encoded * object is a directory and verify this during decode, because * decoding directory file handles is quite different than * decoding connectable non-directory file handles.
*/ if (fh_flags & EXPORT_FH_CONNECTABLE) {
handle->handle_type |= FILEID_IS_CONNECTABLE; if (d_is_dir(path->dentry))
handle->handle_type |= FILEID_IS_DIR;
}
retval = 0;
} /* copy the mount id */ if (unique_mntid) { if (put_user(real_mount(path->mnt)->mnt_id_unique,
(u64 __user *) mnt_id))
retval = -EFAULT;
} else { if (put_user(real_mount(path->mnt)->mnt_id,
(int __user *) mnt_id))
retval = -EFAULT;
} /* copy the handle */ if (retval != -EFAULT &&
copy_to_user(ufh, handle,
struct_size(handle, f_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 * (u64 if AT_HANDLE_MNT_ID_UNIQUE, otherwise int) * @flag: flag value to indicate whether to follow symlink or not * and whether a decodable file handle is required. * * @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, constchar __user *, name, struct file_handle __user *, handle, void __user *, mnt_id, int, flag)
{ struct path path; int lookup_flags; int fh_flags = 0; int err;
/* * AT_HANDLE_FID means there is no intention to decode file handle * AT_HANDLE_CONNECTABLE means there is an intention to decode a * connected fd (with known path), so these flags are conflicting. * AT_EMPTY_PATH could be used along with a dfd that refers to a * disconnected non-directory, which cannot be used to encode a * connectable file handle, because its parent is unknown.
*/ if (flag & AT_HANDLE_CONNECTABLE &&
flag & (AT_HANDLE_FID | AT_EMPTY_PATH)) return -EINVAL; elseif (flag & AT_HANDLE_FID)
fh_flags |= EXPORT_FH_FID; elseif (flag & AT_HANDLE_CONNECTABLE)
fh_flags |= EXPORT_FH_CONNECTABLE;
/* Old permission model with global CAP_DAC_READ_SEARCH. */ if (!ctx->flags) return 1;
/* * Verify that the decoded dentry itself has a valid id mapping. * In case the decoded dentry is the mountfd root itself, this * verifies that the mountfd inode itself has a valid id mapping.
*/ if (!privileged_wrt_inode_uidgid(user_ns, idmap, d_inode(dentry))) return 0;
/* * It's racy as we're not taking rename_lock but we're able to ignore * permissions and we just need an approximation whether we were able * to follow a path to the file. * * It's also potentially expensive on some filesystems especially if * there is a deep path.
*/
d = dget(dentry); while (d != root && !IS_ROOT(d)) { struct dentry *parent = dget_parent(d);
/* * We know that we have the ability to override DAC permissions * as we've verified this earlier via CAP_DAC_READ_SEARCH. But * we also need to make sure that there aren't any unmapped * inodes in the path that would prevent us from reaching the * file.
*/ if (!privileged_wrt_inode_uidgid(user_ns, idmap,
d_inode(parent))) {
dput(d);
dput(parent); return retval;
}
dput(d);
d = parent;
}
if (!(ctx->flags & HANDLE_CHECK_SUBTREE) || d == root)
retval = 1; /* * exportfs_decode_fh_raw() does not call acceptable() callback with * a disconnected directory dentry, so we should have reached either * mount fd directory or sb root.
*/ if (ctx->fh_flags & EXPORT_FH_DIR_ONLY)
WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
dput(d); return retval;
}
/* * Allow relaxed permissions of file handles if the caller has * the ability to mount the filesystem or create a bind-mount of * the provided @mountdirfd. * * In both cases the caller may be able to get an unobstructed * way to the encoded file handle. If the caller is only able to * create a bind-mount we need to verify that there are no * locked mounts on top of it that could prevent us from getting * to the encoded file. * * In principle, locked mounts can prevent the caller from * mounting the filesystem but that only applies to procfs and * sysfs neither of which support decoding file handles. * * Restrict to O_DIRECTORY to provide a deterministic API that * avoids a confusing api in the face of disconnected non-dir * dentries. * * There's only one dentry for each directory inode (VFS rule)...
*/ if (!(o_flags & O_DIRECTORY)) return -EPERM;
if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) return -EFAULT;
if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
(f_handle.handle_bytes == 0)) return -EINVAL;
if (f_handle.handle_type < 0 ||
FILEID_USER_FLAGS(f_handle.handle_type) & ~FILEID_VALID_USER_FLAGS) return -EINVAL;
retval = get_path_anchor(mountdirfd, &ctx.root); if (retval) return retval;
eops = ctx.root.mnt->mnt_sb->s_export_op; if (eops && eops->permission)
retval = eops->permission(&ctx, o_flags); else
retval = may_decode_fh(&ctx, o_flags); if (retval) goto out_path;
handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
GFP_KERNEL); if (!handle) {
retval = -ENOMEM; goto out_path;
} /* copy the full handle */
*handle = f_handle; if (copy_from_user(&handle->f_handle,
&ufh->f_handle,
f_handle.handle_bytes)) {
retval = -EFAULT; goto out_path;
}
/* * If handle was encoded with AT_HANDLE_CONNECTABLE, verify that we * are decoding an fd with connected path, which is accessible from * the mount fd path.
*/ if (f_handle.handle_type & FILEID_IS_CONNECTABLE) {
ctx.fh_flags |= EXPORT_FH_CONNECTABLE;
ctx.flags |= HANDLE_CHECK_SUBTREE;
} if (f_handle.handle_type & FILEID_IS_DIR)
ctx.fh_flags |= EXPORT_FH_DIR_ONLY; /* Filesystem code should not be exposed to user flags */
handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
retval = do_handle_to_path(handle, path, &ctx);
retval = handle_to_path(mountdirfd, ufh, &path, open_flag); if (retval) return retval;
CLASS(get_unused_fd, fd)(open_flag); if (fd < 0) return fd;
eops = path.mnt->mnt_sb->s_export_op; if (eops->open)
file = eops->open(&path, open_flag); else
file = file_open_root(&path, "", open_flag, 0); if (IS_ERR(file)) return PTR_ERR(file);
fd_install(fd, file); return take_fd(fd);
}
/** * sys_open_by_handle_at: Open the file handle * @mountdirfd: directory file descriptor * @handle: file handle to be opened * @flags: open flags. * * @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;
}
#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
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.