]> Git Repo - linux.git/blob - fs/xfs/xfs_handle.c
Merge patch series "riscv: Extension parsing fixes"
[linux.git] / fs / xfs / xfs_handle.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4  * Copyright (c) 2022-2024 Oracle.
5  * All rights reserved.
6  */
7 #include "xfs.h"
8 #include "xfs_fs.h"
9 #include "xfs_format.h"
10 #include "xfs_log_format.h"
11 #include "xfs_shared.h"
12 #include "xfs_trans_resv.h"
13 #include "xfs_mount.h"
14 #include "xfs_bmap_btree.h"
15 #include "xfs_inode.h"
16 #include "xfs_error.h"
17 #include "xfs_trace.h"
18 #include "xfs_trans.h"
19 #include "xfs_da_format.h"
20 #include "xfs_da_btree.h"
21 #include "xfs_attr.h"
22 #include "xfs_ioctl.h"
23 #include "xfs_parent.h"
24 #include "xfs_da_btree.h"
25 #include "xfs_handle.h"
26 #include "xfs_health.h"
27 #include "xfs_icache.h"
28 #include "xfs_export.h"
29 #include "xfs_xattr.h"
30 #include "xfs_acl.h"
31
32 #include <linux/namei.h>
33
34 static inline size_t
35 xfs_filehandle_fid_len(void)
36 {
37         struct xfs_handle       *handle = NULL;
38
39         return sizeof(struct xfs_fid) - sizeof(handle->ha_fid.fid_len);
40 }
41
42 static inline size_t
43 xfs_filehandle_init(
44         struct xfs_mount        *mp,
45         xfs_ino_t               ino,
46         uint32_t                gen,
47         struct xfs_handle       *handle)
48 {
49         memcpy(&handle->ha_fsid, mp->m_fixedfsid, sizeof(struct xfs_fsid));
50
51         handle->ha_fid.fid_len = xfs_filehandle_fid_len();
52         handle->ha_fid.fid_pad = 0;
53         handle->ha_fid.fid_gen = gen;
54         handle->ha_fid.fid_ino = ino;
55
56         return sizeof(struct xfs_handle);
57 }
58
59 static inline size_t
60 xfs_fshandle_init(
61         struct xfs_mount        *mp,
62         struct xfs_handle       *handle)
63 {
64         memcpy(&handle->ha_fsid, mp->m_fixedfsid, sizeof(struct xfs_fsid));
65         memset(&handle->ha_fid, 0, sizeof(handle->ha_fid));
66
67         return sizeof(struct xfs_fsid);
68 }
69
70 /*
71  * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
72  * a file or fs handle.
73  *
74  * XFS_IOC_PATH_TO_FSHANDLE
75  *    returns fs handle for a mount point or path within that mount point
76  * XFS_IOC_FD_TO_HANDLE
77  *    returns full handle for a FD opened in user space
78  * XFS_IOC_PATH_TO_HANDLE
79  *    returns full handle for a path
80  */
81 int
82 xfs_find_handle(
83         unsigned int            cmd,
84         xfs_fsop_handlereq_t    *hreq)
85 {
86         int                     hsize;
87         xfs_handle_t            handle;
88         struct inode            *inode;
89         struct fd               f = {NULL};
90         struct path             path;
91         int                     error;
92         struct xfs_inode        *ip;
93
94         if (cmd == XFS_IOC_FD_TO_HANDLE) {
95                 f = fdget(hreq->fd);
96                 if (!f.file)
97                         return -EBADF;
98                 inode = file_inode(f.file);
99         } else {
100                 error = user_path_at(AT_FDCWD, hreq->path, 0, &path);
101                 if (error)
102                         return error;
103                 inode = d_inode(path.dentry);
104         }
105         ip = XFS_I(inode);
106
107         /*
108          * We can only generate handles for inodes residing on a XFS filesystem,
109          * and only for regular files, directories or symbolic links.
110          */
111         error = -EINVAL;
112         if (inode->i_sb->s_magic != XFS_SB_MAGIC)
113                 goto out_put;
114
115         error = -EBADF;
116         if (!S_ISREG(inode->i_mode) &&
117             !S_ISDIR(inode->i_mode) &&
118             !S_ISLNK(inode->i_mode))
119                 goto out_put;
120
121
122         memcpy(&handle.ha_fsid, ip->i_mount->m_fixedfsid, sizeof(xfs_fsid_t));
123
124         if (cmd == XFS_IOC_PATH_TO_FSHANDLE)
125                 hsize = xfs_fshandle_init(ip->i_mount, &handle);
126         else
127                 hsize = xfs_filehandle_init(ip->i_mount, ip->i_ino,
128                                 inode->i_generation, &handle);
129
130         error = -EFAULT;
131         if (copy_to_user(hreq->ohandle, &handle, hsize) ||
132             copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32)))
133                 goto out_put;
134
135         error = 0;
136
137  out_put:
138         if (cmd == XFS_IOC_FD_TO_HANDLE)
139                 fdput(f);
140         else
141                 path_put(&path);
142         return error;
143 }
144
145 /*
146  * No need to do permission checks on the various pathname components
147  * as the handle operations are privileged.
148  */
149 STATIC int
150 xfs_handle_acceptable(
151         void                    *context,
152         struct dentry           *dentry)
153 {
154         return 1;
155 }
156
157 /* Convert handle already copied to kernel space into a dentry. */
158 static struct dentry *
159 xfs_khandle_to_dentry(
160         struct file             *file,
161         struct xfs_handle       *handle)
162 {
163         struct xfs_fid64        fid = {
164                 .ino            = handle->ha_fid.fid_ino,
165                 .gen            = handle->ha_fid.fid_gen,
166         };
167
168         /*
169          * Only allow handle opens under a directory.
170          */
171         if (!S_ISDIR(file_inode(file)->i_mode))
172                 return ERR_PTR(-ENOTDIR);
173
174         if (handle->ha_fid.fid_len != xfs_filehandle_fid_len())
175                 return ERR_PTR(-EINVAL);
176
177         return exportfs_decode_fh(file->f_path.mnt, (struct fid *)&fid, 3,
178                         FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG,
179                         xfs_handle_acceptable, NULL);
180 }
181
182 /* Convert handle already copied to kernel space into an xfs_inode. */
183 static struct xfs_inode *
184 xfs_khandle_to_inode(
185         struct file             *file,
186         struct xfs_handle       *handle)
187 {
188         struct xfs_inode        *ip = XFS_I(file_inode(file));
189         struct xfs_mount        *mp = ip->i_mount;
190         struct inode            *inode;
191
192         if (!S_ISDIR(VFS_I(ip)->i_mode))
193                 return ERR_PTR(-ENOTDIR);
194
195         if (handle->ha_fid.fid_len != xfs_filehandle_fid_len())
196                 return ERR_PTR(-EINVAL);
197
198         inode = xfs_nfs_get_inode(mp->m_super, handle->ha_fid.fid_ino,
199                         handle->ha_fid.fid_gen);
200         if (IS_ERR(inode))
201                 return ERR_CAST(inode);
202
203         return XFS_I(inode);
204 }
205
206 /*
207  * Convert userspace handle data into a dentry.
208  */
209 struct dentry *
210 xfs_handle_to_dentry(
211         struct file             *parfilp,
212         void __user             *uhandle,
213         u32                     hlen)
214 {
215         xfs_handle_t            handle;
216
217         if (hlen != sizeof(xfs_handle_t))
218                 return ERR_PTR(-EINVAL);
219         if (copy_from_user(&handle, uhandle, hlen))
220                 return ERR_PTR(-EFAULT);
221
222         return xfs_khandle_to_dentry(parfilp, &handle);
223 }
224
225 STATIC struct dentry *
226 xfs_handlereq_to_dentry(
227         struct file             *parfilp,
228         xfs_fsop_handlereq_t    *hreq)
229 {
230         return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen);
231 }
232
233 int
234 xfs_open_by_handle(
235         struct file             *parfilp,
236         xfs_fsop_handlereq_t    *hreq)
237 {
238         const struct cred       *cred = current_cred();
239         int                     error;
240         int                     fd;
241         int                     permflag;
242         struct file             *filp;
243         struct inode            *inode;
244         struct dentry           *dentry;
245         fmode_t                 fmode;
246         struct path             path;
247
248         if (!capable(CAP_SYS_ADMIN))
249                 return -EPERM;
250
251         dentry = xfs_handlereq_to_dentry(parfilp, hreq);
252         if (IS_ERR(dentry))
253                 return PTR_ERR(dentry);
254         inode = d_inode(dentry);
255
256         /* Restrict xfs_open_by_handle to directories & regular files. */
257         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
258                 error = -EPERM;
259                 goto out_dput;
260         }
261
262 #if BITS_PER_LONG != 32
263         hreq->oflags |= O_LARGEFILE;
264 #endif
265
266         permflag = hreq->oflags;
267         fmode = OPEN_FMODE(permflag);
268         if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
269             (fmode & FMODE_WRITE) && IS_APPEND(inode)) {
270                 error = -EPERM;
271                 goto out_dput;
272         }
273
274         if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
275                 error = -EPERM;
276                 goto out_dput;
277         }
278
279         /* Can't write directories. */
280         if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) {
281                 error = -EISDIR;
282                 goto out_dput;
283         }
284
285         fd = get_unused_fd_flags(0);
286         if (fd < 0) {
287                 error = fd;
288                 goto out_dput;
289         }
290
291         path.mnt = parfilp->f_path.mnt;
292         path.dentry = dentry;
293         filp = dentry_open(&path, hreq->oflags, cred);
294         dput(dentry);
295         if (IS_ERR(filp)) {
296                 put_unused_fd(fd);
297                 return PTR_ERR(filp);
298         }
299
300         if (S_ISREG(inode->i_mode)) {
301                 filp->f_flags |= O_NOATIME;
302                 filp->f_mode |= FMODE_NOCMTIME;
303         }
304
305         fd_install(fd, filp);
306         return fd;
307
308  out_dput:
309         dput(dentry);
310         return error;
311 }
312
313 int
314 xfs_readlink_by_handle(
315         struct file             *parfilp,
316         xfs_fsop_handlereq_t    *hreq)
317 {
318         struct dentry           *dentry;
319         __u32                   olen;
320         int                     error;
321
322         if (!capable(CAP_SYS_ADMIN))
323                 return -EPERM;
324
325         dentry = xfs_handlereq_to_dentry(parfilp, hreq);
326         if (IS_ERR(dentry))
327                 return PTR_ERR(dentry);
328
329         /* Restrict this handle operation to symlinks only. */
330         if (!d_is_symlink(dentry)) {
331                 error = -EINVAL;
332                 goto out_dput;
333         }
334
335         if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) {
336                 error = -EFAULT;
337                 goto out_dput;
338         }
339
340         error = vfs_readlink(dentry, hreq->ohandle, olen);
341
342  out_dput:
343         dput(dentry);
344         return error;
345 }
346
347 /*
348  * Format an attribute and copy it out to the user's buffer.
349  * Take care to check values and protect against them changing later,
350  * we may be reading them directly out of a user buffer.
351  */
352 static void
353 xfs_ioc_attr_put_listent(
354         struct xfs_attr_list_context *context,
355         int                     flags,
356         unsigned char           *name,
357         int                     namelen,
358         void                    *value,
359         int                     valuelen)
360 {
361         struct xfs_attrlist     *alist = context->buffer;
362         struct xfs_attrlist_ent *aep;
363         int                     arraytop;
364
365         ASSERT(!context->seen_enough);
366         ASSERT(context->count >= 0);
367         ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
368         ASSERT(context->firstu >= sizeof(*alist));
369         ASSERT(context->firstu <= context->bufsize);
370
371         /*
372          * Only list entries in the right namespace.
373          */
374         if (context->attr_filter != (flags & XFS_ATTR_NSP_ONDISK_MASK))
375                 return;
376
377         arraytop = sizeof(*alist) +
378                         context->count * sizeof(alist->al_offset[0]);
379
380         /* decrement by the actual bytes used by the attr */
381         context->firstu -= round_up(offsetof(struct xfs_attrlist_ent, a_name) +
382                         namelen + 1, sizeof(uint32_t));
383         if (context->firstu < arraytop) {
384                 trace_xfs_attr_list_full(context);
385                 alist->al_more = 1;
386                 context->seen_enough = 1;
387                 return;
388         }
389
390         aep = context->buffer + context->firstu;
391         aep->a_valuelen = valuelen;
392         memcpy(aep->a_name, name, namelen);
393         aep->a_name[namelen] = 0;
394         alist->al_offset[context->count++] = context->firstu;
395         alist->al_count = context->count;
396         trace_xfs_attr_list_add(context);
397 }
398
399 static unsigned int
400 xfs_attr_filter(
401         u32                     ioc_flags)
402 {
403         if (ioc_flags & XFS_IOC_ATTR_ROOT)
404                 return XFS_ATTR_ROOT;
405         if (ioc_flags & XFS_IOC_ATTR_SECURE)
406                 return XFS_ATTR_SECURE;
407         return 0;
408 }
409
410 static inline enum xfs_attr_update
411 xfs_xattr_flags(
412         u32                     ioc_flags,
413         void                    *value)
414 {
415         if (!value)
416                 return XFS_ATTRUPDATE_REMOVE;
417         if (ioc_flags & XFS_IOC_ATTR_CREATE)
418                 return XFS_ATTRUPDATE_CREATE;
419         if (ioc_flags & XFS_IOC_ATTR_REPLACE)
420                 return XFS_ATTRUPDATE_REPLACE;
421         return XFS_ATTRUPDATE_UPSERT;
422 }
423
424 int
425 xfs_ioc_attr_list(
426         struct xfs_inode                *dp,
427         void __user                     *ubuf,
428         size_t                          bufsize,
429         int                             flags,
430         struct xfs_attrlist_cursor __user *ucursor)
431 {
432         struct xfs_attr_list_context    context = { };
433         struct xfs_attrlist             *alist;
434         void                            *buffer;
435         int                             error;
436
437         if (bufsize < sizeof(struct xfs_attrlist) ||
438             bufsize > XFS_XATTR_LIST_MAX)
439                 return -EINVAL;
440
441         /*
442          * Reject flags, only allow namespaces.
443          */
444         if (flags & ~(XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE))
445                 return -EINVAL;
446         if (flags == (XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE))
447                 return -EINVAL;
448
449         /*
450          * Validate the cursor.
451          */
452         if (copy_from_user(&context.cursor, ucursor, sizeof(context.cursor)))
453                 return -EFAULT;
454         if (context.cursor.pad1 || context.cursor.pad2)
455                 return -EINVAL;
456         if (!context.cursor.initted &&
457             (context.cursor.hashval || context.cursor.blkno ||
458              context.cursor.offset))
459                 return -EINVAL;
460
461         buffer = kvzalloc(bufsize, GFP_KERNEL);
462         if (!buffer)
463                 return -ENOMEM;
464
465         /*
466          * Initialize the output buffer.
467          */
468         context.dp = dp;
469         context.resynch = 1;
470         context.attr_filter = xfs_attr_filter(flags);
471         context.buffer = buffer;
472         context.bufsize = round_down(bufsize, sizeof(uint32_t));
473         context.firstu = context.bufsize;
474         context.put_listent = xfs_ioc_attr_put_listent;
475
476         alist = context.buffer;
477         alist->al_count = 0;
478         alist->al_more = 0;
479         alist->al_offset[0] = context.bufsize;
480
481         error = xfs_attr_list(&context);
482         if (error)
483                 goto out_free;
484
485         if (copy_to_user(ubuf, buffer, bufsize) ||
486             copy_to_user(ucursor, &context.cursor, sizeof(context.cursor)))
487                 error = -EFAULT;
488 out_free:
489         kvfree(buffer);
490         return error;
491 }
492
493 int
494 xfs_attrlist_by_handle(
495         struct file             *parfilp,
496         struct xfs_fsop_attrlist_handlereq __user *p)
497 {
498         struct xfs_fsop_attrlist_handlereq al_hreq;
499         struct dentry           *dentry;
500         int                     error = -ENOMEM;
501
502         if (!capable(CAP_SYS_ADMIN))
503                 return -EPERM;
504         if (copy_from_user(&al_hreq, p, sizeof(al_hreq)))
505                 return -EFAULT;
506
507         dentry = xfs_handlereq_to_dentry(parfilp, &al_hreq.hreq);
508         if (IS_ERR(dentry))
509                 return PTR_ERR(dentry);
510
511         error = xfs_ioc_attr_list(XFS_I(d_inode(dentry)), al_hreq.buffer,
512                                   al_hreq.buflen, al_hreq.flags, &p->pos);
513         dput(dentry);
514         return error;
515 }
516
517 static int
518 xfs_attrmulti_attr_get(
519         struct inode            *inode,
520         unsigned char           *name,
521         unsigned char           __user *ubuf,
522         uint32_t                *len,
523         uint32_t                flags)
524 {
525         struct xfs_da_args      args = {
526                 .dp             = XFS_I(inode),
527                 .attr_filter    = xfs_attr_filter(flags),
528                 .name           = name,
529                 .namelen        = strlen(name),
530                 .valuelen       = *len,
531         };
532         int                     error;
533
534         if (*len > XFS_XATTR_SIZE_MAX)
535                 return -EINVAL;
536
537         error = xfs_attr_get(&args);
538         if (error)
539                 goto out_kfree;
540
541         *len = args.valuelen;
542         if (copy_to_user(ubuf, args.value, args.valuelen))
543                 error = -EFAULT;
544
545 out_kfree:
546         kvfree(args.value);
547         return error;
548 }
549
550 static int
551 xfs_attrmulti_attr_set(
552         struct inode            *inode,
553         unsigned char           *name,
554         const unsigned char     __user *ubuf,
555         uint32_t                len,
556         uint32_t                flags)
557 {
558         struct xfs_da_args      args = {
559                 .dp             = XFS_I(inode),
560                 .attr_filter    = xfs_attr_filter(flags),
561                 .name           = name,
562                 .namelen        = strlen(name),
563         };
564         int                     error;
565
566         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
567                 return -EPERM;
568
569         if (ubuf) {
570                 if (len > XFS_XATTR_SIZE_MAX)
571                         return -EINVAL;
572                 args.value = memdup_user(ubuf, len);
573                 if (IS_ERR(args.value))
574                         return PTR_ERR(args.value);
575                 args.valuelen = len;
576         }
577
578         error = xfs_attr_change(&args, xfs_xattr_flags(flags, args.value));
579         if (!error && (flags & XFS_IOC_ATTR_ROOT))
580                 xfs_forget_acl(inode, name);
581         kfree(args.value);
582         return error;
583 }
584
585 int
586 xfs_ioc_attrmulti_one(
587         struct file             *parfilp,
588         struct inode            *inode,
589         uint32_t                opcode,
590         void __user             *uname,
591         void __user             *value,
592         uint32_t                *len,
593         uint32_t                flags)
594 {
595         unsigned char           *name;
596         int                     error;
597
598         if ((flags & XFS_IOC_ATTR_ROOT) && (flags & XFS_IOC_ATTR_SECURE))
599                 return -EINVAL;
600
601         name = strndup_user(uname, MAXNAMELEN);
602         if (IS_ERR(name))
603                 return PTR_ERR(name);
604
605         switch (opcode) {
606         case ATTR_OP_GET:
607                 error = xfs_attrmulti_attr_get(inode, name, value, len, flags);
608                 break;
609         case ATTR_OP_REMOVE:
610                 value = NULL;
611                 *len = 0;
612                 fallthrough;
613         case ATTR_OP_SET:
614                 error = mnt_want_write_file(parfilp);
615                 if (error)
616                         break;
617                 error = xfs_attrmulti_attr_set(inode, name, value, *len, flags);
618                 mnt_drop_write_file(parfilp);
619                 break;
620         default:
621                 error = -EINVAL;
622                 break;
623         }
624
625         kfree(name);
626         return error;
627 }
628
629 int
630 xfs_attrmulti_by_handle(
631         struct file             *parfilp,
632         void                    __user *arg)
633 {
634         int                     error;
635         xfs_attr_multiop_t      *ops;
636         xfs_fsop_attrmulti_handlereq_t am_hreq;
637         struct dentry           *dentry;
638         unsigned int            i, size;
639
640         if (!capable(CAP_SYS_ADMIN))
641                 return -EPERM;
642         if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t)))
643                 return -EFAULT;
644
645         /* overflow check */
646         if (am_hreq.opcount >= INT_MAX / sizeof(xfs_attr_multiop_t))
647                 return -E2BIG;
648
649         dentry = xfs_handlereq_to_dentry(parfilp, &am_hreq.hreq);
650         if (IS_ERR(dentry))
651                 return PTR_ERR(dentry);
652
653         error = -E2BIG;
654         size = am_hreq.opcount * sizeof(xfs_attr_multiop_t);
655         if (!size || size > 16 * PAGE_SIZE)
656                 goto out_dput;
657
658         ops = memdup_user(am_hreq.ops, size);
659         if (IS_ERR(ops)) {
660                 error = PTR_ERR(ops);
661                 goto out_dput;
662         }
663
664         error = 0;
665         for (i = 0; i < am_hreq.opcount; i++) {
666                 ops[i].am_error = xfs_ioc_attrmulti_one(parfilp,
667                                 d_inode(dentry), ops[i].am_opcode,
668                                 ops[i].am_attrname, ops[i].am_attrvalue,
669                                 &ops[i].am_length, ops[i].am_flags);
670         }
671
672         if (copy_to_user(am_hreq.ops, ops, size))
673                 error = -EFAULT;
674
675         kfree(ops);
676  out_dput:
677         dput(dentry);
678         return error;
679 }
680
681 struct xfs_getparents_ctx {
682         struct xfs_attr_list_context    context;
683         struct xfs_getparents_by_handle gph;
684
685         /* File to target */
686         struct xfs_inode                *ip;
687
688         /* Internal buffer where we format records */
689         void                            *krecords;
690
691         /* Last record filled out */
692         struct xfs_getparents_rec       *lastrec;
693
694         unsigned int                    count;
695 };
696
697 static inline unsigned int
698 xfs_getparents_rec_sizeof(
699         unsigned int            namelen)
700 {
701         return round_up(sizeof(struct xfs_getparents_rec) + namelen + 1,
702                         sizeof(uint64_t));
703 }
704
705 static void
706 xfs_getparents_put_listent(
707         struct xfs_attr_list_context    *context,
708         int                             flags,
709         unsigned char                   *name,
710         int                             namelen,
711         void                            *value,
712         int                             valuelen)
713 {
714         struct xfs_getparents_ctx       *gpx =
715                 container_of(context, struct xfs_getparents_ctx, context);
716         struct xfs_inode                *ip = context->dp;
717         struct xfs_mount                *mp = ip->i_mount;
718         struct xfs_getparents           *gp = &gpx->gph.gph_request;
719         struct xfs_getparents_rec       *gpr = gpx->krecords + context->firstu;
720         unsigned short                  reclen =
721                 xfs_getparents_rec_sizeof(namelen);
722         xfs_ino_t                       ino;
723         uint32_t                        gen;
724         int                             error;
725
726         if (!(flags & XFS_ATTR_PARENT))
727                 return;
728
729         error = xfs_parent_from_attr(mp, flags, name, namelen, value, valuelen,
730                         &ino, &gen);
731         if (error) {
732                 xfs_inode_mark_sick(ip, XFS_SICK_INO_PARENT);
733                 context->seen_enough = -EFSCORRUPTED;
734                 return;
735         }
736
737         /*
738          * We found a parent pointer, but we've filled up the buffer.  Signal
739          * to the caller that we did /not/ reach the end of the parent pointer
740          * recordset.
741          */
742         if (context->firstu > context->bufsize - reclen) {
743                 context->seen_enough = 1;
744                 return;
745         }
746
747         /* Format the parent pointer directly into the caller buffer. */
748         gpr->gpr_reclen = reclen;
749         xfs_filehandle_init(mp, ino, gen, &gpr->gpr_parent);
750         memcpy(gpr->gpr_name, name, namelen);
751         gpr->gpr_name[namelen] = 0;
752
753         trace_xfs_getparents_put_listent(ip, gp, context, gpr);
754
755         context->firstu += reclen;
756         gpx->count++;
757         gpx->lastrec = gpr;
758 }
759
760 /* Expand the last record to fill the rest of the caller's buffer. */
761 static inline void
762 xfs_getparents_expand_lastrec(
763         struct xfs_getparents_ctx       *gpx)
764 {
765         struct xfs_getparents           *gp = &gpx->gph.gph_request;
766         struct xfs_getparents_rec       *gpr = gpx->lastrec;
767
768         if (!gpx->lastrec)
769                 gpr = gpx->krecords;
770
771         gpr->gpr_reclen = gp->gp_bufsize - ((void *)gpr - gpx->krecords);
772
773         trace_xfs_getparents_expand_lastrec(gpx->ip, gp, &gpx->context, gpr);
774 }
775
776 static inline void __user *u64_to_uptr(u64 val)
777 {
778         return (void __user *)(uintptr_t)val;
779 }
780
781 /* Retrieve the parent pointers for a given inode. */
782 STATIC int
783 xfs_getparents(
784         struct xfs_getparents_ctx       *gpx)
785 {
786         struct xfs_getparents           *gp = &gpx->gph.gph_request;
787         struct xfs_inode                *ip = gpx->ip;
788         struct xfs_mount                *mp = ip->i_mount;
789         size_t                          bufsize;
790         int                             error;
791
792         /* Check size of buffer requested by user */
793         if (gp->gp_bufsize > XFS_XATTR_LIST_MAX)
794                 return -ENOMEM;
795         if (gp->gp_bufsize < xfs_getparents_rec_sizeof(1))
796                 return -EINVAL;
797
798         if (gp->gp_iflags & ~XFS_GETPARENTS_IFLAGS_ALL)
799                 return -EINVAL;
800         if (gp->gp_reserved)
801                 return -EINVAL;
802
803         bufsize = round_down(gp->gp_bufsize, sizeof(uint64_t));
804         gpx->krecords = kvzalloc(bufsize, GFP_KERNEL);
805         if (!gpx->krecords) {
806                 bufsize = min(bufsize, PAGE_SIZE);
807                 gpx->krecords = kvzalloc(bufsize, GFP_KERNEL);
808                 if (!gpx->krecords)
809                         return -ENOMEM;
810         }
811
812         gpx->context.dp = ip;
813         gpx->context.resynch = 1;
814         gpx->context.put_listent = xfs_getparents_put_listent;
815         gpx->context.bufsize = bufsize;
816         /* firstu is used to track the bytes filled in the buffer */
817         gpx->context.firstu = 0;
818
819         /* Copy the cursor provided by caller */
820         memcpy(&gpx->context.cursor, &gp->gp_cursor,
821                         sizeof(struct xfs_attrlist_cursor));
822         gpx->count = 0;
823         gp->gp_oflags = 0;
824
825         trace_xfs_getparents_begin(ip, gp, &gpx->context.cursor);
826
827         error = xfs_attr_list(&gpx->context);
828         if (error)
829                 goto out_free_buf;
830         if (gpx->context.seen_enough < 0) {
831                 error = gpx->context.seen_enough;
832                 goto out_free_buf;
833         }
834         xfs_getparents_expand_lastrec(gpx);
835
836         /* Update the caller with the current cursor position */
837         memcpy(&gp->gp_cursor, &gpx->context.cursor,
838                         sizeof(struct xfs_attrlist_cursor));
839
840         /* Is this the root directory? */
841         if (ip->i_ino == mp->m_sb.sb_rootino)
842                 gp->gp_oflags |= XFS_GETPARENTS_OFLAG_ROOT;
843
844         if (gpx->context.seen_enough == 0) {
845                 /*
846                  * If we did not run out of buffer space, then we reached the
847                  * end of the pptr recordset, so set the DONE flag.
848                  */
849                 gp->gp_oflags |= XFS_GETPARENTS_OFLAG_DONE;
850         } else if (gpx->count == 0) {
851                 /*
852                  * If we ran out of buffer space before copying any parent
853                  * pointers at all, the caller's buffer was too short.  Tell
854                  * userspace that, erm, the message is too long.
855                  */
856                 error = -EMSGSIZE;
857                 goto out_free_buf;
858         }
859
860         trace_xfs_getparents_end(ip, gp, &gpx->context.cursor);
861
862         ASSERT(gpx->context.firstu <= gpx->gph.gph_request.gp_bufsize);
863
864         /* Copy the records to userspace. */
865         if (copy_to_user(u64_to_uptr(gpx->gph.gph_request.gp_buffer),
866                                 gpx->krecords, gpx->context.firstu))
867                 error = -EFAULT;
868
869 out_free_buf:
870         kvfree(gpx->krecords);
871         gpx->krecords = NULL;
872         return error;
873 }
874
875 /* Retrieve the parents of this file and pass them back to userspace. */
876 int
877 xfs_ioc_getparents(
878         struct file                     *file,
879         struct xfs_getparents __user    *ureq)
880 {
881         struct xfs_getparents_ctx       gpx = {
882                 .ip                     = XFS_I(file_inode(file)),
883         };
884         struct xfs_getparents           *kreq = &gpx.gph.gph_request;
885         struct xfs_mount                *mp = gpx.ip->i_mount;
886         int                             error;
887
888         if (!capable(CAP_SYS_ADMIN))
889                 return -EPERM;
890         if (!xfs_has_parent(mp))
891                 return -EOPNOTSUPP;
892         if (copy_from_user(kreq, ureq, sizeof(*kreq)))
893                 return -EFAULT;
894
895         error = xfs_getparents(&gpx);
896         if (error)
897                 return error;
898
899         if (copy_to_user(ureq, kreq, sizeof(*kreq)))
900                 return -EFAULT;
901
902         return 0;
903 }
904
905 /* Retrieve the parents of this file handle and pass them back to userspace. */
906 int
907 xfs_ioc_getparents_by_handle(
908         struct file                     *file,
909         struct xfs_getparents_by_handle __user  *ureq)
910 {
911         struct xfs_getparents_ctx       gpx = { };
912         struct xfs_inode                *ip = XFS_I(file_inode(file));
913         struct xfs_mount                *mp = ip->i_mount;
914         struct xfs_getparents_by_handle *kreq = &gpx.gph;
915         struct xfs_handle               *handle = &kreq->gph_handle;
916         int                             error;
917
918         if (!capable(CAP_SYS_ADMIN))
919                 return -EPERM;
920         if (!xfs_has_parent(mp))
921                 return -EOPNOTSUPP;
922         if (copy_from_user(kreq, ureq, sizeof(*kreq)))
923                 return -EFAULT;
924
925         /*
926          * We don't use exportfs_decode_fh because it does too much work here.
927          * If the handle refers to a directory, the exportfs code will walk
928          * upwards through the directory tree to connect the dentries to the
929          * root directory dentry.  For GETPARENTS we don't care about that
930          * because we're not actually going to open a file descriptor; we only
931          * want to open an inode and read its parent pointers.
932          *
933          * Note that xfs_scrub uses GETPARENTS to log that it will try to fix a
934          * corrupted file's metadata.  For this usecase we would really rather
935          * userspace single-step the path reconstruction to avoid loops or
936          * other strange things if the directory tree is corrupt.
937          */
938         gpx.ip = xfs_khandle_to_inode(file, handle);
939         if (IS_ERR(gpx.ip))
940                 return PTR_ERR(gpx.ip);
941
942         error = xfs_getparents(&gpx);
943         if (error)
944                 goto out_rele;
945
946         if (copy_to_user(ureq, kreq, sizeof(*kreq)))
947                 error = -EFAULT;
948
949 out_rele:
950         xfs_irele(gpx.ip);
951         return error;
952 }
This page took 0.11436 seconds and 4 git commands to generate.