]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - fs/shiftfs.c
UBUNTU: SAUCE: shiftfs: uid/gid shifting bind mount
[mirror_ubuntu-jammy-kernel.git] / fs / shiftfs.c
CommitLineData
aa269008
JB
1#include <linux/cred.h>
2#include <linux/mount.h>
3#include <linux/file.h>
4#include <linux/fs.h>
5#include <linux/namei.h>
6#include <linux/module.h>
7#include <linux/kernel.h>
8#include <linux/magic.h>
9#include <linux/parser.h>
10#include <linux/seq_file.h>
11#include <linux/statfs.h>
12#include <linux/slab.h>
13#include <linux/user_namespace.h>
14#include <linux/uidgid.h>
15#include <linux/xattr.h>
16
17struct shiftfs_super_info {
18 struct vfsmount *mnt;
19 struct user_namespace *userns;
20 bool mark;
21};
22
23static struct inode *shiftfs_new_inode(struct super_block *sb, umode_t mode,
24 struct dentry *dentry);
25
26enum {
27 OPT_MARK,
28 OPT_LAST,
29};
30
31/* global filesystem options */
32static const match_table_t tokens = {
33 { OPT_MARK, "mark" },
34 { OPT_LAST, NULL }
35};
36
37static const struct cred *shiftfs_get_up_creds(struct super_block *sb)
38{
39 struct shiftfs_super_info *ssi = sb->s_fs_info;
40 struct cred *cred = prepare_creds();
41
42 if (!cred)
43 return NULL;
44
45 cred->fsuid = KUIDT_INIT(from_kuid(sb->s_user_ns, cred->fsuid));
46 cred->fsgid = KGIDT_INIT(from_kgid(sb->s_user_ns, cred->fsgid));
47 put_user_ns(cred->user_ns);
48 cred->user_ns = get_user_ns(ssi->userns);
49
50 return cred;
51}
52
53static const struct cred *shiftfs_new_creds(const struct cred **newcred,
54 struct super_block *sb)
55{
56 const struct cred *cred = shiftfs_get_up_creds(sb);
57
58 *newcred = cred;
59
60 if (cred)
61 cred = override_creds(cred);
62 else
63 printk(KERN_ERR "shiftfs: Credential override failed: no memory\n");
64
65 return cred;
66}
67
68static void shiftfs_old_creds(const struct cred *oldcred,
69 const struct cred **newcred)
70{
71 if (!*newcred)
72 return;
73
74 revert_creds(oldcred);
75 put_cred(*newcred);
76}
77
78static int shiftfs_parse_options(struct shiftfs_super_info *ssi, char *options)
79{
80 char *p;
81 substring_t args[MAX_OPT_ARGS];
82
83 ssi->mark = false;
84
85 while ((p = strsep(&options, ",")) != NULL) {
86 int token;
87
88 if (!*p)
89 continue;
90
91 token = match_token(p, tokens, args);
92 switch (token) {
93 case OPT_MARK:
94 ssi->mark = true;
95 break;
96 default:
97 return -EINVAL;
98 }
99 }
100 return 0;
101}
102
103static void shiftfs_d_release(struct dentry *dentry)
104{
105 struct dentry *real = dentry->d_fsdata;
106
107 dput(real);
108}
109
110static struct dentry *shiftfs_d_real(struct dentry *dentry,
111 const struct inode *inode)
112{
113 struct dentry *real = dentry->d_fsdata;
114
115 if (unlikely(real->d_flags & DCACHE_OP_REAL))
116 return real->d_op->d_real(real, real->d_inode);
117
118 return real;
119}
120
121static int shiftfs_d_weak_revalidate(struct dentry *dentry, unsigned int flags)
122{
123 struct dentry *real = dentry->d_fsdata;
124
125 if (d_unhashed(real))
126 return 0;
127
128 if (!(real->d_flags & DCACHE_OP_WEAK_REVALIDATE))
129 return 1;
130
131 return real->d_op->d_weak_revalidate(real, flags);
132}
133
134static int shiftfs_d_revalidate(struct dentry *dentry, unsigned int flags)
135{
136 struct dentry *real = dentry->d_fsdata;
137 int ret;
138
139 if (d_unhashed(real))
140 return 0;
141
142 /*
143 * inode state of underlying changed from positive to negative
144 * or vice versa; force a lookup to update our view
145 */
146 if (d_is_negative(real) != d_is_negative(dentry))
147 return 0;
148
149 if (!(real->d_flags & DCACHE_OP_REVALIDATE))
150 return 1;
151
152 ret = real->d_op->d_revalidate(real, flags);
153
154 if (ret == 0 && !(flags & LOOKUP_RCU))
155 d_invalidate(real);
156
157 return ret;
158}
159
160static const struct dentry_operations shiftfs_dentry_ops = {
161 .d_release = shiftfs_d_release,
162 .d_real = shiftfs_d_real,
163 .d_revalidate = shiftfs_d_revalidate,
164 .d_weak_revalidate = shiftfs_d_weak_revalidate,
165};
166
167static int shiftfs_readlink(struct dentry *dentry, char __user *data,
168 int flags)
169{
170 struct dentry *real = dentry->d_fsdata;
171 const struct inode_operations *iop = real->d_inode->i_op;
172
173 if (iop->readlink)
174 return iop->readlink(real, data, flags);
175
176 return -EINVAL;
177}
178
179static const char *shiftfs_get_link(struct dentry *dentry, struct inode *inode,
180 struct delayed_call *done)
181{
182 if (dentry) {
183 struct dentry *real = dentry->d_fsdata;
184 struct inode *reali = real->d_inode;
185 const struct inode_operations *iop = reali->i_op;
186 const char *res = ERR_PTR(-EPERM);
187
188 if (iop->get_link)
189 res = iop->get_link(real, reali, done);
190
191 return res;
192 } else {
193 /* RCU lookup not supported */
194 return ERR_PTR(-ECHILD);
195 }
196}
197
198static int shiftfs_setxattr(struct dentry *dentry, struct inode *inode,
199 const char *name, const void *value,
200 size_t size, int flags)
201{
202 struct dentry *real = dentry->d_fsdata;
203 int err = -EOPNOTSUPP;
204 const struct cred *oldcred, *newcred;
205
206 oldcred = shiftfs_new_creds(&newcred, dentry->d_sb);
207 err = vfs_setxattr(real, name, value, size, flags);
208 shiftfs_old_creds(oldcred, &newcred);
209
210 return err;
211}
212
213static int shiftfs_xattr_get(const struct xattr_handler *handler,
214 struct dentry *dentry, struct inode *inode,
215 const char *name, void *value, size_t size)
216{
217 struct dentry *real = dentry->d_fsdata;
218 int err;
219 const struct cred *oldcred, *newcred;
220
221 oldcred = shiftfs_new_creds(&newcred, dentry->d_sb);
222 err = vfs_getxattr(real, name, value, size);
223 shiftfs_old_creds(oldcred, &newcred);
224
225 return err;
226}
227
228static ssize_t shiftfs_listxattr(struct dentry *dentry, char *list,
229 size_t size)
230{
231 struct dentry *real = dentry->d_fsdata;
232 int err;
233 const struct cred *oldcred, *newcred;
234
235 oldcred = shiftfs_new_creds(&newcred, dentry->d_sb);
236 err = vfs_listxattr(real, list, size);
237 shiftfs_old_creds(oldcred, &newcred);
238
239 return err;
240}
241
242static int shiftfs_removexattr(struct dentry *dentry, const char *name)
243{
244 struct dentry *real = dentry->d_fsdata;
245 int err;
246 const struct cred *oldcred, *newcred;
247
248 oldcred = shiftfs_new_creds(&newcred, dentry->d_sb);
249 err = vfs_removexattr(real, name);
250 shiftfs_old_creds(oldcred, &newcred);
251
252 return err;
253}
254
255static int shiftfs_xattr_set(const struct xattr_handler *handler,
256 struct dentry *dentry, struct inode *inode,
257 const char *name, const void *value, size_t size,
258 int flags)
259{
260 if (!value)
261 return shiftfs_removexattr(dentry, name);
262 return shiftfs_setxattr(dentry, inode, name, value, size, flags);
263}
264
265static void shiftfs_fill_inode(struct inode *inode, struct dentry *dentry)
266{
267 struct inode *reali;
268
269 if (!dentry)
270 return;
271
272 reali = dentry->d_inode;
273
274 if (!reali->i_op->get_link)
275 inode->i_opflags |= IOP_NOFOLLOW;
276
277 inode->i_mapping = reali->i_mapping;
278 inode->i_private = dentry;
279}
280
281static int shiftfs_make_object(struct inode *dir, struct dentry *dentry,
282 umode_t mode, const char *symlink,
283 struct dentry *hardlink, bool excl)
284{
285 struct dentry *real = dir->i_private, *new = dentry->d_fsdata;
286 struct inode *reali = real->d_inode, *newi;
287 const struct inode_operations *iop = reali->i_op;
288 int err;
289 const struct cred *oldcred, *newcred;
290 bool op_ok = false;
291
292 if (hardlink) {
293 op_ok = iop->link;
294 } else {
295 switch (mode & S_IFMT) {
296 case S_IFDIR:
297 op_ok = iop->mkdir;
298 break;
299 case S_IFREG:
300 op_ok = iop->create;
301 break;
302 case S_IFLNK:
303 op_ok = iop->symlink;
304 }
305 }
306 if (!op_ok)
307 return -EINVAL;
308
309
310 newi = shiftfs_new_inode(dentry->d_sb, mode, NULL);
311 if (!newi)
312 return -ENOMEM;
313
314 oldcred = shiftfs_new_creds(&newcred, dentry->d_sb);
315
316 inode_lock_nested(reali, I_MUTEX_PARENT);
317
318 err = -EINVAL; /* shut gcc up about uninit var */
319 if (hardlink) {
320 struct dentry *realhardlink = hardlink->d_fsdata;
321
322 err = vfs_link(realhardlink, reali, new, NULL);
323 } else {
324 switch (mode & S_IFMT) {
325 case S_IFDIR:
326 err = vfs_mkdir(reali, new, mode);
327 break;
328 case S_IFREG:
329 err = vfs_create(reali, new, mode, excl);
330 break;
331 case S_IFLNK:
332 err = vfs_symlink(reali, new, symlink);
333 }
334 }
335
336 shiftfs_old_creds(oldcred, &newcred);
337
338 if (err)
339 goto out_dput;
340
341 shiftfs_fill_inode(newi, new);
342
343 d_instantiate(dentry, newi);
344
345 new = NULL;
346 newi = NULL;
347
348 out_dput:
349 dput(new);
350 iput(newi);
351 inode_unlock(reali);
352
353 return err;
354}
355
356static int shiftfs_create(struct inode *dir, struct dentry *dentry,
357 umode_t mode, bool excl)
358{
359 mode |= S_IFREG;
360
361 return shiftfs_make_object(dir, dentry, mode, NULL, NULL, excl);
362}
363
364static int shiftfs_mkdir(struct inode *dir, struct dentry *dentry,
365 umode_t mode)
366{
367 mode |= S_IFDIR;
368
369 return shiftfs_make_object(dir, dentry, mode, NULL, NULL, false);
370}
371
372static int shiftfs_link(struct dentry *hardlink, struct inode *dir,
373 struct dentry *dentry)
374{
375 return shiftfs_make_object(dir, dentry, 0, NULL, hardlink, false);
376}
377
378static int shiftfs_symlink(struct inode *dir, struct dentry *dentry,
379 const char *symlink)
380{
381 return shiftfs_make_object(dir, dentry, S_IFLNK, symlink, NULL, false);
382}
383
384static int shiftfs_rm(struct inode *dir, struct dentry *dentry, bool rmdir)
385{
386 struct dentry *real = dir->i_private, *new = dentry->d_fsdata;
387 struct inode *reali = real->d_inode;
388 int err;
389 const struct cred *oldcred, *newcred;
390
391 inode_lock_nested(reali, I_MUTEX_PARENT);
392
393 oldcred = shiftfs_new_creds(&newcred, dentry->d_sb);
394
395 if (rmdir)
396 err = vfs_rmdir(reali, new);
397 else
398 err = vfs_unlink(reali, new, NULL);
399
400 shiftfs_old_creds(oldcred, &newcred);
401 inode_unlock(reali);
402
403 return err;
404}
405
406static int shiftfs_unlink(struct inode *dir, struct dentry *dentry)
407{
408 return shiftfs_rm(dir, dentry, false);
409}
410
411static int shiftfs_rmdir(struct inode *dir, struct dentry *dentry)
412{
413 return shiftfs_rm(dir, dentry, true);
414}
415
416static int shiftfs_rename(struct inode *olddir, struct dentry *old,
417 struct inode *newdir, struct dentry *new,
418 unsigned int flags)
419{
420 struct dentry *rodd = olddir->i_private, *rndd = newdir->i_private,
421 *realold = old->d_fsdata,
422 *realnew = new->d_fsdata, *trap;
423 struct inode *realolddir = rodd->d_inode, *realnewdir = rndd->d_inode;
424 int err = -EINVAL;
425 const struct cred *oldcred, *newcred;
426
427 trap = lock_rename(rndd, rodd);
428
429 if (trap == realold || trap == realnew)
430 goto out_unlock;
431
432 oldcred = shiftfs_new_creds(&newcred, old->d_sb);
433
434 err = vfs_rename(realolddir, realold, realnewdir,
435 realnew, NULL, flags);
436
437 shiftfs_old_creds(oldcred, &newcred);
438
439 out_unlock:
440 unlock_rename(rndd, rodd);
441
442 return err;
443}
444
445static struct dentry *shiftfs_lookup(struct inode *dir, struct dentry *dentry,
446 unsigned int flags)
447{
448 struct dentry *real = dir->i_private, *new;
449 struct inode *reali = real->d_inode, *newi;
450 const struct cred *oldcred, *newcred;
451
452 inode_lock(reali);
453 oldcred = shiftfs_new_creds(&newcred, dentry->d_sb);
454 new = lookup_one_len(dentry->d_name.name, real, dentry->d_name.len);
455 shiftfs_old_creds(oldcred, &newcred);
456 inode_unlock(reali);
457
458 if (IS_ERR(new))
459 return new;
460
461 dentry->d_fsdata = new;
462
463 newi = NULL;
464 if (!new->d_inode)
465 goto out;
466
467 newi = shiftfs_new_inode(dentry->d_sb, new->d_inode->i_mode, new);
468 if (!newi) {
469 dput(new);
470 return ERR_PTR(-ENOMEM);
471 }
472
473 out:
474 return d_splice_alias(newi, dentry);
475}
476
477static int shiftfs_permission(struct inode *inode, int mask)
478{
479 struct dentry *real = inode->i_private;
480 struct inode *reali = real->d_inode;
481 const struct inode_operations *iop = reali->i_op;
482 int err;
483 const struct cred *oldcred, *newcred;
484
485 if (mask & MAY_NOT_BLOCK)
486 return -ECHILD;
487
488 oldcred = shiftfs_new_creds(&newcred, inode->i_sb);
489 if (iop->permission)
490 err = iop->permission(reali, mask);
491 else
492 err = generic_permission(reali, mask);
493 shiftfs_old_creds(oldcred, &newcred);
494
495 return err;
496}
497
498static int shiftfs_setattr(struct dentry *dentry, struct iattr *attr)
499{
500 struct dentry *real = dentry->d_fsdata;
501 struct inode *reali = real->d_inode;
502 const struct inode_operations *iop = reali->i_op;
503 struct iattr newattr = *attr;
504 const struct cred *oldcred, *newcred;
505 struct super_block *sb = dentry->d_sb;
506 int err;
507
508 newattr.ia_uid = KUIDT_INIT(from_kuid(sb->s_user_ns, attr->ia_uid));
509 newattr.ia_gid = KGIDT_INIT(from_kgid(sb->s_user_ns, attr->ia_gid));
510
511 oldcred = shiftfs_new_creds(&newcred, dentry->d_sb);
512 inode_lock(reali);
513 if (iop->setattr)
514 err = iop->setattr(real, &newattr);
515 else
516 err = simple_setattr(real, &newattr);
517 inode_unlock(reali);
518 shiftfs_old_creds(oldcred, &newcred);
519
520 if (err)
521 return err;
522
523 /* all OK, reflect the change on our inode */
524 setattr_copy(d_inode(dentry), attr);
525 return 0;
526}
527
528static int shiftfs_getattr(const struct path *path, struct kstat *stat,
529 u32 request_mask, unsigned int query_flags)
530{
531 struct inode *inode = path->dentry->d_inode;
532 struct dentry *real = path->dentry->d_fsdata;
533 struct inode *reali = real->d_inode;
534 const struct inode_operations *iop = reali->i_op;
535 struct path newpath = { .mnt = path->dentry->d_sb->s_fs_info, .dentry = real };
536 int err = 0;
537
538 if (iop->getattr)
539 err = iop->getattr(&newpath, stat, request_mask, query_flags);
540 else
541 generic_fillattr(reali, stat);
542
543 if (err)
544 return err;
545
546 /* transform the underlying id */
547 stat->uid = make_kuid(inode->i_sb->s_user_ns, __kuid_val(stat->uid));
548 stat->gid = make_kgid(inode->i_sb->s_user_ns, __kgid_val(stat->gid));
549 return 0;
550}
551
552static const struct inode_operations shiftfs_inode_ops = {
553 .lookup = shiftfs_lookup,
554 .getattr = shiftfs_getattr,
555 .setattr = shiftfs_setattr,
556 .permission = shiftfs_permission,
557 .mkdir = shiftfs_mkdir,
558 .symlink = shiftfs_symlink,
559 .get_link = shiftfs_get_link,
560 .readlink = shiftfs_readlink,
561 .unlink = shiftfs_unlink,
562 .rmdir = shiftfs_rmdir,
563 .rename = shiftfs_rename,
564 .link = shiftfs_link,
565 .create = shiftfs_create,
566 .mknod = NULL, /* no special files currently */
567 .listxattr = shiftfs_listxattr,
568};
569
570static struct inode *shiftfs_new_inode(struct super_block *sb, umode_t mode,
571 struct dentry *dentry)
572{
573 struct inode *inode;
574
575 inode = new_inode(sb);
576 if (!inode)
577 return NULL;
578
579 /*
580 * our inode is completely vestigial. All lookups, getattr
581 * and permission checks are done on the underlying inode, so
582 * what the user sees is entirely from the underlying inode.
583 */
584 mode &= S_IFMT;
585
586 inode->i_ino = get_next_ino();
587 inode->i_mode = mode;
588 inode->i_flags |= S_NOATIME | S_NOCMTIME;
589
590 inode->i_op = &shiftfs_inode_ops;
591
592 shiftfs_fill_inode(inode, dentry);
593
594 return inode;
595}
596
597static int shiftfs_show_options(struct seq_file *m, struct dentry *dentry)
598{
599 struct super_block *sb = dentry->d_sb;
600 struct shiftfs_super_info *ssi = sb->s_fs_info;
601
602 if (ssi->mark)
603 seq_show_option(m, "mark", NULL);
604
605 return 0;
606}
607
608static int shiftfs_statfs(struct dentry *dentry, struct kstatfs *buf)
609{
610 struct super_block *sb = dentry->d_sb;
611 struct shiftfs_super_info *ssi = sb->s_fs_info;
612 struct dentry *root = sb->s_root;
613 struct dentry *realroot = root->d_fsdata;
614 struct path realpath = { .mnt = ssi->mnt, .dentry = realroot };
615 int err;
616
617 err = vfs_statfs(&realpath, buf);
618 if (err)
619 return err;
620
621 buf->f_type = sb->s_magic;
622
623 return 0;
624}
625
626static void shiftfs_put_super(struct super_block *sb)
627{
628 struct shiftfs_super_info *ssi = sb->s_fs_info;
629
630 mntput(ssi->mnt);
631 put_user_ns(ssi->userns);
632 kfree(ssi);
633}
634
635static const struct xattr_handler shiftfs_xattr_handler = {
636 .prefix = "",
637 .get = shiftfs_xattr_get,
638 .set = shiftfs_xattr_set,
639};
640
641const struct xattr_handler *shiftfs_xattr_handlers[] = {
642 &shiftfs_xattr_handler,
643 NULL
644};
645
646static const struct super_operations shiftfs_super_ops = {
647 .put_super = shiftfs_put_super,
648 .show_options = shiftfs_show_options,
649 .statfs = shiftfs_statfs,
650};
651
652struct shiftfs_data {
653 void *data;
654 const char *path;
655};
656
657static int shiftfs_fill_super(struct super_block *sb, void *raw_data,
658 int silent)
659{
660 struct shiftfs_data *data = raw_data;
661 char *name = kstrdup(data->path, GFP_KERNEL);
662 int err = -ENOMEM;
663 struct shiftfs_super_info *ssi = NULL;
664 struct path path;
665 struct dentry *dentry;
666
667 if (!name)
668 goto out;
669
670 ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
671 if (!ssi)
672 goto out;
673
674 err = -EPERM;
675 err = shiftfs_parse_options(ssi, data->data);
676 if (err)
677 goto out;
678
679 /* to mark a mount point, must be real root */
680 if (ssi->mark && !capable(CAP_SYS_ADMIN))
681 goto out;
682
683 /* else to mount a mark, must be userns admin */
684 if (!ssi->mark && !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
685 goto out;
686
687 err = kern_path(name, LOOKUP_FOLLOW, &path);
688 if (err)
689 goto out;
690
691 err = -EPERM;
692
693 if (!S_ISDIR(path.dentry->d_inode->i_mode)) {
694 err = -ENOTDIR;
695 goto out_put;
696 }
697
698 sb->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1;
699 if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) {
700 printk(KERN_ERR "shiftfs: maximum stacking depth exceeded\n");
701 err = -EINVAL;
702 goto out_put;
703 }
704
705 if (ssi->mark) {
706 /*
707 * this part is visible unshifted, so make sure no
708 * executables that could be used to give suid
709 * privileges
710 */
711 sb->s_iflags = SB_I_NOEXEC;
712 ssi->mnt = path.mnt;
713 dentry = path.dentry;
714 } else {
715 struct shiftfs_super_info *mp_ssi;
716
717 /*
718 * this leg executes if we're admin capable in
719 * the namespace, so be very careful
720 */
721 if (path.dentry->d_sb->s_magic != SHIFTFS_MAGIC)
722 goto out_put;
723 mp_ssi = path.dentry->d_sb->s_fs_info;
724 if (!mp_ssi->mark)
725 goto out_put;
726 ssi->mnt = mntget(mp_ssi->mnt);
727 dentry = dget(path.dentry->d_fsdata);
728 path_put(&path);
729 }
730 ssi->userns = get_user_ns(dentry->d_sb->s_user_ns);
731 sb->s_fs_info = ssi;
732 sb->s_magic = SHIFTFS_MAGIC;
733 sb->s_op = &shiftfs_super_ops;
734 sb->s_xattr = shiftfs_xattr_handlers;
735 sb->s_d_op = &shiftfs_dentry_ops;
736 sb->s_root = d_make_root(shiftfs_new_inode(sb, S_IFDIR, dentry));
737 sb->s_root->d_fsdata = dentry;
738
739 return 0;
740
741 out_put:
742 path_put(&path);
743 out:
744 kfree(name);
745 kfree(ssi);
746 return err;
747}
748
749static struct dentry *shiftfs_mount(struct file_system_type *fs_type,
750 int flags, const char *dev_name, void *data)
751{
752 struct shiftfs_data d = { data, dev_name };
753
754 return mount_nodev(fs_type, flags, &d, shiftfs_fill_super);
755}
756
757static struct file_system_type shiftfs_type = {
758 .owner = THIS_MODULE,
759 .name = "shiftfs",
760 .mount = shiftfs_mount,
761 .kill_sb = kill_anon_super,
762 .fs_flags = FS_USERNS_MOUNT,
763};
764
765static int __init shiftfs_init(void)
766{
767 return register_filesystem(&shiftfs_type);
768}
769
770static void __exit shiftfs_exit(void)
771{
772 unregister_filesystem(&shiftfs_type);
773}
774
775MODULE_ALIAS_FS("shiftfs");
776MODULE_AUTHOR("James Bottomley");
777MODULE_DESCRIPTION("uid/gid shifting bind filesystem");
778MODULE_LICENSE("GPL v2");
779module_init(shiftfs_init)
780module_exit(shiftfs_exit)