]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
990d6c2d AK |
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> | |
becfd1f3 AK |
9 | #include <linux/fs_struct.h> |
10 | #include <linux/fsnotify.h> | |
ed5afeaf | 11 | #include <linux/personality.h> |
7c0f6ba6 | 12 | #include <linux/uaccess.h> |
2b891026 | 13 | #include <linux/compat.h> |
990d6c2d | 14 | #include "internal.h" |
15169fe7 | 15 | #include "mount.h" |
990d6c2d | 16 | |
6ccaaf59 | 17 | static long do_sys_name_to_handle(const struct path *path, |
990d6c2d | 18 | struct file_handle __user *ufh, |
96b2b072 | 19 | int __user *mnt_id, int fh_flags) |
990d6c2d AK |
20 | { |
21 | long retval; | |
22 | struct file_handle f_handle; | |
23 | int handle_dwords, handle_bytes; | |
24 | struct file_handle *handle = NULL; | |
25 | ||
26 | /* | |
96b2b072 AG |
27 | * We need to make sure whether the file system support decoding of |
28 | * the file handle if decodeable file handle was requested. | |
990d6c2d | 29 | */ |
66c62769 | 30 | if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags)) |
990d6c2d AK |
31 | return -EOPNOTSUPP; |
32 | ||
33 | if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) | |
34 | return -EFAULT; | |
35 | ||
36 | if (f_handle.handle_bytes > MAX_HANDLE_SZ) | |
37 | return -EINVAL; | |
38 | ||
68d6f4f3 | 39 | handle = kzalloc(struct_size(handle, f_handle, f_handle.handle_bytes), |
990d6c2d AK |
40 | GFP_KERNEL); |
41 | if (!handle) | |
42 | return -ENOMEM; | |
43 | ||
48fc7f7e | 44 | /* convert handle size to multiple of sizeof(u32) */ |
990d6c2d AK |
45 | handle_dwords = f_handle.handle_bytes >> 2; |
46 | ||
96b2b072 | 47 | /* we ask for a non connectable maybe decodeable file handle */ |
990d6c2d AK |
48 | retval = exportfs_encode_fh(path->dentry, |
49 | (struct fid *)handle->f_handle, | |
96b2b072 | 50 | &handle_dwords, fh_flags); |
990d6c2d AK |
51 | handle->handle_type = retval; |
52 | /* convert handle size to bytes */ | |
53 | handle_bytes = handle_dwords * sizeof(u32); | |
54 | handle->handle_bytes = handle_bytes; | |
55 | if ((handle->handle_bytes > f_handle.handle_bytes) || | |
7cdafe6c | 56 | (retval == FILEID_INVALID) || (retval < 0)) { |
990d6c2d AK |
57 | /* As per old exportfs_encode_fh documentation |
58 | * we could return ENOSPC to indicate overflow | |
59 | * But file system returned 255 always. So handle | |
60 | * both the values | |
61 | */ | |
7cdafe6c AG |
62 | if (retval == FILEID_INVALID || retval == -ENOSPC) |
63 | retval = -EOVERFLOW; | |
990d6c2d AK |
64 | /* |
65 | * set the handle size to zero so we copy only | |
66 | * non variable part of the file_handle | |
67 | */ | |
68 | handle_bytes = 0; | |
990d6c2d AK |
69 | } else |
70 | retval = 0; | |
71 | /* copy the mount id */ | |
6391af6f | 72 | if (put_user(real_mount(path->mnt)->mnt_id, mnt_id) || |
990d6c2d | 73 | copy_to_user(ufh, handle, |
68d6f4f3 | 74 | struct_size(handle, f_handle, handle_bytes))) |
990d6c2d AK |
75 | retval = -EFAULT; |
76 | kfree(handle); | |
77 | return retval; | |
78 | } | |
79 | ||
80 | /** | |
81 | * sys_name_to_handle_at: convert name to handle | |
82 | * @dfd: directory relative to which name is interpreted if not absolute | |
83 | * @name: name that should be converted to handle. | |
84 | * @handle: resulting file handle | |
85 | * @mnt_id: mount id of the file system containing the file | |
86 | * @flag: flag value to indicate whether to follow symlink or not | |
96b2b072 | 87 | * and whether a decodable file handle is required. |
990d6c2d AK |
88 | * |
89 | * @handle->handle_size indicate the space available to store the | |
90 | * variable part of the file handle in bytes. If there is not | |
91 | * enough space, the field is updated to return the minimum | |
92 | * value required. | |
93 | */ | |
94 | SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name, | |
95 | struct file_handle __user *, handle, int __user *, mnt_id, | |
96 | int, flag) | |
97 | { | |
98 | struct path path; | |
99 | int lookup_flags; | |
96b2b072 | 100 | int fh_flags; |
990d6c2d AK |
101 | int err; |
102 | ||
96b2b072 | 103 | if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID)) |
990d6c2d AK |
104 | return -EINVAL; |
105 | ||
106 | lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0; | |
96b2b072 | 107 | fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0; |
990d6c2d AK |
108 | if (flag & AT_EMPTY_PATH) |
109 | lookup_flags |= LOOKUP_EMPTY; | |
110 | err = user_path_at(dfd, name, lookup_flags, &path); | |
111 | if (!err) { | |
96b2b072 | 112 | err = do_sys_name_to_handle(&path, handle, mnt_id, fh_flags); |
990d6c2d AK |
113 | path_put(&path); |
114 | } | |
115 | return err; | |
116 | } | |
becfd1f3 | 117 | |
620c266f | 118 | static int get_path_from_fd(int fd, struct path *root) |
becfd1f3 | 119 | { |
becfd1f3 AK |
120 | if (fd == AT_FDCWD) { |
121 | struct fs_struct *fs = current->fs; | |
122 | spin_lock(&fs->lock); | |
620c266f CB |
123 | *root = fs->pwd; |
124 | path_get(root); | |
becfd1f3 AK |
125 | spin_unlock(&fs->lock); |
126 | } else { | |
2903ff01 AV |
127 | struct fd f = fdget(fd); |
128 | if (!f.file) | |
620c266f CB |
129 | return -EBADF; |
130 | *root = f.file->f_path; | |
131 | path_get(root); | |
2903ff01 | 132 | fdput(f); |
becfd1f3 | 133 | } |
620c266f CB |
134 | |
135 | return 0; | |
becfd1f3 AK |
136 | } |
137 | ||
620c266f CB |
138 | enum handle_to_path_flags { |
139 | HANDLE_CHECK_PERMS = (1 << 0), | |
140 | HANDLE_CHECK_SUBTREE = (1 << 1), | |
141 | }; | |
142 | ||
143 | struct handle_to_path_ctx { | |
144 | struct path root; | |
145 | enum handle_to_path_flags flags; | |
146 | unsigned int fh_flags; | |
147 | }; | |
148 | ||
becfd1f3 AK |
149 | static int vfs_dentry_acceptable(void *context, struct dentry *dentry) |
150 | { | |
620c266f CB |
151 | struct handle_to_path_ctx *ctx = context; |
152 | struct user_namespace *user_ns = current_user_ns(); | |
153 | struct dentry *d, *root = ctx->root.dentry; | |
154 | struct mnt_idmap *idmap = mnt_idmap(ctx->root.mnt); | |
155 | int retval = 0; | |
156 | ||
157 | if (!root) | |
158 | return 1; | |
159 | ||
160 | /* Old permission model with global CAP_DAC_READ_SEARCH. */ | |
161 | if (!ctx->flags) | |
162 | return 1; | |
163 | ||
164 | /* | |
165 | * It's racy as we're not taking rename_lock but we're able to ignore | |
166 | * permissions and we just need an approximation whether we were able | |
167 | * to follow a path to the file. | |
168 | * | |
169 | * It's also potentially expensive on some filesystems especially if | |
170 | * there is a deep path. | |
171 | */ | |
172 | d = dget(dentry); | |
173 | while (d != root && !IS_ROOT(d)) { | |
174 | struct dentry *parent = dget_parent(d); | |
175 | ||
176 | /* | |
177 | * We know that we have the ability to override DAC permissions | |
178 | * as we've verified this earlier via CAP_DAC_READ_SEARCH. But | |
179 | * we also need to make sure that there aren't any unmapped | |
180 | * inodes in the path that would prevent us from reaching the | |
181 | * file. | |
182 | */ | |
183 | if (!privileged_wrt_inode_uidgid(user_ns, idmap, | |
184 | d_inode(parent))) { | |
185 | dput(d); | |
186 | dput(parent); | |
187 | return retval; | |
188 | } | |
189 | ||
190 | dput(d); | |
191 | d = parent; | |
192 | } | |
193 | ||
194 | if (!(ctx->flags & HANDLE_CHECK_SUBTREE) || d == root) | |
195 | retval = 1; | |
196 | WARN_ON_ONCE(d != root && d != root->d_sb->s_root); | |
197 | dput(d); | |
198 | return retval; | |
becfd1f3 AK |
199 | } |
200 | ||
620c266f CB |
201 | static int do_handle_to_path(struct file_handle *handle, struct path *path, |
202 | struct handle_to_path_ctx *ctx) | |
becfd1f3 | 203 | { |
becfd1f3 | 204 | int handle_dwords; |
620c266f | 205 | struct vfsmount *mnt = ctx->root.mnt; |
becfd1f3 | 206 | |
becfd1f3 AK |
207 | /* change the handle size to multiple of sizeof(u32) */ |
208 | handle_dwords = handle->handle_bytes >> 2; | |
620c266f | 209 | path->dentry = exportfs_decode_fh_raw(mnt, |
becfd1f3 AK |
210 | (struct fid *)handle->f_handle, |
211 | handle_dwords, handle->handle_type, | |
620c266f CB |
212 | ctx->fh_flags, |
213 | vfs_dentry_acceptable, ctx); | |
214 | if (IS_ERR_OR_NULL(path->dentry)) { | |
215 | if (path->dentry == ERR_PTR(-ENOMEM)) | |
216 | return -ENOMEM; | |
217 | return -ESTALE; | |
becfd1f3 | 218 | } |
620c266f | 219 | path->mnt = mntget(mnt); |
becfd1f3 | 220 | return 0; |
620c266f CB |
221 | } |
222 | ||
223 | /* | |
224 | * Allow relaxed permissions of file handles if the caller has the | |
225 | * ability to mount the filesystem or create a bind-mount of the | |
226 | * provided @mountdirfd. | |
227 | * | |
228 | * In both cases the caller may be able to get an unobstructed way to | |
229 | * the encoded file handle. If the caller is only able to create a | |
230 | * bind-mount we need to verify that there are no locked mounts on top | |
231 | * of it that could prevent us from getting to the encoded file. | |
232 | * | |
233 | * In principle, locked mounts can prevent the caller from mounting the | |
234 | * filesystem but that only applies to procfs and sysfs neither of which | |
235 | * support decoding file handles. | |
236 | */ | |
237 | static inline bool may_decode_fh(struct handle_to_path_ctx *ctx, | |
238 | unsigned int o_flags) | |
239 | { | |
240 | struct path *root = &ctx->root; | |
241 | ||
242 | /* | |
243 | * Restrict to O_DIRECTORY to provide a deterministic API that avoids a | |
244 | * confusing api in the face of disconnected non-dir dentries. | |
245 | * | |
246 | * There's only one dentry for each directory inode (VFS rule)... | |
247 | */ | |
248 | if (!(o_flags & O_DIRECTORY)) | |
249 | return false; | |
250 | ||
251 | if (ns_capable(root->mnt->mnt_sb->s_user_ns, CAP_SYS_ADMIN)) | |
252 | ctx->flags = HANDLE_CHECK_PERMS; | |
253 | else if (is_mounted(root->mnt) && | |
254 | ns_capable(real_mount(root->mnt)->mnt_ns->user_ns, | |
255 | CAP_SYS_ADMIN) && | |
256 | !has_locked_children(real_mount(root->mnt), root->dentry)) | |
257 | ctx->flags = HANDLE_CHECK_PERMS | HANDLE_CHECK_SUBTREE; | |
258 | else | |
259 | return false; | |
260 | ||
261 | /* Are we able to override DAC permissions? */ | |
262 | if (!ns_capable(current_user_ns(), CAP_DAC_READ_SEARCH)) | |
263 | return false; | |
264 | ||
265 | ctx->fh_flags = EXPORT_FH_DIR_ONLY; | |
266 | return true; | |
becfd1f3 AK |
267 | } |
268 | ||
269 | static int handle_to_path(int mountdirfd, struct file_handle __user *ufh, | |
620c266f | 270 | struct path *path, unsigned int o_flags) |
becfd1f3 AK |
271 | { |
272 | int retval = 0; | |
273 | struct file_handle f_handle; | |
274 | struct file_handle *handle = NULL; | |
620c266f | 275 | struct handle_to_path_ctx ctx = {}; |
becfd1f3 | 276 | |
620c266f CB |
277 | retval = get_path_from_fd(mountdirfd, &ctx.root); |
278 | if (retval) | |
becfd1f3 | 279 | goto out_err; |
620c266f CB |
280 | |
281 | if (!capable(CAP_DAC_READ_SEARCH) && !may_decode_fh(&ctx, o_flags)) { | |
282 | retval = -EPERM; | |
283 | goto out_path; | |
becfd1f3 | 284 | } |
620c266f | 285 | |
becfd1f3 AK |
286 | if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) { |
287 | retval = -EFAULT; | |
620c266f | 288 | goto out_path; |
becfd1f3 AK |
289 | } |
290 | if ((f_handle.handle_bytes > MAX_HANDLE_SZ) || | |
291 | (f_handle.handle_bytes == 0)) { | |
292 | retval = -EINVAL; | |
620c266f | 293 | goto out_path; |
becfd1f3 | 294 | } |
68d6f4f3 | 295 | handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes), |
becfd1f3 AK |
296 | GFP_KERNEL); |
297 | if (!handle) { | |
298 | retval = -ENOMEM; | |
620c266f | 299 | goto out_path; |
becfd1f3 AK |
300 | } |
301 | /* copy the full handle */ | |
161f873b SL |
302 | *handle = f_handle; |
303 | if (copy_from_user(&handle->f_handle, | |
304 | &ufh->f_handle, | |
becfd1f3 AK |
305 | f_handle.handle_bytes)) { |
306 | retval = -EFAULT; | |
307 | goto out_handle; | |
308 | } | |
309 | ||
620c266f | 310 | retval = do_handle_to_path(handle, path, &ctx); |
becfd1f3 AK |
311 | |
312 | out_handle: | |
313 | kfree(handle); | |
620c266f CB |
314 | out_path: |
315 | path_put(&ctx.root); | |
becfd1f3 AK |
316 | out_err: |
317 | return retval; | |
318 | } | |
319 | ||
73ecf5cf AV |
320 | static long do_handle_open(int mountdirfd, struct file_handle __user *ufh, |
321 | int open_flag) | |
becfd1f3 AK |
322 | { |
323 | long retval = 0; | |
324 | struct path path; | |
325 | struct file *file; | |
326 | int fd; | |
327 | ||
620c266f | 328 | retval = handle_to_path(mountdirfd, ufh, &path, open_flag); |
becfd1f3 AK |
329 | if (retval) |
330 | return retval; | |
331 | ||
332 | fd = get_unused_fd_flags(open_flag); | |
333 | if (fd < 0) { | |
334 | path_put(&path); | |
335 | return fd; | |
336 | } | |
ffb37ca3 | 337 | file = file_open_root(&path, "", open_flag, 0); |
becfd1f3 AK |
338 | if (IS_ERR(file)) { |
339 | put_unused_fd(fd); | |
340 | retval = PTR_ERR(file); | |
341 | } else { | |
342 | retval = fd; | |
becfd1f3 AK |
343 | fd_install(fd, file); |
344 | } | |
345 | path_put(&path); | |
346 | return retval; | |
347 | } | |
348 | ||
349 | /** | |
350 | * sys_open_by_handle_at: Open the file handle | |
351 | * @mountdirfd: directory file descriptor | |
352 | * @handle: file handle to be opened | |
a92c7ba9 | 353 | * @flags: open flags. |
becfd1f3 AK |
354 | * |
355 | * @mountdirfd indicate the directory file descriptor | |
356 | * of the mount point. file handle is decoded relative | |
357 | * to the vfsmount pointed by the @mountdirfd. @flags | |
358 | * value is same as the open(2) flags. | |
359 | */ | |
360 | SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd, | |
361 | struct file_handle __user *, handle, | |
362 | int, flags) | |
363 | { | |
364 | long ret; | |
365 | ||
366 | if (force_o_largefile()) | |
367 | flags |= O_LARGEFILE; | |
368 | ||
369 | ret = do_handle_open(mountdirfd, handle, flags); | |
370 | return ret; | |
371 | } | |
2b891026 AV |
372 | |
373 | #ifdef CONFIG_COMPAT | |
374 | /* | |
375 | * Exactly like fs/open.c:sys_open_by_handle_at(), except that it | |
376 | * doesn't set the O_LARGEFILE flag. | |
377 | */ | |
378 | COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd, | |
379 | struct file_handle __user *, handle, int, flags) | |
380 | { | |
381 | return do_handle_open(mountdirfd, handle, flags); | |
382 | } | |
383 | #endif |