History

Merge tag 'vfs-6.15-rc1.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs mount updates from Christian Brauner: - Mount notifications The day has come where we finally provide a new api to listen for mount topology changes outside of /proc/<pid>/mountinfo. A mount namespace file descriptor can be supplied and registered with fanotify to listen for mount topology changes. Currently notifications for mount, umount and moving mounts are generated. The generated notification record contains the unique mount id of the mount. The listmount() and statmount() api can be used to query detailed information about the mount using the received unique mount id. This allows userspace to figure out exactly how the mount topology changed without having to generating diffs of /proc/<pid>/mountinfo in userspace. - Support O_PATH file descriptors with FSCONFIG_SET_FD in the new mount api - Support detached mounts in overlayfs Since last cycle we support specifying overlayfs layers via file descriptors. However, we don't allow detached mounts which means userspace cannot user file descriptors received via open_tree(OPEN_TREE_CLONE) and fsmount() directly. They have to attach them to a mount namespace via move_mount() first. This is cumbersome and means they have to undo mounts via umount(). Allow them to directly use detached mounts. - Allow to retrieve idmappings with statmount Currently it isn't possible to figure out what idmapping has been attached to an idmapped mount. Add an extension to statmount() which allows to read the idmapping from the mount. - Allow creating idmapped mounts from mounts that are already idmapped So far it isn't possible to allow the creation of idmapped mounts from already idmapped mounts as this has significant lifetime implications. Make the creation of idmapped mounts atomic by allow to pass struct mount_attr together with the open_tree_attr() system call allowing to solve these issues without complicating VFS lookup in any way. The system call has in general the benefit that creating a detached mount and applying mount attributes to it becomes an atomic operation for userspace. - Add a way to query statmount() for supported options Allow userspace to query which mount information can be retrieved through statmount(). - Allow superblock owners to force unmount * tag 'vfs-6.15-rc1.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (21 commits) umount: Allow superblock owners to force umount selftests: add tests for mount notification selinux: add FILE__WATCH_MOUNTNS samples/vfs: fix printf format string for size_t fs: allow changing idmappings fs: add kflags member to struct mount_kattr fs: add open_tree_attr() fs: add copy_mount_setattr() helper fs: add vfs_open_tree() helper statmount: add a new supported_mask field samples/vfs: add STATMOUNT_MNT_{G,U}IDMAP selftests: add tests for using detached mount with overlayfs samples/vfs: check whether flag was raised statmount: allow to retrieve idmappings uidgid: add map_id_range_up() fs: allow detached mounts in clone_private_mount() selftests/overlayfs: test specifying layers as O_PATH file descriptors fs: support O_PATH fds with FSCONFIG_SET_FD vfs: add notifications for mount attach and detach fanotify: notify on mount attach and detach ...

Linus Torvalds committed 1 year ago

Commit fd101da2 parents a79a09a e1ff7aa52 files · +1567 −175Browse files

Unified · Split

52 files
  1. arch/alpha/kernel/syscalls/syscall.tbl +1 −0
  2. arch/arm/tools/syscall.tbl +1 −0
  3. arch/arm64/tools/syscall_32.tbl +1 −0
  4. arch/m68k/kernel/syscalls/syscall.tbl +1 −0
  5. arch/microblaze/kernel/syscalls/syscall.tbl +1 −0
  6. arch/mips/kernel/syscalls/syscall_n32.tbl +1 −0
  7. arch/mips/kernel/syscalls/syscall_n64.tbl +1 −0
  8. arch/mips/kernel/syscalls/syscall_o32.tbl +1 −0
  9. arch/parisc/kernel/syscalls/syscall.tbl +1 −0
  10. arch/powerpc/kernel/syscalls/syscall.tbl +1 −0
  11. arch/s390/kernel/syscalls/syscall.tbl +1 −0
  12. arch/sh/kernel/syscalls/syscall.tbl +1 −0
  13. arch/sparc/kernel/syscalls/syscall.tbl +1 −0
  14. arch/x86/entry/syscalls/syscall_32.tbl +1 −0
  15. arch/x86/entry/syscalls/syscall_64.tbl +1 −0
  16. arch/xtensa/kernel/syscalls/syscall.tbl +1 −0
  17. fs/autofs/autofs_i.h +2 −0
  18. fs/fsopen.c +1 −1
  19. fs/internal.h +1 −0
  20. fs/mnt_idmapping.c +51 −0
  21. fs/mount.h +26 −0
  22. fs/namespace.c +363 −122
  23. fs/notify/fanotify/fanotify.c +35 −3
  24. fs/notify/fanotify/fanotify.h +18 −0
  25. fs/notify/fanotify/fanotify_user.c +75 −14
  26. fs/notify/fdinfo.c +5 −0
  27. fs/notify/fsnotify.c +40 −7
  28. fs/notify/fsnotify.h +11 −0
  29. fs/notify/mark.c +11 −3
  30. fs/pnode.c +3 −1
  31. include/linux/fanotify.h +8 −4
  32. include/linux/fsnotify.h +20 −0
  33. include/linux/fsnotify_backend.h +42 −0
  34. include/linux/mnt_idmapping.h +5 −0
  35. include/linux/syscalls.h +4 −0
  36. include/linux/uidgid.h +6 −0
  37. include/uapi/asm-generic/unistd.h +3 −1
  38. include/uapi/linux/fanotify.h +10 −0
  39. include/uapi/linux/mount.h +9 −1
  40. kernel/user_namespace.c +17 −9
  41. samples/vfs/samples-vfs.h +13 −1
  42. samples/vfs/test-list-all-mounts.c +29 −6
  43. scripts/syscall.tbl +1 −0
  44. security/selinux/hooks.c +3 −0
  45. security/selinux/include/classmap.h +1 −1
  46. tools/testing/selftests/Makefile +1 −0
  47. tools/testing/selftests/filesystems/mount-notify/.gitignore +2 −0
  48. tools/testing/selftests/filesystems/mount-notify/Makefile +6 −0
  49. tools/testing/selftests/filesystems/mount-notify/mount-notify_test.c +516 −0
  50. tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c +195 −0
  51. tools/testing/selftests/filesystems/overlayfs/wrappers.h +17 −0
  52. tools/testing/selftests/filesystems/statmount/statmount.h +1 −1
arch/alpha/kernel/syscalls/syscall.tbl+1−0
@@ -506,3 +506,4 @@ · 505 unmodified lines
506574 common getxattrat sys_getxattrat506574 common getxattrat sys_getxattrat
507575 common listxattrat sys_listxattrat507575 common listxattrat sys_listxattrat
508576 common removexattrat sys_removexattrat508576 common removexattrat sys_removexattrat
509577 common open_tree_attr sys_open_tree_attr
arch/arm/tools/syscall.tbl+1−0
@@ -481,3 +481,4 @@ · 480 unmodified lines
481464 common getxattrat sys_getxattrat481464 common getxattrat sys_getxattrat
482465 common listxattrat sys_listxattrat482465 common listxattrat sys_listxattrat
483466 common removexattrat sys_removexattrat483466 common removexattrat sys_removexattrat
484467 common open_tree_attr sys_open_tree_attr
arch/arm64/tools/syscall_32.tbl+1−0
@@ -478,3 +478,4 @@ · 477 unmodified lines
478464 common getxattrat sys_getxattrat478464 common getxattrat sys_getxattrat
479465 common listxattrat sys_listxattrat479465 common listxattrat sys_listxattrat
480466 common removexattrat sys_removexattrat480466 common removexattrat sys_removexattrat
481467 common open_tree_attr sys_open_tree_attr
arch/m68k/kernel/syscalls/syscall.tbl+1−0
@@ -466,3 +466,4 @@ · 465 unmodified lines
466464 common getxattrat sys_getxattrat466464 common getxattrat sys_getxattrat
467465 common listxattrat sys_listxattrat467465 common listxattrat sys_listxattrat
468466 common removexattrat sys_removexattrat468466 common removexattrat sys_removexattrat
469467 common open_tree_attr sys_open_tree_attr
arch/microblaze/kernel/syscalls/syscall.tbl+1−0
@@ -472,3 +472,4 @@ · 471 unmodified lines
472464 common getxattrat sys_getxattrat472464 common getxattrat sys_getxattrat
473465 common listxattrat sys_listxattrat473465 common listxattrat sys_listxattrat
474466 common removexattrat sys_removexattrat474466 common removexattrat sys_removexattrat
475467 common open_tree_attr sys_open_tree_attr
arch/mips/kernel/syscalls/syscall_n32.tbl+1−0
@@ -405,3 +405,4 @@ · 404 unmodified lines
405464 n32 getxattrat sys_getxattrat405464 n32 getxattrat sys_getxattrat
406465 n32 listxattrat sys_listxattrat406465 n32 listxattrat sys_listxattrat
407466 n32 removexattrat sys_removexattrat407466 n32 removexattrat sys_removexattrat
408467 n32 open_tree_attr sys_open_tree_attr
arch/mips/kernel/syscalls/syscall_n64.tbl+1−0
@@ -381,3 +381,4 @@ · 380 unmodified lines
381464 n64 getxattrat sys_getxattrat381464 n64 getxattrat sys_getxattrat
382465 n64 listxattrat sys_listxattrat382465 n64 listxattrat sys_listxattrat
383466 n64 removexattrat sys_removexattrat383466 n64 removexattrat sys_removexattrat
384467 n64 open_tree_attr sys_open_tree_attr
arch/mips/kernel/syscalls/syscall_o32.tbl+1−0
@@ -454,3 +454,4 @@ · 453 unmodified lines
454464 o32 getxattrat sys_getxattrat454464 o32 getxattrat sys_getxattrat
455465 o32 listxattrat sys_listxattrat455465 o32 listxattrat sys_listxattrat
456466 o32 removexattrat sys_removexattrat456466 o32 removexattrat sys_removexattrat
457467 o32 open_tree_attr sys_open_tree_attr
arch/parisc/kernel/syscalls/syscall.tbl+1−0
@@ -465,3 +465,4 @@ · 464 unmodified lines
465464 common getxattrat sys_getxattrat465464 common getxattrat sys_getxattrat
466465 common listxattrat sys_listxattrat466465 common listxattrat sys_listxattrat
467466 common removexattrat sys_removexattrat467466 common removexattrat sys_removexattrat
468467 common open_tree_attr sys_open_tree_attr
arch/powerpc/kernel/syscalls/syscall.tbl+1−0
@@ -557,3 +557,4 @@ · 556 unmodified lines
557464 common getxattrat sys_getxattrat557464 common getxattrat sys_getxattrat
558465 common listxattrat sys_listxattrat558465 common listxattrat sys_listxattrat
559466 common removexattrat sys_removexattrat559466 common removexattrat sys_removexattrat
560467 common open_tree_attr sys_open_tree_attr
arch/s390/kernel/syscalls/syscall.tbl+1−0
@@ -469,3 +469,4 @@ · 468 unmodified lines
469464 common getxattrat sys_getxattrat sys_getxattrat469464 common getxattrat sys_getxattrat sys_getxattrat
470465 common listxattrat sys_listxattrat sys_listxattrat470465 common listxattrat sys_listxattrat sys_listxattrat
471466 common removexattrat sys_removexattrat sys_removexattrat471466 common removexattrat sys_removexattrat sys_removexattrat
472467 common open_tree_attr sys_open_tree_attr sys_open_tree_attr
arch/sh/kernel/syscalls/syscall.tbl+1−0
@@ -470,3 +470,4 @@ · 469 unmodified lines
470464 common getxattrat sys_getxattrat470464 common getxattrat sys_getxattrat
471465 common listxattrat sys_listxattrat471465 common listxattrat sys_listxattrat
472466 common removexattrat sys_removexattrat472466 common removexattrat sys_removexattrat
473467 common open_tree_attr sys_open_tree_attr
arch/sparc/kernel/syscalls/syscall.tbl+1−0
@@ -512,3 +512,4 @@ · 511 unmodified lines
512464 common getxattrat sys_getxattrat512464 common getxattrat sys_getxattrat
513465 common listxattrat sys_listxattrat513465 common listxattrat sys_listxattrat
514466 common removexattrat sys_removexattrat514466 common removexattrat sys_removexattrat
515467 common open_tree_attr sys_open_tree_attr
arch/x86/entry/syscalls/syscall_32.tbl+1−0
@@ -472,3 +472,4 @@ · 471 unmodified lines
472464 i386 getxattrat sys_getxattrat472464 i386 getxattrat sys_getxattrat
473465 i386 listxattrat sys_listxattrat473465 i386 listxattrat sys_listxattrat
474466 i386 removexattrat sys_removexattrat474466 i386 removexattrat sys_removexattrat
475467 i386 open_tree_attr sys_open_tree_attr
arch/x86/entry/syscalls/syscall_64.tbl+1−0
@@ -390,6 +390,7 @@ · 389 unmodified lines
390464 common getxattrat sys_getxattrat390464 common getxattrat sys_getxattrat
391465 common listxattrat sys_listxattrat391465 common listxattrat sys_listxattrat
392466 common removexattrat sys_removexattrat392466 common removexattrat sys_removexattrat
393467 common open_tree_attr sys_open_tree_attr
393 394
394#395#
395# Due to a historical design error, certain syscalls are numbered differently396# Due to a historical design error, certain syscalls are numbered differently
arch/xtensa/kernel/syscalls/syscall.tbl+1−0
@@ -437,3 +437,4 @@ · 436 unmodified lines
437464 common getxattrat sys_getxattrat437464 common getxattrat sys_getxattrat
438465 common listxattrat sys_listxattrat438465 common listxattrat sys_listxattrat
439466 common removexattrat sys_removexattrat439466 common removexattrat sys_removexattrat
440467 common open_tree_attr sys_open_tree_attr
fs/autofs/autofs_i.h+2−0
@@ -218,6 +218,8 @@ void autofs_clean_ino(struct autofs_info *); · 217 unmodified lines
218 218
219static inline int autofs_check_pipe(struct file *pipe)219static inline int autofs_check_pipe(struct file *pipe)
220{220{
221 if (pipe->f_mode & FMODE_PATH)
222 return -EINVAL;
221 if (!(pipe->f_mode & FMODE_CAN_WRITE))223 if (!(pipe->f_mode & FMODE_CAN_WRITE))
222 return -EINVAL;224 return -EINVAL;
223 if (!S_ISFIFO(file_inode(pipe)->i_mode))225 if (!S_ISFIFO(file_inode(pipe)->i_mode))
fs/fsopen.c+1−1
@@ -453,7 +453,7 @@ SYSCALL_DEFINE5(fsconfig, · 452 unmodified lines
453 case FSCONFIG_SET_FD:453 case FSCONFIG_SET_FD:
454 param.type = fs_value_is_file;454 param.type = fs_value_is_file;
455 ret = -EBADF;455 ret = -EBADF;
456 param.file = fget(aux);456 param.file = fget_raw(aux);
457 if (!param.file)457 if (!param.file)
458 goto out_key;458 goto out_key;
459 param.dirfd = aux;459 param.dirfd = aux;
fs/internal.h+1−0
@@ -338,3 +338,4 @@ static inline bool path_mounted(const struct path *path) · 337 unmodified lines
338}338}
339void file_f_owner_release(struct file *file);339void file_f_owner_release(struct file *file);
340bool file_seek_cur_needs_f_lock(struct file *file);340bool file_seek_cur_needs_f_lock(struct file *file);
341int statmount_mnt_idmap(struct mnt_idmap *idmap, struct seq_file *seq, bool uid_map);
fs/mnt_idmapping.c+51−0
@@ -6,6 +6,7 @@ · 5 unmodified lines
6#include <linux/mnt_idmapping.h>6#include <linux/mnt_idmapping.h>
7#include <linux/slab.h>7#include <linux/slab.h>
8#include <linux/user_namespace.h>8#include <linux/user_namespace.h>
9#include <linux/seq_file.h>
9 10
10#include "internal.h"11#include "internal.h"
11 12
@@ -334,3 +335,53 @@ void mnt_idmap_put(struct mnt_idmap *idmap) · 322 unmodified lines
334 free_mnt_idmap(idmap);335 free_mnt_idmap(idmap);
335}336}
336EXPORT_SYMBOL_GPL(mnt_idmap_put);337EXPORT_SYMBOL_GPL(mnt_idmap_put);
338
339int statmount_mnt_idmap(struct mnt_idmap *idmap, struct seq_file *seq, bool uid_map)
340{
341 struct uid_gid_map *map, *map_up;
342 u32 idx, nr_mappings;
343
344 if (!is_valid_mnt_idmap(idmap))
345 return 0;
346
347 /*
348 * Idmappings are shown relative to the caller's idmapping.
349 * This is both the most intuitive and most useful solution.
350 */
351 if (uid_map) {
352 map = &idmap->uid_map;
353 map_up = &current_user_ns()->uid_map;
354 } else {
355 map = &idmap->gid_map;
356 map_up = &current_user_ns()->gid_map;
357 }
358
359 for (idx = 0, nr_mappings = 0; idx < map->nr_extents; idx++) {
360 uid_t lower;
361 struct uid_gid_extent *extent;
362
363 if (map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
364 extent = &map->extent[idx];
365 else
366 extent = &map->forward[idx];
367
368 /*
369 * Verify that the whole range of the mapping can be
370 * resolved in the caller's idmapping. If it cannot be
371 * resolved skip the mapping.
372 */
373 lower = map_id_range_up(map_up, extent->lower_first, extent->count);
374 if (lower == (uid_t) -1)
375 continue;
376
377 seq_printf(seq, "%u %u %u", extent->first, lower, extent->count);
378
379 seq->count++; /* mappings are separated by \0 */
380 if (seq_has_overflowed(seq))
381 return -EAGAIN;
382
383 nr_mappings++;
384 }
385
386 return nr_mappings;
387}
fs/mount.h+26−0
@@ -5,6 +5,8 @@ · 4 unmodified lines
5#include <linux/ns_common.h>5#include <linux/ns_common.h>
6#include <linux/fs_pin.h>6#include <linux/fs_pin.h>
7 7
8extern struct list_head notify_list;
9
8struct mnt_namespace {10struct mnt_namespace {
9 struct ns_common ns;11 struct ns_common ns;
10 struct mount * root;12 struct mount * root;
@@ -21,6 +23,10 @@ struct mnt_namespace { · 10 unmodified lines
21 struct rcu_head mnt_ns_rcu;23 struct rcu_head mnt_ns_rcu;
22 };24 };
23 u64 event;25 u64 event;
26#ifdef CONFIG_FSNOTIFY
27 __u32 n_fsnotify_mask;
28 struct fsnotify_mark_connector __rcu *n_fsnotify_marks;
29#endif
24 unsigned int nr_mounts; /* # of mounts in the namespace */30 unsigned int nr_mounts; /* # of mounts in the namespace */
25 unsigned int pending_mounts;31 unsigned int pending_mounts;
26 struct rb_node mnt_ns_tree_node; /* node in the mnt_ns_tree */32 struct rb_node mnt_ns_tree_node; /* node in the mnt_ns_tree */
@@ -76,6 +82,8 @@ struct mount { · 49 unmodified lines
76#ifdef CONFIG_FSNOTIFY82#ifdef CONFIG_FSNOTIFY
77 struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;83 struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
78 __u32 mnt_fsnotify_mask;84 __u32 mnt_fsnotify_mask;
85 struct list_head to_notify; /* need to queue notification */
86 struct mnt_namespace *prev_ns; /* previous namespace (NULL if none) */
79#endif87#endif
80 int mnt_id; /* mount identifier, reused */88 int mnt_id; /* mount identifier, reused */
81 u64 mnt_id_unique; /* mount ID unique until reboot */89 u64 mnt_id_unique; /* mount ID unique until reboot */
@@ -177,3 +185,21 @@ static inline struct mnt_namespace *to_mnt_ns(struct ns_common *ns) · 95 unmodified lines
177{185{
178 return container_of(ns, struct mnt_namespace, ns);186 return container_of(ns, struct mnt_namespace, ns);
179}187}
188
189#ifdef CONFIG_FSNOTIFY
190static inline void mnt_notify_add(struct mount *m)
191{
192 /* Optimize the case where there are no watches */
193 if ((m->mnt_ns && m->mnt_ns->n_fsnotify_marks) ||
194 (m->prev_ns && m->prev_ns->n_fsnotify_marks))
195 list_add_tail(&m->to_notify, &notify_list);
196 else
197 m->prev_ns = m->mnt_ns;
198}
199#else
200static inline void mnt_notify_add(struct mount *m)
201{
202}
203#endif
204
205struct mnt_namespace *mnt_ns_from_dentry(struct dentry *dentry);
fs/namespace.c+363−122
@@ -81,15 +81,23 @@ static HLIST_HEAD(unmounted); /* protected by namespace_sem */ · 80 unmodified lines
81static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */81static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */
82static DEFINE_SEQLOCK(mnt_ns_tree_lock);82static DEFINE_SEQLOCK(mnt_ns_tree_lock);
83 83
84#ifdef CONFIG_FSNOTIFY
85LIST_HEAD(notify_list); /* protected by namespace_sem */
86#endif
84static struct rb_root mnt_ns_tree = RB_ROOT; /* protected by mnt_ns_tree_lock */87static struct rb_root mnt_ns_tree = RB_ROOT; /* protected by mnt_ns_tree_lock */
85static LIST_HEAD(mnt_ns_list); /* protected by mnt_ns_tree_lock */88static LIST_HEAD(mnt_ns_list); /* protected by mnt_ns_tree_lock */
86 89
90enum mount_kattr_flags_t {
91 MOUNT_KATTR_RECURSE = (1 << 0),
92 MOUNT_KATTR_IDMAP_REPLACE = (1 << 1),
93};
94
87struct mount_kattr {95struct mount_kattr {
88 unsigned int attr_set;96 unsigned int attr_set;
89 unsigned int attr_clr;97 unsigned int attr_clr;
90 unsigned int propagation;98 unsigned int propagation;
91 unsigned int lookup_flags;99 unsigned int lookup_flags;
92 bool recurse;100 enum mount_kattr_flags_t kflags;
93 struct user_namespace *mnt_userns;101 struct user_namespace *mnt_userns;
94 struct mnt_idmap *mnt_idmap;102 struct mnt_idmap *mnt_idmap;
95};103};
@@ -163,6 +171,7 @@ static void mnt_ns_release(struct mnt_namespace *ns) · 67 unmodified lines
163{171{
164 /* keep alive for {list,stat}mount() */172 /* keep alive for {list,stat}mount() */
165 if (refcount_dec_and_test(&ns->passive)) {173 if (refcount_dec_and_test(&ns->passive)) {
174 fsnotify_mntns_delete(ns);
166 put_user_ns(ns->user_ns);175 put_user_ns(ns->user_ns);
167 kfree(ns);176 kfree(ns);
168 }177 }
@@ -1176,6 +1185,8 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt) · 1007 unmodified lines
1176 ns->mnt_first_node = &mnt->mnt_node;1185 ns->mnt_first_node = &mnt->mnt_node;
1177 rb_link_node(&mnt->mnt_node, parent, link);1186 rb_link_node(&mnt->mnt_node, parent, link);
1178 rb_insert_color(&mnt->mnt_node, &ns->mounts);1187 rb_insert_color(&mnt->mnt_node, &ns->mounts);
1188
1189 mnt_notify_add(mnt);
1179}1190}
1180 1191
1181/*1192/*
@@ -1723,6 +1734,50 @@ int may_umount(struct vfsmount *mnt) · 541 unmodified lines
1723 1734
1724EXPORT_SYMBOL(may_umount);1735EXPORT_SYMBOL(may_umount);
1725 1736
1737#ifdef CONFIG_FSNOTIFY
1738static void mnt_notify(struct mount *p)
1739{
1740 if (!p->prev_ns && p->mnt_ns) {
1741 fsnotify_mnt_attach(p->mnt_ns, &p->mnt);
1742 } else if (p->prev_ns && !p->mnt_ns) {
1743 fsnotify_mnt_detach(p->prev_ns, &p->mnt);
1744 } else if (p->prev_ns == p->mnt_ns) {
1745 fsnotify_mnt_move(p->mnt_ns, &p->mnt);
1746 } else {
1747 fsnotify_mnt_detach(p->prev_ns, &p->mnt);
1748 fsnotify_mnt_attach(p->mnt_ns, &p->mnt);
1749 }
1750 p->prev_ns = p->mnt_ns;
1751}
1752
1753static void notify_mnt_list(void)
1754{
1755 struct mount *m, *tmp;
1756 /*
1757 * Notify about mounts that were added/reparented/detached/remain
1758 * connected after unmount.
1759 */
1760 list_for_each_entry_safe(m, tmp, &notify_list, to_notify) {
1761 mnt_notify(m);
1762 list_del_init(&m->to_notify);
1763 }
1764}
1765
1766static bool need_notify_mnt_list(void)
1767{
1768 return !list_empty(&notify_list);
1769}
1770#else
1771static void notify_mnt_list(void)
1772{
1773}
1774
1775static bool need_notify_mnt_list(void)
1776{
1777 return false;
1778}
1779#endif
1780
1726static void namespace_unlock(void)1781static void namespace_unlock(void)
1727{1782{
1728 struct hlist_head head;1783 struct hlist_head head;
@@ -1733,7 +1788,18 @@ static void namespace_unlock(void) · 4 unmodified lines
1733 hlist_move_list(&unmounted, &head);1788 hlist_move_list(&unmounted, &head);
1734 list_splice_init(&ex_mountpoints, &list);1789 list_splice_init(&ex_mountpoints, &list);
1735 1790
1736 up_write(&namespace_sem);1791 if (need_notify_mnt_list()) {
1792 /*
1793 * No point blocking out concurrent readers while notifications
1794 * are sent. This will also allow statmount()/listmount() to run
1795 * concurrently.
1796 */
1797 downgrade_write(&namespace_sem);
1798 notify_mnt_list();
1799 up_read(&namespace_sem);
1800 } else {
1801 up_write(&namespace_sem);
1802 }
1737 1803
1738 shrink_dentry_list(&list);1804 shrink_dentry_list(&list);
1739 1805
@@ -1846,6 +1912,19 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how) · 106 unmodified lines
1846 change_mnt_propagation(p, MS_PRIVATE);1912 change_mnt_propagation(p, MS_PRIVATE);
1847 if (disconnect)1913 if (disconnect)
1848 hlist_add_head(&p->mnt_umount, &unmounted);1914 hlist_add_head(&p->mnt_umount, &unmounted);
1915
1916 /*
1917 * At this point p->mnt_ns is NULL, notification will be queued
1918 * only if
1919 *
1920 * - p->prev_ns is non-NULL *and*
1921 * - p->prev_ns->n_fsnotify_marks is non-NULL
1922 *
1923 * This will preclude queuing the mount if this is a cleanup
1924 * after a failed copy_tree() or destruction of an anonymous
1925 * namespace, etc.
1926 */
1927 mnt_notify_add(p);
1849 }1928 }
1850}1929}
1851 1930
@@ -2026,6 +2105,7 @@ static void warn_mandlock(void) · 174 unmodified lines
2026static int can_umount(const struct path *path, int flags)2105static int can_umount(const struct path *path, int flags)
2027{2106{
2028 struct mount *mnt = real_mount(path->mnt);2107 struct mount *mnt = real_mount(path->mnt);
2108 struct super_block *sb = path->dentry->d_sb;
2029 2109
2030 if (!may_mount())2110 if (!may_mount())
2031 return -EPERM;2111 return -EPERM;
@@ -2035,7 +2115,7 @@ static int can_umount(const struct path *path, int flags) · 3 unmodified lines
2035 return -EINVAL;2115 return -EINVAL;
2036 if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */2116 if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
2037 return -EINVAL;2117 return -EINVAL;
2038 if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))2118 if (flags & MNT_FORCE && !ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
2039 return -EPERM;2119 return -EPERM;
2040 return 0;2120 return 0;
2041}2121}
@@ -2145,16 +2225,24 @@ struct mnt_namespace *get_sequential_mnt_ns(struct mnt_namespace *mntns, bool pr · 103 unmodified lines
2145 }2225 }
2146}2226}
2147 2227
2228struct mnt_namespace *mnt_ns_from_dentry(struct dentry *dentry)
2229{
2230 if (!is_mnt_ns_file(dentry))
2231 return NULL;
2232
2233 return to_mnt_ns(get_proc_ns(dentry->d_inode));
2234}
2235
2148static bool mnt_ns_loop(struct dentry *dentry)2236static bool mnt_ns_loop(struct dentry *dentry)
2149{2237{
2150 /* Could bind mounting the mount namespace inode cause a2238 /* Could bind mounting the mount namespace inode cause a
2151 * mount namespace loop?2239 * mount namespace loop?
2152 */2240 */
2153 struct mnt_namespace *mnt_ns;2241 struct mnt_namespace *mnt_ns = mnt_ns_from_dentry(dentry);
2154 if (!is_mnt_ns_file(dentry))2242
2243 if (!mnt_ns)
2155 return false;2244 return false;
2156 2245
2157 mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode));
2158 return current->nsproxy->mnt_ns->seq >= mnt_ns->seq;2246 return current->nsproxy->mnt_ns->seq >= mnt_ns->seq;
2159}2247}
2160 2248
@@ -2287,6 +2375,28 @@ bool has_locked_children(struct mount *mnt, struct dentry *dentry) · 126 unmodified lines
2287 return false;2375 return false;
2288}2376}
2289 2377
2378/*
2379 * Check that there aren't references to earlier/same mount namespaces in the
2380 * specified subtree. Such references can act as pins for mount namespaces
2381 * that aren't checked by the mount-cycle checking code, thereby allowing
2382 * cycles to be made.
2383 */
2384static bool check_for_nsfs_mounts(struct mount *subtree)
2385{
2386 struct mount *p;
2387 bool ret = false;
2388
2389 lock_mount_hash();
2390 for (p = subtree; p; p = next_mnt(p, subtree))
2391 if (mnt_ns_loop(p->mnt.mnt_root))
2392 goto out;
2393
2394 ret = true;
2395out:
2396 unlock_mount_hash();
2397 return ret;
2398}
2399
2290/**2400/**
2291 * clone_private_mount - create a private clone of a path2401 * clone_private_mount - create a private clone of a path
2292 * @path: path to clone2402 * @path: path to clone
@@ -2295,6 +2405,8 @@ bool has_locked_children(struct mount *mnt, struct dentry *dentry) · 2 unmodified lines
2295 * will not be attached anywhere in the namespace and will be private (i.e.2405 * will not be attached anywhere in the namespace and will be private (i.e.
2296 * changes to the originating mount won't be propagated into this).2406 * changes to the originating mount won't be propagated into this).
2297 *2407 *
2408 * This assumes caller has called or done the equivalent of may_mount().
2409 *
2298 * Release with mntput().2410 * Release with mntput().
2299 */2411 */
2300struct vfsmount *clone_private_mount(const struct path *path)2412struct vfsmount *clone_private_mount(const struct path *path)
@@ -2302,30 +2414,36 @@ struct vfsmount *clone_private_mount(const struct path *path) · 1 unmodified line
2302 struct mount *old_mnt = real_mount(path->mnt);2414 struct mount *old_mnt = real_mount(path->mnt);
2303 struct mount *new_mnt;2415 struct mount *new_mnt;
2304 2416
2305 down_read(&namespace_sem);2417 scoped_guard(rwsem_read, &namespace_sem)
2306 if (IS_MNT_UNBINDABLE(old_mnt))2418 if (IS_MNT_UNBINDABLE(old_mnt))
2307 goto invalid;2419 return ERR_PTR(-EINVAL);
2420
2421 if (mnt_has_parent(old_mnt)) {
2422 if (!check_mnt(old_mnt))
2423 return ERR_PTR(-EINVAL);
2424 } else {
2425 if (!is_mounted(&old_mnt->mnt))
2426 return ERR_PTR(-EINVAL);
2308 2427
2309 if (!check_mnt(old_mnt))2428 /* Make sure this isn't something purely kernel internal. */
2310 goto invalid;2429 if (!is_anon_ns(old_mnt->mnt_ns))
2430 return ERR_PTR(-EINVAL);
2431
2432 /* Make sure we don't create mount namespace loops. */
2433 if (!check_for_nsfs_mounts(old_mnt))
2434 return ERR_PTR(-EINVAL);
2435 }
2311 2436
2312 if (has_locked_children(old_mnt, path->dentry))2437 if (has_locked_children(old_mnt, path->dentry))
2313 goto invalid;2438 return ERR_PTR(-EINVAL);
2314 2439
2315 new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);2440 new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);
2316 up_read(&namespace_sem);
2317
2318 if (IS_ERR(new_mnt))2441 if (IS_ERR(new_mnt))
2319 return ERR_CAST(new_mnt);2442 return ERR_PTR(-EINVAL);
2320 2443
2321 /* Longterm mount to be removed by kern_unmount*() */2444 /* Longterm mount to be removed by kern_unmount*() */
2322 new_mnt->mnt_ns = MNT_NS_INTERNAL;2445 new_mnt->mnt_ns = MNT_NS_INTERNAL;
2323
2324 return &new_mnt->mnt;2446 return &new_mnt->mnt;
2325
2326invalid:
2327 up_read(&namespace_sem);
2328 return ERR_PTR(-EINVAL);
2329}2447}
2330EXPORT_SYMBOL_GPL(clone_private_mount);2448EXPORT_SYMBOL_GPL(clone_private_mount);
2331 2449
@@ -2547,6 +2665,7 @@ static int attach_recursive_mnt(struct mount *source_mnt, · 215 unmodified lines
2547 dest_mp = smp;2665 dest_mp = smp;
2548 unhash_mnt(source_mnt);2666 unhash_mnt(source_mnt);
2549 attach_mnt(source_mnt, top_mnt, dest_mp, beneath);2667 attach_mnt(source_mnt, top_mnt, dest_mp, beneath);
2668 mnt_notify_add(source_mnt);
2550 touch_mnt_namespace(source_mnt->mnt_ns);2669 touch_mnt_namespace(source_mnt->mnt_ns);
2551 } else {2670 } else {
2552 if (source_mnt->mnt_ns) {2671 if (source_mnt->mnt_ns) {
@@ -2889,24 +3008,22 @@ static struct file *open_detached_copy(struct path *path, bool recursive) · 336 unmodified lines
2889 return file;3008 return file;
2890}3009}
2891 3010
2892SYSCALL_DEFINE3(open_tree, int, dfd, const char __user *, filename, unsigned, flags)3011static struct file *vfs_open_tree(int dfd, const char __user *filename, unsigned int flags)
2893{3012{
2894 struct file *file;3013 int ret;
2895 struct path path;3014 struct path path __free(path_put) = {};
2896 int lookup_flags = LOOKUP_AUTOMOUNT | LOOKUP_FOLLOW;3015 int lookup_flags = LOOKUP_AUTOMOUNT | LOOKUP_FOLLOW;
2897 bool detached = flags & OPEN_TREE_CLONE;3016 bool detached = flags & OPEN_TREE_CLONE;
2898 int error;
2899 int fd;
2900 3017
2901 BUILD_BUG_ON(OPEN_TREE_CLOEXEC != O_CLOEXEC);3018 BUILD_BUG_ON(OPEN_TREE_CLOEXEC != O_CLOEXEC);
2902 3019
2903 if (flags & ~(AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_RECURSIVE |3020 if (flags & ~(AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_RECURSIVE |
2904 AT_SYMLINK_NOFOLLOW | OPEN_TREE_CLONE |3021 AT_SYMLINK_NOFOLLOW | OPEN_TREE_CLONE |
2905 OPEN_TREE_CLOEXEC))3022 OPEN_TREE_CLOEXEC))
2906 return -EINVAL;3023 return ERR_PTR(-EINVAL);
2907 3024
2908 if ((flags & (AT_RECURSIVE | OPEN_TREE_CLONE)) == AT_RECURSIVE)3025 if ((flags & (AT_RECURSIVE | OPEN_TREE_CLONE)) == AT_RECURSIVE)
2909 return -EINVAL;3026 return ERR_PTR(-EINVAL);
2910 3027
2911 if (flags & AT_NO_AUTOMOUNT)3028 if (flags & AT_NO_AUTOMOUNT)
2912 lookup_flags &= ~LOOKUP_AUTOMOUNT;3029 lookup_flags &= ~LOOKUP_AUTOMOUNT;
@@ -2916,27 +3033,32 @@ SYSCALL_DEFINE3(open_tree, int, dfd, const char __user *, filename, unsigned, fl · 3 unmodified lines
2916 lookup_flags |= LOOKUP_EMPTY;3033 lookup_flags |= LOOKUP_EMPTY;
2917 3034
2918 if (detached && !may_mount())3035 if (detached && !may_mount())
2919 return -EPERM;3036 return ERR_PTR(-EPERM);
3037
3038 ret = user_path_at(dfd, filename, lookup_flags, &path);
3039 if (unlikely(ret))
3040 return ERR_PTR(ret);
3041
3042 if (detached)
3043 return open_detached_copy(&path, flags & AT_RECURSIVE);
3044
3045 return dentry_open(&path, O_PATH, current_cred());
3046}
3047
3048SYSCALL_DEFINE3(open_tree, int, dfd, const char __user *, filename, unsigned, flags)
3049{
3050 int fd;
3051 struct file *file __free(fput) = NULL;
3052
3053 file = vfs_open_tree(dfd, filename, flags);
3054 if (IS_ERR(file))
3055 return PTR_ERR(file);
2920 3056
2921 fd = get_unused_fd_flags(flags & O_CLOEXEC);3057 fd = get_unused_fd_flags(flags & O_CLOEXEC);
2922 if (fd < 0)3058 if (fd < 0)
2923 return fd;3059 return fd;
2924 3060
2925 error = user_path_at(dfd, filename, lookup_flags, &path);3061 fd_install(fd, no_free_ptr(file));
2926 if (unlikely(error)) {
2927 file = ERR_PTR(error);
2928 } else {
2929 if (detached)
2930 file = open_detached_copy(&path, flags & AT_RECURSIVE);
2931 else
2932 file = dentry_open(&path, O_PATH, current_cred());
2933 path_put(&path);
2934 }
2935 if (IS_ERR(file)) {
2936 put_unused_fd(fd);
2937 return PTR_ERR(file);
2938 }
2939 fd_install(fd, file);
2940 return fd;3062 return fd;
2941}3063}
2942 3064
@@ -3123,28 +3245,6 @@ static inline int tree_contains_unbindable(struct mount *mnt) · 180 unmodified lines
3123 return 0;3245 return 0;
3124}3246}
3125 3247
3126/*
3127 * Check that there aren't references to earlier/same mount namespaces in the
3128 * specified subtree. Such references can act as pins for mount namespaces
3129 * that aren't checked by the mount-cycle checking code, thereby allowing
3130 * cycles to be made.
3131 */
3132static bool check_for_nsfs_mounts(struct mount *subtree)
3133{
3134 struct mount *p;
3135 bool ret = false;
3136
3137 lock_mount_hash();
3138 for (p = subtree; p; p = next_mnt(p, subtree))
3139 if (mnt_ns_loop(p->mnt.mnt_root))
3140 goto out;
3141
3142 ret = true;
3143out:
3144 unlock_mount_hash();
3145 return ret;
3146}
3147
3148static int do_set_group(struct path *from_path, struct path *to_path)3248static int do_set_group(struct path *from_path, struct path *to_path)
3149{3249{
3150 struct mount *from, *to;3250 struct mount *from, *to;
@@ -4468,6 +4568,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, · 1317 unmodified lines
4468 list_del_init(&new_mnt->mnt_expire);4568 list_del_init(&new_mnt->mnt_expire);
4469 put_mountpoint(root_mp);4569 put_mountpoint(root_mp);
4470 unlock_mount_hash();4570 unlock_mount_hash();
4571 mnt_notify_add(root_mnt);
4572 mnt_notify_add(new_mnt);
4471 chroot_fs_refs(&root, &new);4573 chroot_fs_refs(&root, &new);
4472 error = 0;4574 error = 0;
4473out4:4575out4:
@@ -4512,11 +4614,10 @@ static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt) · 38 unmodified lines
4512 return -EINVAL;4614 return -EINVAL;
4513 4615
4514 /*4616 /*
4515 * Once a mount has been idmapped we don't allow it to change its4617 * We only allow an mount to change it's idmapping if it has
4516 * mapping. It makes things simpler and callers can just create4618 * never been accessible to userspace.
4517 * another bind-mount they can idmap if they want to.
4518 */4619 */
4519 if (is_idmapped_mnt(m))4620 if (!(kattr->kflags & MOUNT_KATTR_IDMAP_REPLACE) && is_idmapped_mnt(m))
4520 return -EPERM;4621 return -EPERM;
4521 4622
4522 /* The underlying filesystem doesn't support idmapped mounts yet. */4623 /* The underlying filesystem doesn't support idmapped mounts yet. */
@@ -4576,7 +4677,7 @@ static int mount_setattr_prepare(struct mount_kattr *kattr, struct mount *mnt) · 53 unmodified lines
4576 break;4677 break;
4577 }4678 }
4578 4679
4579 if (!kattr->recurse)4680 if (!(kattr->kflags & MOUNT_KATTR_RECURSE))
4580 return 0;4681 return 0;
4581 }4682 }
4582 4683
@@ -4606,18 +4707,16 @@ static int mount_setattr_prepare(struct mount_kattr *kattr, struct mount *mnt) · 23 unmodified lines
4606 4707
4607static void do_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)4708static void do_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)
4608{4709{
4710 struct mnt_idmap *old_idmap;
4711
4609 if (!kattr->mnt_idmap)4712 if (!kattr->mnt_idmap)
4610 return;4713 return;
4611 4714
4612 /*4715 old_idmap = mnt_idmap(&mnt->mnt);
4613 * Pairs with smp_load_acquire() in mnt_idmap().4716
4614 *4717 /* Pairs with smp_load_acquire() in mnt_idmap(). */
4615 * Since we only allow a mount to change the idmapping once and
4616 * verified this in can_idmap_mount() we know that the mount has
4617 * @nop_mnt_idmap attached to it. So there's no need to drop any
4618 * references.
4619 */
4620 smp_store_release(&mnt->mnt.mnt_idmap, mnt_idmap_get(kattr->mnt_idmap));4718 smp_store_release(&mnt->mnt.mnt_idmap, mnt_idmap_get(kattr->mnt_idmap));
4719 mnt_idmap_put(old_idmap);
4621}4720}
4622 4721
4623static void mount_setattr_commit(struct mount_kattr *kattr, struct mount *mnt)4722static void mount_setattr_commit(struct mount_kattr *kattr, struct mount *mnt)
@@ -4637,7 +4736,7 @@ static void mount_setattr_commit(struct mount_kattr *kattr, struct mount *mnt) · 13 unmodified lines
4637 4736
4638 if (kattr->propagation)4737 if (kattr->propagation)
4639 change_mnt_propagation(m, kattr->propagation);4738 change_mnt_propagation(m, kattr->propagation);
4640 if (!kattr->recurse)4739 if (!(kattr->kflags & MOUNT_KATTR_RECURSE))
4641 break;4740 break;
4642 }4741 }
4643 touch_mnt_namespace(mnt->mnt_ns);4742 touch_mnt_namespace(mnt->mnt_ns);
@@ -4667,7 +4766,7 @@ static int do_mount_setattr(struct path *path, struct mount_kattr *kattr) · 23 unmodified lines
4667 */4766 */
4668 namespace_lock();4767 namespace_lock();
4669 if (kattr->propagation == MS_SHARED) {4768 if (kattr->propagation == MS_SHARED) {
4670 err = invent_group_ids(mnt, kattr->recurse);4769 err = invent_group_ids(mnt, kattr->kflags & MOUNT_KATTR_RECURSE);
4671 if (err) {4770 if (err) {
4672 namespace_unlock();4771 namespace_unlock();
4673 return err;4772 return err;
@@ -4718,7 +4817,7 @@ out: · 44 unmodified lines
4718}4817}
4719 4818
4720static int build_mount_idmapped(const struct mount_attr *attr, size_t usize,4819static int build_mount_idmapped(const struct mount_attr *attr, size_t usize,
4721 struct mount_kattr *kattr, unsigned int flags)4820 struct mount_kattr *kattr)
4722{4821{
4723 struct ns_common *ns;4822 struct ns_common *ns;
4724 struct user_namespace *mnt_userns;4823 struct user_namespace *mnt_userns;
@@ -4726,13 +4825,23 @@ static int build_mount_idmapped(const struct mount_attr *attr, size_t usize, · 1 unmodified line
4726 if (!((attr->attr_set | attr->attr_clr) & MOUNT_ATTR_IDMAP))4825 if (!((attr->attr_set | attr->attr_clr) & MOUNT_ATTR_IDMAP))
4727 return 0;4826 return 0;
4728 4827
4729 /*4828 if (attr->attr_clr & MOUNT_ATTR_IDMAP) {
4730 * We currently do not support clearing an idmapped mount. If this ever4829 /*
4731 * is a use-case we can revisit this but for now let's keep it simple4830 * We can only remove an idmapping if it's never been
4732 * and not allow it.4831 * exposed to userspace.
4733 */4832 */
4734 if (attr->attr_clr & MOUNT_ATTR_IDMAP)4833 if (!(kattr->kflags & MOUNT_KATTR_IDMAP_REPLACE))
4735 return -EINVAL;4834 return -EINVAL;
4835
4836 /*
4837 * Removal of idmappings is equivalent to setting
4838 * nop_mnt_idmap.
4839 */
4840 if (!(attr->attr_set & MOUNT_ATTR_IDMAP)) {
4841 kattr->mnt_idmap = &nop_mnt_idmap;
4842 return 0;
4843 }
4844 }
4736 4845
4737 if (attr->userns_fd > INT_MAX)4846 if (attr->userns_fd > INT_MAX)
4738 return -EINVAL;4847 return -EINVAL;
@@ -4769,22 +4878,8 @@ static int build_mount_idmapped(const struct mount_attr *attr, size_t usize, · 30 unmodified lines
4769}4878}
4770 4879
4771static int build_mount_kattr(const struct mount_attr *attr, size_t usize,4880static int build_mount_kattr(const struct mount_attr *attr, size_t usize,
4772 struct mount_kattr *kattr, unsigned int flags)4881 struct mount_kattr *kattr)
4773{4882{
4774 unsigned int lookup_flags = LOOKUP_AUTOMOUNT | LOOKUP_FOLLOW;
4775
4776 if (flags & AT_NO_AUTOMOUNT)
4777 lookup_flags &= ~LOOKUP_AUTOMOUNT;
4778 if (flags & AT_SYMLINK_NOFOLLOW)
4779 lookup_flags &= ~LOOKUP_FOLLOW;
4780 if (flags & AT_EMPTY_PATH)
4781 lookup_flags |= LOOKUP_EMPTY;
4782
4783 *kattr = (struct mount_kattr) {
4784 .lookup_flags = lookup_flags,
4785 .recurse = !!(flags & AT_RECURSIVE),
4786 };
4787
4788 if (attr->propagation & ~MOUNT_SETATTR_PROPAGATION_FLAGS)4883 if (attr->propagation & ~MOUNT_SETATTR_PROPAGATION_FLAGS)
4789 return -EINVAL;4884 return -EINVAL;
4790 if (hweight32(attr->propagation & MOUNT_SETATTR_PROPAGATION_FLAGS) > 1)4885 if (hweight32(attr->propagation & MOUNT_SETATTR_PROPAGATION_FLAGS) > 1)
@@ -4832,35 +4927,28 @@ static int build_mount_kattr(const struct mount_attr *attr, size_t usize, · 41 unmodified lines
4832 return -EINVAL;4927 return -EINVAL;
4833 }4928 }
4834 4929
4835 return build_mount_idmapped(attr, usize, kattr, flags);4930 return build_mount_idmapped(attr, usize, kattr);
4836}4931}
4837 4932
4838static void finish_mount_kattr(struct mount_kattr *kattr)4933static void finish_mount_kattr(struct mount_kattr *kattr)
4839{4934{
4840 put_user_ns(kattr->mnt_userns);4935 if (kattr->mnt_userns) {
4841 kattr->mnt_userns = NULL;4936 put_user_ns(kattr->mnt_userns);
4937 kattr->mnt_userns = NULL;
4938 }
4842 4939
4843 if (kattr->mnt_idmap)4940 if (kattr->mnt_idmap)
4844 mnt_idmap_put(kattr->mnt_idmap);4941 mnt_idmap_put(kattr->mnt_idmap);
4845}4942}
4846 4943
4847SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,4944static int copy_mount_setattr(struct mount_attr __user *uattr, size_t usize,
4848 unsigned int, flags, struct mount_attr __user *, uattr,4945 struct mount_kattr *kattr)
4849 size_t, usize)
4850{4946{
4851 int err;4947 int ret;
4852 struct path target;
4853 struct mount_attr attr;4948 struct mount_attr attr;
4854 struct mount_kattr kattr;
4855 4949
4856 BUILD_BUG_ON(sizeof(struct mount_attr) != MOUNT_ATTR_SIZE_VER0);4950 BUILD_BUG_ON(sizeof(struct mount_attr) != MOUNT_ATTR_SIZE_VER0);
4857 4951
4858 if (flags & ~(AT_EMPTY_PATH |
4859 AT_RECURSIVE |
4860 AT_SYMLINK_NOFOLLOW |
4861 AT_NO_AUTOMOUNT))
4862 return -EINVAL;
4863
4864 if (unlikely(usize > PAGE_SIZE))4952 if (unlikely(usize > PAGE_SIZE))
4865 return -E2BIG;4953 return -E2BIG;
4866 if (unlikely(usize < MOUNT_ATTR_SIZE_VER0))4954 if (unlikely(usize < MOUNT_ATTR_SIZE_VER0))
@@ -4869,9 +4957,9 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path, · 2 unmodified lines
4869 if (!may_mount())4957 if (!may_mount())
4870 return -EPERM;4958 return -EPERM;
4871 4959
4872 err = copy_struct_from_user(&attr, sizeof(attr), uattr, usize);4960 ret = copy_struct_from_user(&attr, sizeof(attr), uattr, usize);
4873 if (err)4961 if (ret)
4874 return err;4962 return ret;
4875 4963
4876 /* Don't bother walking through the mounts if this is a nop. */4964 /* Don't bother walking through the mounts if this is a nop. */
4877 if (attr.attr_set == 0 &&4965 if (attr.attr_set == 0 &&
@@ -4879,7 +4967,39 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path, · 1 unmodified line
4879 attr.propagation == 0)4967 attr.propagation == 0)
4880 return 0;4968 return 0;
4881 4969
4882 err = build_mount_kattr(&attr, usize, &kattr, flags);4970 return build_mount_kattr(&attr, usize, kattr);
4971}
4972
4973SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,
4974 unsigned int, flags, struct mount_attr __user *, uattr,
4975 size_t, usize)
4976{
4977 int err;
4978 struct path target;
4979 struct mount_kattr kattr;
4980 unsigned int lookup_flags = LOOKUP_AUTOMOUNT | LOOKUP_FOLLOW;
4981
4982 if (flags & ~(AT_EMPTY_PATH |
4983 AT_RECURSIVE |
4984 AT_SYMLINK_NOFOLLOW |
4985 AT_NO_AUTOMOUNT))
4986 return -EINVAL;
4987
4988 if (flags & AT_NO_AUTOMOUNT)
4989 lookup_flags &= ~LOOKUP_AUTOMOUNT;
4990 if (flags & AT_SYMLINK_NOFOLLOW)
4991 lookup_flags &= ~LOOKUP_FOLLOW;
4992 if (flags & AT_EMPTY_PATH)
4993 lookup_flags |= LOOKUP_EMPTY;
4994
4995 kattr = (struct mount_kattr) {
4996 .lookup_flags = lookup_flags,
4997 };
4998
4999 if (flags & AT_RECURSIVE)
5000 kattr.kflags |= MOUNT_KATTR_RECURSE;
5001
5002 err = copy_mount_setattr(uattr, usize, &kattr);
4883 if (err)5003 if (err)
4884 return err;5004 return err;
4885 5005
@@ -4892,6 +5012,47 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path, · 6 unmodified lines
4892 return err;5012 return err;
4893}5013}
4894 5014
5015SYSCALL_DEFINE5(open_tree_attr, int, dfd, const char __user *, filename,
5016 unsigned, flags, struct mount_attr __user *, uattr,
5017 size_t, usize)
5018{
5019 struct file __free(fput) *file = NULL;
5020 int fd;
5021
5022 if (!uattr && usize)
5023 return -EINVAL;
5024
5025 file = vfs_open_tree(dfd, filename, flags);
5026 if (IS_ERR(file))
5027 return PTR_ERR(file);
5028
5029 if (uattr) {
5030 int ret;
5031 struct mount_kattr kattr = {};
5032
5033 kattr.kflags = MOUNT_KATTR_IDMAP_REPLACE;
5034 if (flags & AT_RECURSIVE)
5035 kattr.kflags |= MOUNT_KATTR_RECURSE;
5036
5037 ret = copy_mount_setattr(uattr, usize, &kattr);
5038 if (ret)
5039 return ret;
5040
5041 ret = do_mount_setattr(&file->f_path, &kattr);
5042 if (ret)
5043 return ret;
5044
5045 finish_mount_kattr(&kattr);
5046 }
5047
5048 fd = get_unused_fd_flags(flags & O_CLOEXEC);
5049 if (fd < 0)
5050 return fd;
5051
5052 fd_install(fd, no_free_ptr(file));
5053 return fd;
5054}
5055
4895int show_path(struct seq_file *m, struct dentry *root)5056int show_path(struct seq_file *m, struct dentry *root)
4896{5057{
4897 if (root->d_sb->s_op->show_path)5058 if (root->d_sb->s_op->show_path)
@@ -4915,6 +5076,7 @@ struct kstatmount { · 17 unmodified lines
4915 struct statmount __user *buf;5076 struct statmount __user *buf;
4916 size_t bufsize;5077 size_t bufsize;
4917 struct vfsmount *mnt;5078 struct vfsmount *mnt;
5079 struct mnt_idmap *idmap;
4918 u64 mask;5080 u64 mask;
4919 struct path root;5081 struct path root;
4920 struct statmount sm;5082 struct statmount sm;
@@ -5184,6 +5346,46 @@ static int statmount_opt_sec_array(struct kstatmount *s, struct seq_file *seq) · 263 unmodified lines
5184 return 0;5346 return 0;
5185}5347}
5186 5348
5349static inline int statmount_mnt_uidmap(struct kstatmount *s, struct seq_file *seq)
5350{
5351 int ret;
5352
5353 ret = statmount_mnt_idmap(s->idmap, seq, true);
5354 if (ret < 0)
5355 return ret;
5356
5357 s->sm.mnt_uidmap_num = ret;
5358 /*
5359 * Always raise STATMOUNT_MNT_UIDMAP even if there are no valid
5360 * mappings. This allows userspace to distinguish between a
5361 * non-idmapped mount and an idmapped mount where none of the
5362 * individual mappings are valid in the caller's idmapping.
5363 */
5364 if (is_valid_mnt_idmap(s->idmap))
5365 s->sm.mask |= STATMOUNT_MNT_UIDMAP;
5366 return 0;
5367}
5368
5369static inline int statmount_mnt_gidmap(struct kstatmount *s, struct seq_file *seq)
5370{
5371 int ret;
5372
5373 ret = statmount_mnt_idmap(s->idmap, seq, false);
5374 if (ret < 0)
5375 return ret;
5376
5377 s->sm.mnt_gidmap_num = ret;
5378 /*
5379 * Always raise STATMOUNT_MNT_GIDMAP even if there are no valid
5380 * mappings. This allows userspace to distinguish between a
5381 * non-idmapped mount and an idmapped mount where none of the
5382 * individual mappings are valid in the caller's idmapping.
5383 */
5384 if (is_valid_mnt_idmap(s->idmap))
5385 s->sm.mask |= STATMOUNT_MNT_GIDMAP;
5386 return 0;
5387}
5388
5187static int statmount_string(struct kstatmount *s, u64 flag)5389static int statmount_string(struct kstatmount *s, u64 flag)
5188{5390{
5189 int ret = 0;5391 int ret = 0;
@@ -5231,6 +5433,14 @@ static int statmount_string(struct kstatmount *s, u64 flag) · 41 unmodified lines
5231 offp = &sm->sb_source;5433 offp = &sm->sb_source;
5232 ret = statmount_sb_source(s, seq);5434 ret = statmount_sb_source(s, seq);
5233 break;5435 break;
5436 case STATMOUNT_MNT_UIDMAP:
5437 sm->mnt_uidmap = start;
5438 ret = statmount_mnt_uidmap(s, seq);
5439 break;
5440 case STATMOUNT_MNT_GIDMAP:
5441 sm->mnt_gidmap = start;
5442 ret = statmount_mnt_gidmap(s, seq);
5443 break;
5234 default:5444 default:
5235 WARN_ON_ONCE(true);5445 WARN_ON_ONCE(true);
5236 return -EINVAL;5446 return -EINVAL;
@@ -5323,6 +5533,21 @@ static int grab_requested_root(struct mnt_namespace *ns, struct path *root) · 86 unmodified lines
5323 return 0;5533 return 0;
5324}5534}
5325 5535
5536/* This must be updated whenever a new flag is added */
5537#define STATMOUNT_SUPPORTED (STATMOUNT_SB_BASIC | \
5538 STATMOUNT_MNT_BASIC | \
5539 STATMOUNT_PROPAGATE_FROM | \
5540 STATMOUNT_MNT_ROOT | \
5541 STATMOUNT_MNT_POINT | \
5542 STATMOUNT_FS_TYPE | \
5543 STATMOUNT_MNT_NS_ID | \
5544 STATMOUNT_MNT_OPTS | \
5545 STATMOUNT_FS_SUBTYPE | \
5546 STATMOUNT_SB_SOURCE | \
5547 STATMOUNT_OPT_ARRAY | \
5548 STATMOUNT_OPT_SEC_ARRAY | \
5549 STATMOUNT_SUPPORTED_MASK)
5550
5326static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,5551static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,
5327 struct mnt_namespace *ns)5552 struct mnt_namespace *ns)
5328{5553{
@@ -5356,6 +5581,7 @@ static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id, · 27 unmodified lines
5356 return err;5581 return err;
5357 5582
5358 s->root = root;5583 s->root = root;
5584 s->idmap = mnt_idmap(s->mnt);
5359 if (s->mask & STATMOUNT_SB_BASIC)5585 if (s->mask & STATMOUNT_SB_BASIC)
5360 statmount_sb_basic(s);5586 statmount_sb_basic(s);
5361 5587
@@ -5389,12 +5615,26 @@ static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id, · 27 unmodified lines
5389 if (!err && s->mask & STATMOUNT_SB_SOURCE)5615 if (!err && s->mask & STATMOUNT_SB_SOURCE)
5390 err = statmount_string(s, STATMOUNT_SB_SOURCE);5616 err = statmount_string(s, STATMOUNT_SB_SOURCE);
5391 5617
5618 if (!err && s->mask & STATMOUNT_MNT_UIDMAP)
5619 err = statmount_string(s, STATMOUNT_MNT_UIDMAP);
5620
5621 if (!err && s->mask & STATMOUNT_MNT_GIDMAP)
5622 err = statmount_string(s, STATMOUNT_MNT_GIDMAP);
5623
5392 if (!err && s->mask & STATMOUNT_MNT_NS_ID)5624 if (!err && s->mask & STATMOUNT_MNT_NS_ID)
5393 statmount_mnt_ns_id(s, ns);5625 statmount_mnt_ns_id(s, ns);
5394 5626
5627 if (!err && s->mask & STATMOUNT_SUPPORTED_MASK) {
5628 s->sm.mask |= STATMOUNT_SUPPORTED_MASK;
5629 s->sm.supported_mask = STATMOUNT_SUPPORTED;
5630 }
5631
5395 if (err)5632 if (err)
5396 return err;5633 return err;
5397 5634
5635 /* Are there bits in the return mask not present in STATMOUNT_SUPPORTED? */
5636 WARN_ON_ONCE(~STATMOUNT_SUPPORTED & s->sm.mask);
5637
5398 return 0;5638 return 0;
5399}5639}
5400 5640
@@ -5412,7 +5652,8 @@ static inline bool retry_statmount(const long ret, size_t *seq_size) · 11 unmodified lines
5412#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \5652#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
5413 STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS | \5653 STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS | \
5414 STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE | \5654 STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE | \
5415 STATMOUNT_OPT_ARRAY | STATMOUNT_OPT_SEC_ARRAY)5655 STATMOUNT_OPT_ARRAY | STATMOUNT_OPT_SEC_ARRAY | \
5656 STATMOUNT_MNT_UIDMAP | STATMOUNT_MNT_GIDMAP)
5416 5657
5417static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,5658static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
5418 struct statmount __user *buf, size_t bufsize,5659 struct statmount __user *buf, size_t bufsize,
fs/notify/fanotify/fanotify.c+35−3
@@ -166,6 +166,8 @@ static bool fanotify_should_merge(struct fanotify_event *old, · 165 unmodified lines
166 case FANOTIFY_EVENT_TYPE_FS_ERROR:166 case FANOTIFY_EVENT_TYPE_FS_ERROR:
167 return fanotify_error_event_equal(FANOTIFY_EE(old),167 return fanotify_error_event_equal(FANOTIFY_EE(old),
168 FANOTIFY_EE(new));168 FANOTIFY_EE(new));
169 case FANOTIFY_EVENT_TYPE_MNT:
170 return false;
169 default:171 default:
170 WARN_ON_ONCE(1);172 WARN_ON_ONCE(1);
171 }173 }
@@ -312,7 +314,10 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, · 140 unmodified lines
312 pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",314 pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
313 __func__, iter_info->report_mask, event_mask, data, data_type);315 __func__, iter_info->report_mask, event_mask, data, data_type);
314 316
315 if (!fid_mode) {317 if (FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) {
318 if (data_type != FSNOTIFY_EVENT_MNT)
319 return 0;
320 } else if (!fid_mode) {
316 /* Do we have path to open a file descriptor? */321 /* Do we have path to open a file descriptor? */
317 if (!path)322 if (!path)
318 return 0;323 return 0;
@@ -557,6 +562,20 @@ static struct fanotify_event *fanotify_alloc_path_event(const struct path *path, · 238 unmodified lines
557 return &pevent->fae;562 return &pevent->fae;
558}563}
559 564
565static struct fanotify_event *fanotify_alloc_mnt_event(u64 mnt_id, gfp_t gfp)
566{
567 struct fanotify_mnt_event *pevent;
568
569 pevent = kmem_cache_alloc(fanotify_mnt_event_cachep, gfp);
570 if (!pevent)
571 return NULL;
572
573 pevent->fae.type = FANOTIFY_EVENT_TYPE_MNT;
574 pevent->mnt_id = mnt_id;
575
576 return &pevent->fae;
577}
578
560static struct fanotify_event *fanotify_alloc_perm_event(const void *data,579static struct fanotify_event *fanotify_alloc_perm_event(const void *data,
561 int data_type,580 int data_type,
562 gfp_t gfp)581 gfp_t gfp)
@@ -731,6 +750,7 @@ static struct fanotify_event *fanotify_alloc_event( · 168 unmodified lines
731 fid_mode);750 fid_mode);
732 struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir);751 struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir);
733 const struct path *path = fsnotify_data_path(data, data_type);752 const struct path *path = fsnotify_data_path(data, data_type);
753 u64 mnt_id = fsnotify_data_mnt_id(data, data_type);
734 struct mem_cgroup *old_memcg;754 struct mem_cgroup *old_memcg;
735 struct dentry *moved = NULL;755 struct dentry *moved = NULL;
736 struct inode *child = NULL;756 struct inode *child = NULL;
@@ -826,8 +846,12 @@ static struct fanotify_event *fanotify_alloc_event( · 89 unmodified lines
826 moved, &hash, gfp);846 moved, &hash, gfp);
827 } else if (fid_mode) {847 } else if (fid_mode) {
828 event = fanotify_alloc_fid_event(id, fsid, &hash, gfp);848 event = fanotify_alloc_fid_event(id, fsid, &hash, gfp);
829 } else {849 } else if (path) {
830 event = fanotify_alloc_path_event(path, &hash, gfp);850 event = fanotify_alloc_path_event(path, &hash, gfp);
851 } else if (mnt_id) {
852 event = fanotify_alloc_mnt_event(mnt_id, gfp);
853 } else {
854 WARN_ON_ONCE(1);
831 }855 }
832 856
833 if (!event)857 if (!event)
@@ -927,7 +951,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, · 93 unmodified lines
927 BUILD_BUG_ON(FAN_RENAME != FS_RENAME);951 BUILD_BUG_ON(FAN_RENAME != FS_RENAME);
928 BUILD_BUG_ON(FAN_PRE_ACCESS != FS_PRE_ACCESS);952 BUILD_BUG_ON(FAN_PRE_ACCESS != FS_PRE_ACCESS);
929 953
930 BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 22);954 BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 24);
931 955
932 mask = fanotify_group_event_mask(group, iter_info, &match_mask,956 mask = fanotify_group_event_mask(group, iter_info, &match_mask,
933 mask, data, data_type, dir);957 mask, data, data_type, dir);
@@ -1028,6 +1052,11 @@ static void fanotify_free_error_event(struct fsnotify_group *group, · 94 unmodified lines
1028 mempool_free(fee, &group->fanotify_data.error_events_pool);1052 mempool_free(fee, &group->fanotify_data.error_events_pool);
1029}1053}
1030 1054
1055static void fanotify_free_mnt_event(struct fanotify_event *event)
1056{
1057 kmem_cache_free(fanotify_mnt_event_cachep, FANOTIFY_ME(event));
1058}
1059
1031static void fanotify_free_event(struct fsnotify_group *group,1060static void fanotify_free_event(struct fsnotify_group *group,
1032 struct fsnotify_event *fsn_event)1061 struct fsnotify_event *fsn_event)
1033{1062{
@@ -1054,6 +1083,9 @@ static void fanotify_free_event(struct fsnotify_group *group, · 20 unmodified lines
1054 case FANOTIFY_EVENT_TYPE_FS_ERROR:1083 case FANOTIFY_EVENT_TYPE_FS_ERROR:
1055 fanotify_free_error_event(group, event);1084 fanotify_free_error_event(group, event);
1056 break;1085 break;
1086 case FANOTIFY_EVENT_TYPE_MNT:
1087 fanotify_free_mnt_event(event);
1088 break;
1057 default:1089 default:
1058 WARN_ON_ONCE(1);1090 WARN_ON_ONCE(1);
1059 }1091 }
fs/notify/fanotify/fanotify.h+18−0
@@ -9,6 +9,7 @@ extern struct kmem_cache *fanotify_mark_cache; · 8 unmodified lines
9extern struct kmem_cache *fanotify_fid_event_cachep;9extern struct kmem_cache *fanotify_fid_event_cachep;
10extern struct kmem_cache *fanotify_path_event_cachep;10extern struct kmem_cache *fanotify_path_event_cachep;
11extern struct kmem_cache *fanotify_perm_event_cachep;11extern struct kmem_cache *fanotify_perm_event_cachep;
12extern struct kmem_cache *fanotify_mnt_event_cachep;
12 13
13/* Possible states of the permission event */14/* Possible states of the permission event */
14enum {15enum {
@@ -244,6 +245,7 @@ enum fanotify_event_type { · 229 unmodified lines
244 FANOTIFY_EVENT_TYPE_PATH_PERM,245 FANOTIFY_EVENT_TYPE_PATH_PERM,
245 FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */246 FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */
246 FANOTIFY_EVENT_TYPE_FS_ERROR, /* struct fanotify_error_event */247 FANOTIFY_EVENT_TYPE_FS_ERROR, /* struct fanotify_error_event */
248 FANOTIFY_EVENT_TYPE_MNT,
247 __FANOTIFY_EVENT_TYPE_NUM249 __FANOTIFY_EVENT_TYPE_NUM
248};250};
249 251
@@ -409,12 +411,23 @@ struct fanotify_path_event { · 159 unmodified lines
409 struct path path;411 struct path path;
410};412};
411 413
414struct fanotify_mnt_event {
415 struct fanotify_event fae;
416 u64 mnt_id;
417};
418
412static inline struct fanotify_path_event *419static inline struct fanotify_path_event *
413FANOTIFY_PE(struct fanotify_event *event)420FANOTIFY_PE(struct fanotify_event *event)
414{421{
415 return container_of(event, struct fanotify_path_event, fae);422 return container_of(event, struct fanotify_path_event, fae);
416}423}
417 424
425static inline struct fanotify_mnt_event *
426FANOTIFY_ME(struct fanotify_event *event)
427{
428 return container_of(event, struct fanotify_mnt_event, fae);
429}
430
418/*431/*
419 * Structure for permission fanotify events. It gets allocated and freed in432 * Structure for permission fanotify events. It gets allocated and freed in
420 * fanotify_handle_event() since we wait there for user response. When the433 * fanotify_handle_event() since we wait there for user response. When the
@@ -466,6 +479,11 @@ static inline bool fanotify_is_error_event(u32 mask) · 45 unmodified lines
466 return mask & FAN_FS_ERROR;479 return mask & FAN_FS_ERROR;
467}480}
468 481
482static inline bool fanotify_is_mnt_event(u32 mask)
483{
484 return mask & (FAN_MNT_ATTACH | FAN_MNT_DETACH);
485}
486
469static inline const struct path *fanotify_event_path(struct fanotify_event *event)487static inline const struct path *fanotify_event_path(struct fanotify_event *event)
470{488{
471 if (event->type == FANOTIFY_EVENT_TYPE_PATH)489 if (event->type == FANOTIFY_EVENT_TYPE_PATH)
fs/notify/fanotify/fanotify_user.c+75−14
@@ -113,6 +113,7 @@ struct kmem_cache *fanotify_mark_cache __ro_after_init; · 112 unmodified lines
113struct kmem_cache *fanotify_fid_event_cachep __ro_after_init;113struct kmem_cache *fanotify_fid_event_cachep __ro_after_init;
114struct kmem_cache *fanotify_path_event_cachep __ro_after_init;114struct kmem_cache *fanotify_path_event_cachep __ro_after_init;
115struct kmem_cache *fanotify_perm_event_cachep __ro_after_init;115struct kmem_cache *fanotify_perm_event_cachep __ro_after_init;
116struct kmem_cache *fanotify_mnt_event_cachep __ro_after_init;
116 117
117#define FANOTIFY_EVENT_ALIGN 4118#define FANOTIFY_EVENT_ALIGN 4
118#define FANOTIFY_FID_INFO_HDR_LEN \119#define FANOTIFY_FID_INFO_HDR_LEN \
@@ -123,6 +124,8 @@ struct kmem_cache *fanotify_perm_event_cachep __ro_after_init; · 4 unmodified lines
123 (sizeof(struct fanotify_event_info_error))124 (sizeof(struct fanotify_event_info_error))
124#define FANOTIFY_RANGE_INFO_LEN \125#define FANOTIFY_RANGE_INFO_LEN \
125 (sizeof(struct fanotify_event_info_range))126 (sizeof(struct fanotify_event_info_range))
127#define FANOTIFY_MNT_INFO_LEN \
128 (sizeof(struct fanotify_event_info_mnt))
126 129
127static int fanotify_fid_info_len(int fh_len, int name_len)130static int fanotify_fid_info_len(int fh_len, int name_len)
128{131{
@@ -178,6 +181,8 @@ static size_t fanotify_event_len(unsigned int info_mode, · 49 unmodified lines
178 fh_len = fanotify_event_object_fh_len(event);181 fh_len = fanotify_event_object_fh_len(event);
179 event_len += fanotify_fid_info_len(fh_len, dot_len);182 event_len += fanotify_fid_info_len(fh_len, dot_len);
180 }183 }
184 if (fanotify_is_mnt_event(event->mask))
185 event_len += FANOTIFY_MNT_INFO_LEN;
181 186
182 if (info_mode & FAN_REPORT_PIDFD)187 if (info_mode & FAN_REPORT_PIDFD)
183 event_len += FANOTIFY_PIDFD_INFO_LEN;188 event_len += FANOTIFY_PIDFD_INFO_LEN;
@@ -405,6 +410,25 @@ static int process_access_response(struct fsnotify_group *group, · 221 unmodified lines
405 return -ENOENT;410 return -ENOENT;
406}411}
407 412
413static size_t copy_mnt_info_to_user(struct fanotify_event *event,
414 char __user *buf, int count)
415{
416 struct fanotify_event_info_mnt info = { };
417
418 info.hdr.info_type = FAN_EVENT_INFO_TYPE_MNT;
419 info.hdr.len = FANOTIFY_MNT_INFO_LEN;
420
421 if (WARN_ON(count < info.hdr.len))
422 return -EFAULT;
423
424 info.mnt_id = FANOTIFY_ME(event)->mnt_id;
425
426 if (copy_to_user(buf, &info, sizeof(info)))
427 return -EFAULT;
428
429 return info.hdr.len;
430}
431
408static size_t copy_error_info_to_user(struct fanotify_event *event,432static size_t copy_error_info_to_user(struct fanotify_event *event,
409 char __user *buf, int count)433 char __user *buf, int count)
410{434{
@@ -700,6 +724,15 @@ static int copy_info_records_to_user(struct fanotify_event *event, · 289 unmodified lines
700 total_bytes += ret;724 total_bytes += ret;
701 }725 }
702 726
727 if (fanotify_is_mnt_event(event->mask)) {
728 ret = copy_mnt_info_to_user(event, buf, count);
729 if (ret < 0)
730 return ret;
731 buf += ret;
732 count -= ret;
733 total_bytes += ret;
734 }
735
703 return total_bytes;736 return total_bytes;
704}737}
705 738
@@ -1508,6 +1541,14 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) · 802 unmodified lines
1508 if ((flags & FAN_REPORT_PIDFD) && (flags & FAN_REPORT_TID))1541 if ((flags & FAN_REPORT_PIDFD) && (flags & FAN_REPORT_TID))
1509 return -EINVAL;1542 return -EINVAL;
1510 1543
1544 /* Don't allow mixing mnt events with inode events for now */
1545 if (flags & FAN_REPORT_MNT) {
1546 if (class != FAN_CLASS_NOTIF)
1547 return -EINVAL;
1548 if (flags & (FANOTIFY_FID_BITS | FAN_REPORT_FD_ERROR))
1549 return -EINVAL;
1550 }
1551
1511 if (event_f_flags & ~FANOTIFY_INIT_ALL_EVENT_F_BITS)1552 if (event_f_flags & ~FANOTIFY_INIT_ALL_EVENT_F_BITS)
1512 return -EINVAL;1553 return -EINVAL;
1513 1554
@@ -1767,7 +1808,6 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 253 unmodified lines
1767 int dfd, const char __user *pathname)1808 int dfd, const char __user *pathname)
1768{1809{
1769 struct inode *inode = NULL;1810 struct inode *inode = NULL;
1770 struct vfsmount *mnt = NULL;
1771 struct fsnotify_group *group;1811 struct fsnotify_group *group;
1772 struct path path;1812 struct path path;
1773 struct fan_fsid __fsid, *fsid = NULL;1813 struct fan_fsid __fsid, *fsid = NULL;
@@ -1776,7 +1816,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 2 unmodified lines
1776 unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;1816 unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;
1777 unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS;1817 unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS;
1778 unsigned int obj_type, fid_mode;1818 unsigned int obj_type, fid_mode;
1779 void *obj;1819 void *obj = NULL;
1780 u32 umask = 0;1820 u32 umask = 0;
1781 int ret;1821 int ret;
1782 1822
@@ -1800,6 +1840,9 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 17 unmodified lines
1800 case FAN_MARK_FILESYSTEM:1840 case FAN_MARK_FILESYSTEM:
1801 obj_type = FSNOTIFY_OBJ_TYPE_SB;1841 obj_type = FSNOTIFY_OBJ_TYPE_SB;
1802 break;1842 break;
1843 case FAN_MARK_MNTNS:
1844 obj_type = FSNOTIFY_OBJ_TYPE_MNTNS;
1845 break;
1803 default:1846 default:
1804 return -EINVAL;1847 return -EINVAL;
1805 }1848 }
@@ -1847,6 +1890,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 41 unmodified lines
1847 return -EINVAL;1890 return -EINVAL;
1848 group = fd_file(f)->private_data;1891 group = fd_file(f)->private_data;
1849 1892
1893 /* Only report mount events on mnt namespace */
1894 if (FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) {
1895 if (mask & ~FANOTIFY_MOUNT_EVENTS)
1896 return -EINVAL;
1897 if (mark_type != FAN_MARK_MNTNS)
1898 return -EINVAL;
1899 } else {
1900 if (mask & FANOTIFY_MOUNT_EVENTS)
1901 return -EINVAL;
1902 if (mark_type == FAN_MARK_MNTNS)
1903 return -EINVAL;
1904 }
1905
1850 /*1906 /*
1851 * An unprivileged user is not allowed to setup mount nor filesystem1907 * An unprivileged user is not allowed to setup mount nor filesystem
1852 * marks. This also includes setting up such marks by a group that1908 * marks. This also includes setting up such marks by a group that
@@ -1888,7 +1944,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 35 unmodified lines
1888 * point.1944 * point.
1889 */1945 */
1890 fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);1946 fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
1891 if (mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_EVENT_FLAGS) &&1947 if (mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_MOUNT_EVENTS|FANOTIFY_EVENT_FLAGS) &&
1892 (!fid_mode || mark_type == FAN_MARK_MOUNT))1948 (!fid_mode || mark_type == FAN_MARK_MOUNT))
1893 return -EINVAL;1949 return -EINVAL;
1894 1950
@@ -1938,17 +1994,21 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 43 unmodified lines
1938 }1994 }
1939 1995
1940 /* inode held in place by reference to path; group by fget on fd */1996 /* inode held in place by reference to path; group by fget on fd */
1941 if (mark_type == FAN_MARK_INODE) {1997 if (obj_type == FSNOTIFY_OBJ_TYPE_INODE) {
1942 inode = path.dentry->d_inode;1998 inode = path.dentry->d_inode;
1943 obj = inode;1999 obj = inode;
1944 } else {2000 } else if (obj_type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
1945 mnt = path.mnt;2001 obj = path.mnt;
1946 if (mark_type == FAN_MARK_MOUNT)2002 } else if (obj_type == FSNOTIFY_OBJ_TYPE_SB) {
1947 obj = mnt;2003 obj = path.mnt->mnt_sb;
1948 else2004 } else if (obj_type == FSNOTIFY_OBJ_TYPE_MNTNS) {
1949 obj = mnt->mnt_sb;2005 obj = mnt_ns_from_dentry(path.dentry);
1950 }2006 }
1951 2007
2008 ret = -EINVAL;
2009 if (!obj)
2010 goto path_put_and_out;
2011
1952 /*2012 /*
1953 * If some other task has this inode open for write we should not add2013 * If some other task has this inode open for write we should not add
1954 * an ignore mask, unless that ignore mask is supposed to survive2014 * an ignore mask, unless that ignore mask is supposed to survive
@@ -1956,10 +2016,10 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 1 unmodified line
1956 */2016 */
1957 if (mark_cmd == FAN_MARK_ADD && (flags & FANOTIFY_MARK_IGNORE_BITS) &&2017 if (mark_cmd == FAN_MARK_ADD && (flags & FANOTIFY_MARK_IGNORE_BITS) &&
1958 !(flags & FAN_MARK_IGNORED_SURV_MODIFY)) {2018 !(flags & FAN_MARK_IGNORED_SURV_MODIFY)) {
1959 ret = mnt ? -EINVAL : -EISDIR;2019 ret = !inode ? -EINVAL : -EISDIR;
1960 /* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */2020 /* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */
1961 if (ignore == FAN_MARK_IGNORE &&2021 if (ignore == FAN_MARK_IGNORE &&
1962 (mnt || S_ISDIR(inode->i_mode)))2022 (!inode || S_ISDIR(inode->i_mode)))
1963 goto path_put_and_out;2023 goto path_put_and_out;
1964 2024
1965 ret = 0;2025 ret = 0;
@@ -1968,7 +2028,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, · 2 unmodified lines
1968 }2028 }
1969 2029
1970 /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */2030 /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */
1971 if (mnt || !S_ISDIR(inode->i_mode)) {2031 if (!inode || !S_ISDIR(inode->i_mode)) {
1972 mask &= ~FAN_EVENT_ON_CHILD;2032 mask &= ~FAN_EVENT_ON_CHILD;
1973 umask = FAN_EVENT_ON_CHILD;2033 umask = FAN_EVENT_ON_CHILD;
1974 /*2034 /*
@@ -2042,7 +2102,7 @@ static int __init fanotify_user_setup(void) · 67 unmodified lines
2042 FANOTIFY_DEFAULT_MAX_USER_MARKS);2102 FANOTIFY_DEFAULT_MAX_USER_MARKS);
2043 2103
2044 BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS);2104 BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS);
2045 BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 13);2105 BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 14);
2046 BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11);2106 BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11);
2047 2107
2048 fanotify_mark_cache = KMEM_CACHE(fanotify_mark,2108 fanotify_mark_cache = KMEM_CACHE(fanotify_mark,
@@ -2055,6 +2115,7 @@ static int __init fanotify_user_setup(void) · 6 unmodified lines
2055 fanotify_perm_event_cachep =2115 fanotify_perm_event_cachep =
2056 KMEM_CACHE(fanotify_perm_event, SLAB_PANIC);2116 KMEM_CACHE(fanotify_perm_event, SLAB_PANIC);
2057 }2117 }
2118 fanotify_mnt_event_cachep = KMEM_CACHE(fanotify_mnt_event, SLAB_PANIC);
2058 2119
2059 fanotify_max_queued_events = FANOTIFY_DEFAULT_MAX_EVENTS;2120 fanotify_max_queued_events = FANOTIFY_DEFAULT_MAX_EVENTS;
2060 init_user_ns.ucount_max[UCOUNT_FANOTIFY_GROUPS] =2121 init_user_ns.ucount_max[UCOUNT_FANOTIFY_GROUPS] =
fs/notify/fdinfo.c+5−0
@@ -121,6 +121,11 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) · 120 unmodified lines
121 121
122 seq_printf(m, "fanotify sdev:%x mflags:%x mask:%x ignored_mask:%x\n",122 seq_printf(m, "fanotify sdev:%x mflags:%x mask:%x ignored_mask:%x\n",
123 sb->s_dev, mflags, mark->mask, mark->ignore_mask);123 sb->s_dev, mflags, mark->mask, mark->ignore_mask);
124 } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_MNTNS) {
125 struct mnt_namespace *mnt_ns = fsnotify_conn_mntns(mark->connector);
126
127 seq_printf(m, "fanotify mnt_ns:%u mflags:%x mask:%x ignored_mask:%x\n",
128 mnt_ns->ns.inum, mflags, mark->mask, mark->ignore_mask);
124 }129 }
125}130}
126 131
fs/notify/fsnotify.c+40−7
@@ -28,6 +28,11 @@ void __fsnotify_vfsmount_delete(struct vfsmount *mnt) · 27 unmodified lines
28 fsnotify_clear_marks_by_mount(mnt);28 fsnotify_clear_marks_by_mount(mnt);
29}29}
30 30
31void __fsnotify_mntns_delete(struct mnt_namespace *mntns)
32{
33 fsnotify_clear_marks_by_mntns(mntns);
34}
35
31/**36/**
32 * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes.37 * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes.
33 * @sb: superblock being unmounted.38 * @sb: superblock being unmounted.
@@ -420,7 +425,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type, · 386 unmodified lines
420 file_name, cookie, iter_info);425 file_name, cookie, iter_info);
421}426}
422 427
423static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp)428static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector *const *connp)
424{429{
425 struct fsnotify_mark_connector *conn;430 struct fsnotify_mark_connector *conn;
426 struct hlist_node *node = NULL;431 struct hlist_node *node = NULL;
@@ -538,14 +543,15 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, · 111 unmodified lines
538{543{
539 const struct path *path = fsnotify_data_path(data, data_type);544 const struct path *path = fsnotify_data_path(data, data_type);
540 struct super_block *sb = fsnotify_data_sb(data, data_type);545 struct super_block *sb = fsnotify_data_sb(data, data_type);
541 struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);546 const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type);
547 struct fsnotify_sb_info *sbinfo = sb ? fsnotify_sb_info(sb) : NULL;
542 struct fsnotify_iter_info iter_info = {};548 struct fsnotify_iter_info iter_info = {};
543 struct mount *mnt = NULL;549 struct mount *mnt = NULL;
544 struct inode *inode2 = NULL;550 struct inode *inode2 = NULL;
545 struct dentry *moved;551 struct dentry *moved;
546 int inode2_type;552 int inode2_type;
547 int ret = 0;553 int ret = 0;
548 __u32 test_mask, marks_mask;554 __u32 test_mask, marks_mask = 0;
549 555
550 if (path)556 if (path)
551 mnt = real_mount(path->mnt);557 mnt = real_mount(path->mnt);
@@ -578,17 +584,20 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, · 26 unmodified lines
578 if ((!sbinfo || !sbinfo->sb_marks) &&584 if ((!sbinfo || !sbinfo->sb_marks) &&
579 (!mnt || !mnt->mnt_fsnotify_marks) &&585 (!mnt || !mnt->mnt_fsnotify_marks) &&
580 (!inode || !inode->i_fsnotify_marks) &&586 (!inode || !inode->i_fsnotify_marks) &&
581 (!inode2 || !inode2->i_fsnotify_marks))587 (!inode2 || !inode2->i_fsnotify_marks) &&
588 (!mnt_data || !mnt_data->ns->n_fsnotify_marks))
582 return 0;589 return 0;
583 590
584 marks_mask = READ_ONCE(sb->s_fsnotify_mask);591 if (sb)
592 marks_mask |= READ_ONCE(sb->s_fsnotify_mask);
585 if (mnt)593 if (mnt)
586 marks_mask |= READ_ONCE(mnt->mnt_fsnotify_mask);594 marks_mask |= READ_ONCE(mnt->mnt_fsnotify_mask);
587 if (inode)595 if (inode)
588 marks_mask |= READ_ONCE(inode->i_fsnotify_mask);596 marks_mask |= READ_ONCE(inode->i_fsnotify_mask);
589 if (inode2)597 if (inode2)
590 marks_mask |= READ_ONCE(inode2->i_fsnotify_mask);598 marks_mask |= READ_ONCE(inode2->i_fsnotify_mask);
591 599 if (mnt_data)
600 marks_mask |= READ_ONCE(mnt_data->ns->n_fsnotify_mask);
592 601
593 /*602 /*
594 * If this is a modify event we may need to clear some ignore masks.603 * If this is a modify event we may need to clear some ignore masks.
@@ -618,6 +627,10 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, · 23 unmodified lines
618 iter_info.marks[inode2_type] =627 iter_info.marks[inode2_type] =
619 fsnotify_first_mark(&inode2->i_fsnotify_marks);628 fsnotify_first_mark(&inode2->i_fsnotify_marks);
620 }629 }
630 if (mnt_data) {
631 iter_info.marks[FSNOTIFY_ITER_TYPE_MNTNS] =
632 fsnotify_first_mark(&mnt_data->ns->n_fsnotify_marks);
633 }
621 634
622 /*635 /*
623 * We need to merge inode/vfsmount/sb mark lists so that e.g. inode mark636 * We need to merge inode/vfsmount/sb mark lists so that e.g. inode mark
@@ -708,11 +721,31 @@ void file_set_fsnotify_mode_from_watchers(struct file *file) · 84 unmodified lines
708}721}
709#endif722#endif
710 723
724void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt)
725{
726 struct fsnotify_mnt data = {
727 .ns = ns,
728 .mnt_id = real_mount(mnt)->mnt_id_unique,
729 };
730
731 if (WARN_ON_ONCE(!ns))
732 return;
733
734 /*
735 * This is an optimization as well as making sure fsnotify_init() has
736 * been called.
737 */
738 if (!ns->n_fsnotify_marks)
739 return;
740
741 fsnotify(mask, &data, FSNOTIFY_EVENT_MNT, NULL, NULL, NULL, 0);
742}
743
711static __init int fsnotify_init(void)744static __init int fsnotify_init(void)
712{745{
713 int ret;746 int ret;
714 747
715 BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 24);748 BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 26);
716 749
717 ret = init_srcu_struct(&fsnotify_mark_srcu);750 ret = init_srcu_struct(&fsnotify_mark_srcu);
718 if (ret)751 if (ret)
fs/notify/fsnotify.h+11−0
@@ -33,6 +33,12 @@ static inline struct super_block *fsnotify_conn_sb( · 32 unmodified lines
33 return conn->obj;33 return conn->obj;
34}34}
35 35
36static inline struct mnt_namespace *fsnotify_conn_mntns(
37 struct fsnotify_mark_connector *conn)
38{
39 return conn->obj;
40}
41
36static inline struct super_block *fsnotify_object_sb(void *obj,42static inline struct super_block *fsnotify_object_sb(void *obj,
37 enum fsnotify_obj_type obj_type)43 enum fsnotify_obj_type obj_type)
38{44{
@@ -89,6 +95,11 @@ static inline void fsnotify_clear_marks_by_sb(struct super_block *sb) · 50 unmodified lines
89 fsnotify_destroy_marks(fsnotify_sb_marks(sb));95 fsnotify_destroy_marks(fsnotify_sb_marks(sb));
90}96}
91 97
98static inline void fsnotify_clear_marks_by_mntns(struct mnt_namespace *mntns)
99{
100 fsnotify_destroy_marks(&mntns->n_fsnotify_marks);
101}
102
92/*103/*
93 * update the dentry->d_flags of all of inode's children to indicate if inode cares104 * update the dentry->d_flags of all of inode's children to indicate if inode cares
94 * about events that happen to its children.105 * about events that happen to its children.
fs/notify/mark.c+11−3
@@ -107,6 +107,8 @@ static fsnotify_connp_t *fsnotify_object_connp(void *obj, · 106 unmodified lines
107 return &real_mount(obj)->mnt_fsnotify_marks;107 return &real_mount(obj)->mnt_fsnotify_marks;
108 case FSNOTIFY_OBJ_TYPE_SB:108 case FSNOTIFY_OBJ_TYPE_SB:
109 return fsnotify_sb_marks(obj);109 return fsnotify_sb_marks(obj);
110 case FSNOTIFY_OBJ_TYPE_MNTNS:
111 return &((struct mnt_namespace *)obj)->n_fsnotify_marks;
110 default:112 default:
111 return NULL;113 return NULL;
112 }114 }
@@ -120,6 +122,8 @@ static __u32 *fsnotify_conn_mask_p(struct fsnotify_mark_connector *conn) · 7 unmodified lines
120 return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask;122 return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask;
121 else if (conn->type == FSNOTIFY_OBJ_TYPE_SB)123 else if (conn->type == FSNOTIFY_OBJ_TYPE_SB)
122 return &fsnotify_conn_sb(conn)->s_fsnotify_mask;124 return &fsnotify_conn_sb(conn)->s_fsnotify_mask;
125 else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS)
126 return &fsnotify_conn_mntns(conn)->n_fsnotify_mask;
123 return NULL;127 return NULL;
124}128}
125 129
@@ -346,12 +350,15 @@ static void *fsnotify_detach_connector_from_object( · 220 unmodified lines
346 fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;350 fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;
347 } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) {351 } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) {
348 fsnotify_conn_sb(conn)->s_fsnotify_mask = 0;352 fsnotify_conn_sb(conn)->s_fsnotify_mask = 0;
353 } else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS) {
354 fsnotify_conn_mntns(conn)->n_fsnotify_mask = 0;
349 }355 }
350 356
351 rcu_assign_pointer(*connp, NULL);357 rcu_assign_pointer(*connp, NULL);
352 conn->obj = NULL;358 conn->obj = NULL;
353 conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;359 conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
354 fsnotify_update_sb_watchers(sb, conn);360 if (sb)
361 fsnotify_update_sb_watchers(sb, conn);
355 362
356 return inode;363 return inode;
357}364}
@@ -724,7 +731,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj, · 366 unmodified lines
724 * Attach the sb info before attaching a connector to any object on sb.731 * Attach the sb info before attaching a connector to any object on sb.
725 * The sb info will remain attached as long as sb lives.732 * The sb info will remain attached as long as sb lives.
726 */733 */
727 if (!fsnotify_sb_info(sb)) {734 if (sb && !fsnotify_sb_info(sb)) {
728 err = fsnotify_attach_info_to_sb(sb);735 err = fsnotify_attach_info_to_sb(sb);
729 if (err)736 if (err)
730 return err;737 return err;
@@ -770,7 +777,8 @@ restart: · 39 unmodified lines
770 /* mark should be the last entry. last is the current last entry */777 /* mark should be the last entry. last is the current last entry */
771 hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);778 hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
772added:779added:
773 fsnotify_update_sb_watchers(sb, conn);780 if (sb)
781 fsnotify_update_sb_watchers(sb, conn);
774 /*782 /*
775 * Since connector is attached to object using cmpxchg() we are783 * Since connector is attached to object using cmpxchg() we are
776 * guaranteed that connector initialization is fully visible by anyone784 * guaranteed that connector initialization is fully visible by anyone
fs/pnode.c+3−1
@@ -549,8 +549,10 @@ static void restore_mounts(struct list_head *to_restore) · 548 unmodified lines
549 mp = parent->mnt_mp;549 mp = parent->mnt_mp;
550 parent = parent->mnt_parent;550 parent = parent->mnt_parent;
551 }551 }
552 if (parent != mnt->mnt_parent)552 if (parent != mnt->mnt_parent) {
553 mnt_change_mountpoint(parent, mp, mnt);553 mnt_change_mountpoint(parent, mp, mnt);
554 mnt_notify_add(mnt);
555 }
554 }556 }
555}557}
556 558
include/linux/fanotify.h+8−4
@@ -25,7 +25,7 @@ · 24 unmodified lines
25 25
26#define FANOTIFY_FID_BITS (FAN_REPORT_DFID_NAME_TARGET)26#define FANOTIFY_FID_BITS (FAN_REPORT_DFID_NAME_TARGET)
27 27
28#define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD)28#define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD | FAN_REPORT_MNT)
29 29
30/*30/*
31 * fanotify_init() flags that require CAP_SYS_ADMIN.31 * fanotify_init() flags that require CAP_SYS_ADMIN.
@@ -38,7 +38,8 @@ · 6 unmodified lines
38 FAN_REPORT_PIDFD | \38 FAN_REPORT_PIDFD | \
39 FAN_REPORT_FD_ERROR | \39 FAN_REPORT_FD_ERROR | \
40 FAN_UNLIMITED_QUEUE | \40 FAN_UNLIMITED_QUEUE | \
41 FAN_UNLIMITED_MARKS)41 FAN_UNLIMITED_MARKS | \
42 FAN_REPORT_MNT)
42 43
43/*44/*
44 * fanotify_init() flags that are allowed for user without CAP_SYS_ADMIN.45 * fanotify_init() flags that are allowed for user without CAP_SYS_ADMIN.
@@ -58,7 +59,7 @@ · 13 unmodified lines
58#define FANOTIFY_INTERNAL_GROUP_FLAGS (FANOTIFY_UNPRIV)59#define FANOTIFY_INTERNAL_GROUP_FLAGS (FANOTIFY_UNPRIV)
59 60
60#define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \61#define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \
61 FAN_MARK_FILESYSTEM)62 FAN_MARK_FILESYSTEM | FAN_MARK_MNTNS)
62 63
63#define FANOTIFY_MARK_CMD_BITS (FAN_MARK_ADD | FAN_MARK_REMOVE | \64#define FANOTIFY_MARK_CMD_BITS (FAN_MARK_ADD | FAN_MARK_REMOVE | \
64 FAN_MARK_FLUSH)65 FAN_MARK_FLUSH)
@@ -109,10 +110,13 @@ · 44 unmodified lines
109/* Events that can only be reported with data type FSNOTIFY_EVENT_ERROR */110/* Events that can only be reported with data type FSNOTIFY_EVENT_ERROR */
110#define FANOTIFY_ERROR_EVENTS (FAN_FS_ERROR)111#define FANOTIFY_ERROR_EVENTS (FAN_FS_ERROR)
111 112
113#define FANOTIFY_MOUNT_EVENTS (FAN_MNT_ATTACH | FAN_MNT_DETACH)
114
112/* Events that user can request to be notified on */115/* Events that user can request to be notified on */
113#define FANOTIFY_EVENTS (FANOTIFY_PATH_EVENTS | \116#define FANOTIFY_EVENTS (FANOTIFY_PATH_EVENTS | \
114 FANOTIFY_INODE_EVENTS | \117 FANOTIFY_INODE_EVENTS | \
115 FANOTIFY_ERROR_EVENTS)118 FANOTIFY_ERROR_EVENTS | \
119 FANOTIFY_MOUNT_EVENTS)
116 120
117/* Extra flags that may be reported with event or control handling of events */121/* Extra flags that may be reported with event or control handling of events */
118#define FANOTIFY_EVENT_FLAGS (FAN_EVENT_ON_CHILD | FAN_ONDIR)122#define FANOTIFY_EVENT_FLAGS (FAN_EVENT_ON_CHILD | FAN_ONDIR)
include/linux/fsnotify.h+20−0
@@ -320,6 +320,11 @@ static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt) · 319 unmodified lines
320 __fsnotify_vfsmount_delete(mnt);320 __fsnotify_vfsmount_delete(mnt);
321}321}
322 322
323static inline void fsnotify_mntns_delete(struct mnt_namespace *mntns)
324{
325 __fsnotify_mntns_delete(mntns);
326}
327
323/*328/*
324 * fsnotify_inoderemove - an inode is going away329 * fsnotify_inoderemove - an inode is going away
325 */330 */
@@ -528,4 +533,19 @@ static inline int fsnotify_sb_error(struct super_block *sb, struct inode *inode, · 202 unmodified lines
528 NULL, NULL, NULL, 0);533 NULL, NULL, NULL, 0);
529}534}
530 535
536static inline void fsnotify_mnt_attach(struct mnt_namespace *ns, struct vfsmount *mnt)
537{
538 fsnotify_mnt(FS_MNT_ATTACH, ns, mnt);
539}
540
541static inline void fsnotify_mnt_detach(struct mnt_namespace *ns, struct vfsmount *mnt)
542{
543 fsnotify_mnt(FS_MNT_DETACH, ns, mnt);
544}
545
546static inline void fsnotify_mnt_move(struct mnt_namespace *ns, struct vfsmount *mnt)
547{
548 fsnotify_mnt(FS_MNT_MOVE, ns, mnt);
549}
550
531#endif /* _LINUX_FS_NOTIFY_H */551#endif /* _LINUX_FS_NOTIFY_H */
include/linux/fsnotify_backend.h+42−0
@@ -59,6 +59,10 @@ · 58 unmodified lines
59 59
60#define FS_PRE_ACCESS 0x00100000 /* Pre-content access hook */60#define FS_PRE_ACCESS 0x00100000 /* Pre-content access hook */
61 61
62#define FS_MNT_ATTACH 0x01000000 /* Mount was attached */
63#define FS_MNT_DETACH 0x02000000 /* Mount was detached */
64#define FS_MNT_MOVE (FS_MNT_ATTACH | FS_MNT_DETACH)
65
62/*66/*
63 * Set on inode mark that cares about things that happen to its children.67 * Set on inode mark that cares about things that happen to its children.
64 * Always set for dnotify and inotify.68 * Always set for dnotify and inotify.
@@ -80,6 +84,9 @@ · 15 unmodified lines
80 */84 */
81#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME)85#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME)
82 86
87/* Mount namespace events */
88#define FSNOTIFY_MNT_EVENTS (FS_MNT_ATTACH | FS_MNT_DETACH)
89
83/* Content events can be used to inspect file content */90/* Content events can be used to inspect file content */
84#define FSNOTIFY_CONTENT_PERM_EVENTS (FS_OPEN_PERM | FS_OPEN_EXEC_PERM | \91#define FSNOTIFY_CONTENT_PERM_EVENTS (FS_OPEN_PERM | FS_OPEN_EXEC_PERM | \
85 FS_ACCESS_PERM)92 FS_ACCESS_PERM)
@@ -108,6 +115,7 @@ · 22 unmodified lines
108 115
109/* Events that can be reported to backends */116/* Events that can be reported to backends */
110#define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \117#define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \
118 FSNOTIFY_MNT_EVENTS | \
111 FS_EVENTS_POSS_ON_CHILD | \119 FS_EVENTS_POSS_ON_CHILD | \
112 FS_DELETE_SELF | FS_MOVE_SELF | \120 FS_DELETE_SELF | FS_MOVE_SELF | \
113 FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \121 FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \
@@ -298,6 +306,7 @@ enum fsnotify_data_type { · 184 unmodified lines
298 FSNOTIFY_EVENT_PATH,306 FSNOTIFY_EVENT_PATH,
299 FSNOTIFY_EVENT_INODE,307 FSNOTIFY_EVENT_INODE,
300 FSNOTIFY_EVENT_DENTRY,308 FSNOTIFY_EVENT_DENTRY,
309 FSNOTIFY_EVENT_MNT,
301 FSNOTIFY_EVENT_ERROR,310 FSNOTIFY_EVENT_ERROR,
302};311};
303 312
@@ -318,6 +327,11 @@ static inline const struct path *file_range_path(const struct file_range *range) · 14 unmodified lines
318 return range->path;327 return range->path;
319}328}
320 329
330struct fsnotify_mnt {
331 const struct mnt_namespace *ns;
332 u64 mnt_id;
333};
334
321static inline struct inode *fsnotify_data_inode(const void *data, int data_type)335static inline struct inode *fsnotify_data_inode(const void *data, int data_type)
322{336{
323 switch (data_type) {337 switch (data_type) {
@@ -383,6 +397,24 @@ static inline struct super_block *fsnotify_data_sb(const void *data, · 59 unmodified lines
383 }397 }
384}398}
385 399
400static inline const struct fsnotify_mnt *fsnotify_data_mnt(const void *data,
401 int data_type)
402{
403 switch (data_type) {
404 case FSNOTIFY_EVENT_MNT:
405 return data;
406 default:
407 return NULL;
408 }
409}
410
411static inline u64 fsnotify_data_mnt_id(const void *data, int data_type)
412{
413 const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type);
414
415 return mnt_data ? mnt_data->mnt_id : 0;
416}
417
386static inline struct fs_error_report *fsnotify_data_error_report(418static inline struct fs_error_report *fsnotify_data_error_report(
387 const void *data,419 const void *data,
388 int data_type)420 int data_type)
@@ -420,6 +452,7 @@ enum fsnotify_iter_type { · 31 unmodified lines
420 FSNOTIFY_ITER_TYPE_SB,452 FSNOTIFY_ITER_TYPE_SB,
421 FSNOTIFY_ITER_TYPE_PARENT,453 FSNOTIFY_ITER_TYPE_PARENT,
422 FSNOTIFY_ITER_TYPE_INODE2,454 FSNOTIFY_ITER_TYPE_INODE2,
455 FSNOTIFY_ITER_TYPE_MNTNS,
423 FSNOTIFY_ITER_TYPE_COUNT456 FSNOTIFY_ITER_TYPE_COUNT
424};457};
425 458
@@ -429,6 +462,7 @@ enum fsnotify_obj_type { · 3 unmodified lines
429 FSNOTIFY_OBJ_TYPE_INODE,462 FSNOTIFY_OBJ_TYPE_INODE,
430 FSNOTIFY_OBJ_TYPE_VFSMOUNT,463 FSNOTIFY_OBJ_TYPE_VFSMOUNT,
431 FSNOTIFY_OBJ_TYPE_SB,464 FSNOTIFY_OBJ_TYPE_SB,
465 FSNOTIFY_OBJ_TYPE_MNTNS,
432 FSNOTIFY_OBJ_TYPE_COUNT,466 FSNOTIFY_OBJ_TYPE_COUNT,
433 FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT467 FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT
434};468};
@@ -613,8 +647,10 @@ extern int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data · 178 unmodified lines
613extern void __fsnotify_inode_delete(struct inode *inode);647extern void __fsnotify_inode_delete(struct inode *inode);
614extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);648extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
615extern void fsnotify_sb_delete(struct super_block *sb);649extern void fsnotify_sb_delete(struct super_block *sb);
650extern void __fsnotify_mntns_delete(struct mnt_namespace *mntns);
616extern void fsnotify_sb_free(struct super_block *sb);651extern void fsnotify_sb_free(struct super_block *sb);
617extern u32 fsnotify_get_cookie(void);652extern u32 fsnotify_get_cookie(void);
653extern void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt);
618 654
619static inline __u32 fsnotify_parent_needed_mask(__u32 mask)655static inline __u32 fsnotify_parent_needed_mask(__u32 mask)
620{656{
@@ -928,6 +964,9 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) · 307 unmodified lines
928static inline void fsnotify_sb_delete(struct super_block *sb)964static inline void fsnotify_sb_delete(struct super_block *sb)
929{}965{}
930 966
967static inline void __fsnotify_mntns_delete(struct mnt_namespace *mntns)
968{}
969
931static inline void fsnotify_sb_free(struct super_block *sb)970static inline void fsnotify_sb_free(struct super_block *sb)
932{}971{}
933 972
@@ -942,6 +981,9 @@ static inline u32 fsnotify_get_cookie(void) · 8 unmodified lines
942static inline void fsnotify_unmount_inodes(struct super_block *sb)981static inline void fsnotify_unmount_inodes(struct super_block *sb)
943{}982{}
944 983
984static inline void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt)
985{}
986
945#endif /* CONFIG_FSNOTIFY */987#endif /* CONFIG_FSNOTIFY */
946 988
947#endif /* __KERNEL __ */989#endif /* __KERNEL __ */
include/linux/mnt_idmapping.h+5−0
@@ -25,6 +25,11 @@ static_assert(sizeof(vfsgid_t) == sizeof(kgid_t)); · 24 unmodified lines
25static_assert(offsetof(vfsuid_t, val) == offsetof(kuid_t, val));25static_assert(offsetof(vfsuid_t, val) == offsetof(kuid_t, val));
26static_assert(offsetof(vfsgid_t, val) == offsetof(kgid_t, val));26static_assert(offsetof(vfsgid_t, val) == offsetof(kgid_t, val));
27 27
28static inline bool is_valid_mnt_idmap(const struct mnt_idmap *idmap)
29{
30 return idmap != &nop_mnt_idmap && idmap != &invalid_mnt_idmap;
31}
32
28#ifdef CONFIG_MULTIUSER33#ifdef CONFIG_MULTIUSER
29static inline uid_t __vfsuid_val(vfsuid_t uid)34static inline uid_t __vfsuid_val(vfsuid_t uid)
30{35{
include/linux/syscalls.h+4−0
@@ -951,6 +951,10 @@ asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, · 950 unmodified lines
951asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len,951asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len,
952 int flags, uint32_t sig);952 int flags, uint32_t sig);
953asmlinkage long sys_open_tree(int dfd, const char __user *path, unsigned flags);953asmlinkage long sys_open_tree(int dfd, const char __user *path, unsigned flags);
954asmlinkage long sys_open_tree_attr(int dfd, const char __user *path,
955 unsigned flags,
956 struct mount_attr __user *uattr,
957 size_t usize);
954asmlinkage long sys_move_mount(int from_dfd, const char __user *from_path,958asmlinkage long sys_move_mount(int from_dfd, const char __user *from_path,
955 int to_dfd, const char __user *to_path,959 int to_dfd, const char __user *to_path,
956 unsigned int ms_flags);960 unsigned int ms_flags);
include/linux/uidgid.h+6−0
@@ -132,6 +132,7 @@ static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid) · 131 unmodified lines
132 132
133u32 map_id_down(struct uid_gid_map *map, u32 id);133u32 map_id_down(struct uid_gid_map *map, u32 id);
134u32 map_id_up(struct uid_gid_map *map, u32 id);134u32 map_id_up(struct uid_gid_map *map, u32 id);
135u32 map_id_range_up(struct uid_gid_map *map, u32 id, u32 count);
135 136
136#else137#else
137 138
@@ -186,6 +187,11 @@ static inline u32 map_id_down(struct uid_gid_map *map, u32 id) · 48 unmodified lines
186 return id;187 return id;
187}188}
188 189
190static inline u32 map_id_range_up(struct uid_gid_map *map, u32 id, u32 count)
191{
192 return id;
193}
194
189static inline u32 map_id_up(struct uid_gid_map *map, u32 id)195static inline u32 map_id_up(struct uid_gid_map *map, u32 id)
190{196{
191 return id;197 return id;
include/uapi/asm-generic/unistd.h+3−1
@@ -849,9 +849,11 @@ __SYSCALL(__NR_getxattrat, sys_getxattrat) · 848 unmodified lines
849__SYSCALL(__NR_listxattrat, sys_listxattrat)849__SYSCALL(__NR_listxattrat, sys_listxattrat)
850#define __NR_removexattrat 466850#define __NR_removexattrat 466
851__SYSCALL(__NR_removexattrat, sys_removexattrat)851__SYSCALL(__NR_removexattrat, sys_removexattrat)
852#define __NR_open_tree_attr 467
853__SYSCALL(__NR_open_tree_attr, sys_open_tree_attr)
852 854
853#undef __NR_syscalls855#undef __NR_syscalls
854#define __NR_syscalls 467856#define __NR_syscalls 468
855 857
856/*858/*
857 * 32 bit systems traditionally used different859 * 32 bit systems traditionally used different
include/uapi/linux/fanotify.h+10−0
@@ -28,6 +28,8 @@ · 27 unmodified lines
28/* #define FAN_DIR_MODIFY 0x00080000 */ /* Deprecated (reserved) */28/* #define FAN_DIR_MODIFY 0x00080000 */ /* Deprecated (reserved) */
29 29
30#define FAN_PRE_ACCESS 0x00100000 /* Pre-content access hook */30#define FAN_PRE_ACCESS 0x00100000 /* Pre-content access hook */
31#define FAN_MNT_ATTACH 0x01000000 /* Mount was attached */
32#define FAN_MNT_DETACH 0x02000000 /* Mount was detached */
31 33
32#define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */34#define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */
33 35
@@ -64,6 +66,7 @@ · 30 unmodified lines
64#define FAN_REPORT_NAME 0x00000800 /* Report events with name */66#define FAN_REPORT_NAME 0x00000800 /* Report events with name */
65#define FAN_REPORT_TARGET_FID 0x00001000 /* Report dirent target id */67#define FAN_REPORT_TARGET_FID 0x00001000 /* Report dirent target id */
66#define FAN_REPORT_FD_ERROR 0x00002000 /* event->fd can report error */68#define FAN_REPORT_FD_ERROR 0x00002000 /* event->fd can report error */
69#define FAN_REPORT_MNT 0x00004000 /* Report mount events */
67 70
68/* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */71/* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */
69#define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME)72#define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME)
@@ -94,6 +97,7 @@ · 24 unmodified lines
94#define FAN_MARK_INODE 0x0000000097#define FAN_MARK_INODE 0x00000000
95#define FAN_MARK_MOUNT 0x0000001098#define FAN_MARK_MOUNT 0x00000010
96#define FAN_MARK_FILESYSTEM 0x0000010099#define FAN_MARK_FILESYSTEM 0x00000100
100#define FAN_MARK_MNTNS 0x00000110
97 101
98/*102/*
99 * Convenience macro - FAN_MARK_IGNORE requires FAN_MARK_IGNORED_SURV_MODIFY103 * Convenience macro - FAN_MARK_IGNORE requires FAN_MARK_IGNORED_SURV_MODIFY
@@ -147,6 +151,7 @@ struct fanotify_event_metadata { · 47 unmodified lines
147#define FAN_EVENT_INFO_TYPE_PIDFD 4151#define FAN_EVENT_INFO_TYPE_PIDFD 4
148#define FAN_EVENT_INFO_TYPE_ERROR 5152#define FAN_EVENT_INFO_TYPE_ERROR 5
149#define FAN_EVENT_INFO_TYPE_RANGE 6153#define FAN_EVENT_INFO_TYPE_RANGE 6
154#define FAN_EVENT_INFO_TYPE_MNT 7
150 155
151/* Special info types for FAN_RENAME */156/* Special info types for FAN_RENAME */
152#define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME 10157#define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME 10
@@ -200,6 +205,11 @@ struct fanotify_event_info_range { · 47 unmodified lines
200 __u64 count;205 __u64 count;
201};206};
202 207
208struct fanotify_event_info_mnt {
209 struct fanotify_event_info_header hdr;
210 __u64 mnt_id;
211};
212
203/*213/*
204 * User space may need to record additional information about its decision.214 * User space may need to record additional information about its decision.
205 * The extra information type records what kind of information is included.215 * The extra information type records what kind of information is included.
include/uapi/linux/mount.h+9−1
@@ -179,7 +179,12 @@ struct statmount { · 178 unmodified lines
179 __u32 opt_array; /* [str] Array of nul terminated fs options */179 __u32 opt_array; /* [str] Array of nul terminated fs options */
180 __u32 opt_sec_num; /* Number of security options */180 __u32 opt_sec_num; /* Number of security options */
181 __u32 opt_sec_array; /* [str] Array of nul terminated security options */181 __u32 opt_sec_array; /* [str] Array of nul terminated security options */
182 __u64 __spare2[46];182 __u64 supported_mask; /* Mask flags that this kernel supports */
183 __u32 mnt_uidmap_num; /* Number of uid mappings */
184 __u32 mnt_uidmap; /* [str] Array of uid mappings (as seen from callers namespace) */
185 __u32 mnt_gidmap_num; /* Number of gid mappings */
186 __u32 mnt_gidmap; /* [str] Array of gid mappings (as seen from callers namespace) */
187 __u64 __spare2[43];
183 char str[]; /* Variable size part containing strings */188 char str[]; /* Variable size part containing strings */
184};189};
185 190
@@ -217,6 +222,9 @@ struct mnt_id_req { · 31 unmodified lines
217#define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */222#define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */
218#define STATMOUNT_OPT_ARRAY 0x00000400U /* Want/got opt_... */223#define STATMOUNT_OPT_ARRAY 0x00000400U /* Want/got opt_... */
219#define STATMOUNT_OPT_SEC_ARRAY 0x00000800U /* Want/got opt_sec... */224#define STATMOUNT_OPT_SEC_ARRAY 0x00000800U /* Want/got opt_sec... */
225#define STATMOUNT_SUPPORTED_MASK 0x00001000U /* Want/got supported mask flags */
226#define STATMOUNT_MNT_UIDMAP 0x00002000U /* Want/got uidmap... */
227#define STATMOUNT_MNT_GIDMAP 0x00004000U /* Want/got gidmap... */
220 228
221/*229/*
222 * Special @mnt_id values that can be passed to listmount230 * Special @mnt_id values that can be passed to listmount
kernel/user_namespace.c+17−9
@@ -238,7 +238,7 @@ EXPORT_SYMBOL(__put_user_ns); · 237 unmodified lines
238struct idmap_key {238struct idmap_key {
239 bool map_up; /* true -> id from kid; false -> kid from id */239 bool map_up; /* true -> id from kid; false -> kid from id */
240 u32 id; /* id to find */240 u32 id; /* id to find */
241 u32 count; /* == 0 unless used with map_id_range_down() */241 u32 count;
242};242};
243 243
244/*244/*
@@ -343,16 +343,19 @@ u32 map_id_down(struct uid_gid_map *map, u32 id) · 98 unmodified lines
343 * UID_GID_MAP_MAX_BASE_EXTENTS.343 * UID_GID_MAP_MAX_BASE_EXTENTS.
344 */344 */
345static struct uid_gid_extent *345static struct uid_gid_extent *
346map_id_up_base(unsigned extents, struct uid_gid_map *map, u32 id)346map_id_range_up_base(unsigned extents, struct uid_gid_map *map, u32 id, u32 count)
347{347{
348 unsigned idx;348 unsigned idx;
349 u32 first, last;349 u32 first, last, id2;
350
351 id2 = id + count - 1;
350 352
351 /* Find the matching extent */353 /* Find the matching extent */
352 for (idx = 0; idx < extents; idx++) {354 for (idx = 0; idx < extents; idx++) {
353 first = map->extent[idx].lower_first;355 first = map->extent[idx].lower_first;
354 last = first + map->extent[idx].count - 1;356 last = first + map->extent[idx].count - 1;
355 if (id >= first && id <= last)357 if (id >= first && id <= last &&
358 (id2 >= first && id2 <= last))
356 return &map->extent[idx];359 return &map->extent[idx];
357 }360 }
358 return NULL;361 return NULL;
@@ -363,28 +366,28 @@ map_id_up_base(unsigned extents, struct uid_gid_map *map, u32 id) · 4 unmodified lines
363 * Can only be called if number of mappings exceeds UID_GID_MAP_MAX_BASE_EXTENTS.366 * Can only be called if number of mappings exceeds UID_GID_MAP_MAX_BASE_EXTENTS.
364 */367 */
365static struct uid_gid_extent *368static struct uid_gid_extent *
366map_id_up_max(unsigned extents, struct uid_gid_map *map, u32 id)369map_id_range_up_max(unsigned extents, struct uid_gid_map *map, u32 id, u32 count)
367{370{
368 struct idmap_key key;371 struct idmap_key key;
369 372
370 key.map_up = true;373 key.map_up = true;
371 key.count = 1;374 key.count = count;
372 key.id = id;375 key.id = id;
373 376
374 return bsearch(&key, map->reverse, extents,377 return bsearch(&key, map->reverse, extents,
375 sizeof(struct uid_gid_extent), cmp_map_id);378 sizeof(struct uid_gid_extent), cmp_map_id);
376}379}
377 380
378u32 map_id_up(struct uid_gid_map *map, u32 id)381u32 map_id_range_up(struct uid_gid_map *map, u32 id, u32 count)
379{382{
380 struct uid_gid_extent *extent;383 struct uid_gid_extent *extent;
381 unsigned extents = map->nr_extents;384 unsigned extents = map->nr_extents;
382 smp_rmb();385 smp_rmb();
383 386
384 if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS)387 if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
385 extent = map_id_up_base(extents, map, id);388 extent = map_id_range_up_base(extents, map, id, count);
386 else389 else
387 extent = map_id_up_max(extents, map, id);390 extent = map_id_range_up_max(extents, map, id, count);
388 391
389 /* Map the id or note failure */392 /* Map the id or note failure */
390 if (extent)393 if (extent)
@@ -395,6 +398,11 @@ u32 map_id_up(struct uid_gid_map *map, u32 id) · 4 unmodified lines
395 return id;398 return id;
396}399}
397 400
401u32 map_id_up(struct uid_gid_map *map, u32 id)
402{
403 return map_id_range_up(map, id, 1);
404}
405
398/**406/**
399 * make_kuid - Map a user-namespace uid pair into a kuid.407 * make_kuid - Map a user-namespace uid pair into a kuid.
400 * @ns: User namespace that the uid is in408 * @ns: User namespace that the uid is in
samples/vfs/samples-vfs.h+13−1
@@ -42,7 +42,11 @@ struct statmount { · 41 unmodified lines
42 __u32 opt_array; /* [str] Array of nul terminated fs options */42 __u32 opt_array; /* [str] Array of nul terminated fs options */
43 __u32 opt_sec_num; /* Number of security options */43 __u32 opt_sec_num; /* Number of security options */
44 __u32 opt_sec_array; /* [str] Array of nul terminated security options */44 __u32 opt_sec_array; /* [str] Array of nul terminated security options */
45 __u64 __spare2[46];45 __u32 mnt_uidmap_num; /* Number of uid mappings */
46 __u32 mnt_uidmap; /* [str] Array of uid mappings */
47 __u32 mnt_gidmap_num; /* Number of gid mappings */
48 __u32 mnt_gidmap; /* [str] Array of gid mappings */
49 __u64 __spare2[44];
46 char str[]; /* Variable size part containing strings */50 char str[]; /* Variable size part containing strings */
47};51};
48 52
@@ -158,6 +162,14 @@ struct mnt_ns_info { · 109 unmodified lines
158#define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */162#define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */
159#endif163#endif
160 164
165#ifndef STATMOUNT_MNT_UIDMAP
166#define STATMOUNT_MNT_UIDMAP 0x00002000U /* Want/got uidmap... */
167#endif
168
169#ifndef STATMOUNT_MNT_GIDMAP
170#define STATMOUNT_MNT_GIDMAP 0x00004000U /* Want/got gidmap... */
171#endif
172
161#ifndef MOUNT_ATTR_RDONLY173#ifndef MOUNT_ATTR_RDONLY
162#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */174#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */
163#endif175#endif
samples/vfs/test-list-all-mounts.c+29−6
@@ -128,20 +128,43 @@ next: · 127 unmodified lines
128 STATMOUNT_MNT_POINT |128 STATMOUNT_MNT_POINT |
129 STATMOUNT_MNT_NS_ID |129 STATMOUNT_MNT_NS_ID |
130 STATMOUNT_MNT_OPTS |130 STATMOUNT_MNT_OPTS |
131 STATMOUNT_FS_TYPE, 0);131 STATMOUNT_FS_TYPE |
132 STATMOUNT_MNT_UIDMAP |
133 STATMOUNT_MNT_GIDMAP, 0);
132 if (!stmnt) {134 if (!stmnt) {
133 printf("Failed to statmount(%" PRIu64 ") in mount namespace(%" PRIu64 ")\n",135 printf("Failed to statmount(%" PRIu64 ") in mount namespace(%" PRIu64 ")\n",
134 (uint64_t)last_mnt_id, (uint64_t)info.mnt_ns_id);136 (uint64_t)last_mnt_id, (uint64_t)info.mnt_ns_id);
135 continue;137 continue;
136 }138 }
137 139
138 printf("mnt_id:\t\t%" PRIu64 "\nmnt_parent_id:\t%" PRIu64 "\nfs_type:\t%s\nmnt_root:\t%s\nmnt_point:\t%s\nmnt_opts:\t%s\n\n",140 printf("mnt_id:\t\t%" PRIu64 "\nmnt_parent_id:\t%" PRIu64 "\nfs_type:\t%s\nmnt_root:\t%s\nmnt_point:\t%s\nmnt_opts:\t%s\n",
139 (uint64_t)stmnt->mnt_id,141 (uint64_t)stmnt->mnt_id,
140 (uint64_t)stmnt->mnt_parent_id,142 (uint64_t)stmnt->mnt_parent_id,
141 stmnt->str + stmnt->fs_type,143 (stmnt->mask & STATMOUNT_FS_TYPE) ? stmnt->str + stmnt->fs_type : "",
142 stmnt->str + stmnt->mnt_root,144 (stmnt->mask & STATMOUNT_MNT_ROOT) ? stmnt->str + stmnt->mnt_root : "",
143 stmnt->str + stmnt->mnt_point,145 (stmnt->mask & STATMOUNT_MNT_POINT) ? stmnt->str + stmnt->mnt_point : "",
144 stmnt->str + stmnt->mnt_opts);146 (stmnt->mask & STATMOUNT_MNT_OPTS) ? stmnt->str + stmnt->mnt_opts : "");
147
148 if (stmnt->mask & STATMOUNT_MNT_UIDMAP) {
149 const char *idmap = stmnt->str + stmnt->mnt_uidmap;
150
151 for (size_t idx = 0; idx < stmnt->mnt_uidmap_num; idx++) {
152 printf("mnt_uidmap[%zu]:\t%s\n", idx, idmap);
153 idmap += strlen(idmap) + 1;
154 }
155 }
156
157 if (stmnt->mask & STATMOUNT_MNT_GIDMAP) {
158 const char *idmap = stmnt->str + stmnt->mnt_gidmap;
159
160 for (size_t idx = 0; idx < stmnt->mnt_gidmap_num; idx++) {
161 printf("mnt_gidmap[%zu]:\t%s\n", idx, idmap);
162 idmap += strlen(idmap) + 1;
163 }
164 }
165
166 printf("\n");
167
145 free(stmnt);168 free(stmnt);
146 }169 }
147 }170 }
scripts/syscall.tbl+1−0
@@ -407,3 +407,4 @@ · 406 unmodified lines
407464 common getxattrat sys_getxattrat407464 common getxattrat sys_getxattrat
408465 common listxattrat sys_listxattrat408465 common listxattrat sys_listxattrat
409466 common removexattrat sys_removexattrat409466 common removexattrat sys_removexattrat
410467 common open_tree_attr sys_open_tree_attr
security/selinux/hooks.c+3−0
@@ -3395,6 +3395,9 @@ static int selinux_path_notify(const struct path *path, u64 mask, · 3394 unmodified lines
3395 case FSNOTIFY_OBJ_TYPE_INODE:3395 case FSNOTIFY_OBJ_TYPE_INODE:
3396 perm = FILE__WATCH;3396 perm = FILE__WATCH;
3397 break;3397 break;
3398 case FSNOTIFY_OBJ_TYPE_MNTNS:
3399 perm = FILE__WATCH_MOUNTNS;
3400 break;
3398 default:3401 default:
3399 return -EINVAL;3402 return -EINVAL;
3400 }3403 }
security/selinux/include/classmap.h+1−1
@@ -8,7 +8,7 @@ · 7 unmodified lines
8 COMMON_FILE_SOCK_PERMS, "unlink", "link", "rename", "execute", \8 COMMON_FILE_SOCK_PERMS, "unlink", "link", "rename", "execute", \
9 "quotaon", "mounton", "audit_access", "open", "execmod", \9 "quotaon", "mounton", "audit_access", "open", "execmod", \
10 "watch", "watch_mount", "watch_sb", "watch_with_perm", \10 "watch", "watch_mount", "watch_sb", "watch_with_perm", \
11 "watch_reads"11 "watch_reads", "watch_mountns"
12 12
13#define COMMON_SOCK_PERMS \13#define COMMON_SOCK_PERMS \
14 COMMON_FILE_SOCK_PERMS, "bind", "connect", "listen", "accept", \14 COMMON_FILE_SOCK_PERMS, "bind", "connect", "listen", "accept", \
tools/testing/selftests/Makefile+1−0
@@ -35,6 +35,7 @@ TARGETS += filesystems/epoll · 34 unmodified lines
35TARGETS += filesystems/fat35TARGETS += filesystems/fat
36TARGETS += filesystems/overlayfs36TARGETS += filesystems/overlayfs
37TARGETS += filesystems/statmount37TARGETS += filesystems/statmount
38TARGETS += filesystems/mount-notify
38TARGETS += firmware39TARGETS += firmware
39TARGETS += fpu40TARGETS += fpu
40TARGETS += ftrace41TARGETS += ftrace
tools/testing/selftests/filesystems/mount-notify/.gitignore+2−0
@@ -0,0 +1,2 @@
1# SPDX-License-Identifier: GPL-2.0-only
2/*_test
tools/testing/selftests/filesystems/mount-notify/Makefile+6−0
@@ -0,0 +1,6 @@
1# SPDX-License-Identifier: GPL-2.0-or-later
2
3CFLAGS += -Wall -O2 -g $(KHDR_INCLUDES)
4TEST_GEN_PROGS := mount-notify_test
5
6include ../../lib.mk
tools/testing/selftests/filesystems/mount-notify/mount-notify_test.c+516−0
@@ -0,0 +1,516 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2// Copyright (c) 2025 Miklos Szeredi <miklos@szeredi.hu>
3
4#define _GNU_SOURCE
5#include <fcntl.h>
6#include <sched.h>
7#include <stdio.h>
8#include <string.h>
9#include <sys/stat.h>
10#include <sys/mount.h>
11#include <linux/fanotify.h>
12#include <unistd.h>
13#include <sys/fanotify.h>
14#include <sys/syscall.h>
15
16#include "../../kselftest_harness.h"
17#include "../statmount/statmount.h"
18
19#ifndef FAN_MNT_ATTACH
20struct fanotify_event_info_mnt {
21 struct fanotify_event_info_header hdr;
22 __u64 mnt_id;
23};
24#define FAN_MNT_ATTACH 0x01000000 /* Mount was attached */
25#endif
26
27#ifndef FAN_MNT_DETACH
28#define FAN_MNT_DETACH 0x02000000 /* Mount was detached */
29#endif
30
31#ifndef FAN_REPORT_MNT
32#define FAN_REPORT_MNT 0x00004000 /* Report mount events */
33#endif
34
35#ifndef FAN_MARK_MNTNS
36#define FAN_MARK_MNTNS 0x00000110
37#endif
38
39static uint64_t get_mnt_id(struct __test_metadata *const _metadata,
40 const char *path)
41{
42 struct statx sx;
43
44 ASSERT_EQ(statx(AT_FDCWD, path, 0, STATX_MNT_ID_UNIQUE, &sx), 0);
45 ASSERT_TRUE(!!(sx.stx_mask & STATX_MNT_ID_UNIQUE));
46 return sx.stx_mnt_id;
47}
48
49static const char root_mntpoint_templ[] = "/tmp/mount-notify_test_root.XXXXXX";
50
51FIXTURE(fanotify) {
52 int fan_fd;
53 char buf[256];
54 unsigned int rem;
55 void *next;
56 char root_mntpoint[sizeof(root_mntpoint_templ)];
57 int orig_root;
58 int ns_fd;
59 uint64_t root_id;
60};
61
62FIXTURE_SETUP(fanotify)
63{
64 int ret;
65
66 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
67
68 self->ns_fd = open("/proc/self/ns/mnt", O_RDONLY);
69 ASSERT_GE(self->ns_fd, 0);
70
71 ASSERT_EQ(mount("", "/", NULL, MS_REC|MS_PRIVATE, NULL), 0);
72
73 strcpy(self->root_mntpoint, root_mntpoint_templ);
74 ASSERT_NE(mkdtemp(self->root_mntpoint), NULL);
75
76 self->orig_root = open("/", O_PATH | O_CLOEXEC);
77 ASSERT_GE(self->orig_root, 0);
78
79 ASSERT_EQ(mount("tmpfs", self->root_mntpoint, "tmpfs", 0, NULL), 0);
80
81 ASSERT_EQ(chroot(self->root_mntpoint), 0);
82
83 ASSERT_EQ(chdir("/"), 0);
84
85 ASSERT_EQ(mkdir("a", 0700), 0);
86
87 ASSERT_EQ(mkdir("b", 0700), 0);
88
89 self->root_id = get_mnt_id(_metadata, "/");
90 ASSERT_NE(self->root_id, 0);
91
92 self->fan_fd = fanotify_init(FAN_REPORT_MNT, 0);
93 ASSERT_GE(self->fan_fd, 0);
94
95 ret = fanotify_mark(self->fan_fd, FAN_MARK_ADD | FAN_MARK_MNTNS,
96 FAN_MNT_ATTACH | FAN_MNT_DETACH, self->ns_fd, NULL);
97 ASSERT_EQ(ret, 0);
98
99 self->rem = 0;
100}
101
102FIXTURE_TEARDOWN(fanotify)
103{
104 ASSERT_EQ(self->rem, 0);
105 close(self->fan_fd);
106
107 ASSERT_EQ(fchdir(self->orig_root), 0);
108
109 ASSERT_EQ(chroot("."), 0);
110
111 EXPECT_EQ(umount2(self->root_mntpoint, MNT_DETACH), 0);
112 EXPECT_EQ(chdir(self->root_mntpoint), 0);
113 EXPECT_EQ(chdir("/"), 0);
114 EXPECT_EQ(rmdir(self->root_mntpoint), 0);
115}
116
117static uint64_t expect_notify(struct __test_metadata *const _metadata,
118 FIXTURE_DATA(fanotify) *self,
119 uint64_t *mask)
120{
121 struct fanotify_event_metadata *meta;
122 struct fanotify_event_info_mnt *mnt;
123 unsigned int thislen;
124
125 if (!self->rem) {
126 ssize_t len = read(self->fan_fd, self->buf, sizeof(self->buf));
127 ASSERT_GT(len, 0);
128
129 self->rem = len;
130 self->next = (void *) self->buf;
131 }
132
133 meta = self->next;
134 ASSERT_TRUE(FAN_EVENT_OK(meta, self->rem));
135
136 thislen = meta->event_len;
137 self->rem -= thislen;
138 self->next += thislen;
139
140 *mask = meta->mask;
141 thislen -= sizeof(*meta);
142
143 mnt = ((void *) meta) + meta->event_len - thislen;
144
145 ASSERT_EQ(thislen, sizeof(*mnt));
146
147 return mnt->mnt_id;
148}
149
150static void expect_notify_n(struct __test_metadata *const _metadata,
151 FIXTURE_DATA(fanotify) *self,
152 unsigned int n, uint64_t mask[], uint64_t mnts[])
153{
154 unsigned int i;
155
156 for (i = 0; i < n; i++)
157 mnts[i] = expect_notify(_metadata, self, &mask[i]);
158}
159
160static uint64_t expect_notify_mask(struct __test_metadata *const _metadata,
161 FIXTURE_DATA(fanotify) *self,
162 uint64_t expect_mask)
163{
164 uint64_t mntid, mask;
165
166 mntid = expect_notify(_metadata, self, &mask);
167 ASSERT_EQ(expect_mask, mask);
168
169 return mntid;
170}
171
172
173static void expect_notify_mask_n(struct __test_metadata *const _metadata,
174 FIXTURE_DATA(fanotify) *self,
175 uint64_t mask, unsigned int n, uint64_t mnts[])
176{
177 unsigned int i;
178
179 for (i = 0; i < n; i++)
180 mnts[i] = expect_notify_mask(_metadata, self, mask);
181}
182
183static void verify_mount_ids(struct __test_metadata *const _metadata,
184 const uint64_t list1[], const uint64_t list2[],
185 size_t num)
186{
187 unsigned int i, j;
188
189 // Check that neither list has any duplicates
190 for (i = 0; i < num; i++) {
191 for (j = 0; j < num; j++) {
192 if (i != j) {
193 ASSERT_NE(list1[i], list1[j]);
194 ASSERT_NE(list2[i], list2[j]);
195 }
196 }
197 }
198 // Check that all list1 memebers can be found in list2. Together with
199 // the above it means that the list1 and list2 represent the same sets.
200 for (i = 0; i < num; i++) {
201 for (j = 0; j < num; j++) {
202 if (list1[i] == list2[j])
203 break;
204 }
205 ASSERT_NE(j, num);
206 }
207}
208
209static void check_mounted(struct __test_metadata *const _metadata,
210 const uint64_t mnts[], size_t num)
211{
212 ssize_t ret;
213 uint64_t *list;
214
215 list = malloc((num + 1) * sizeof(list[0]));
216 ASSERT_NE(list, NULL);
217
218 ret = listmount(LSMT_ROOT, 0, 0, list, num + 1, 0);
219 ASSERT_EQ(ret, num);
220
221 verify_mount_ids(_metadata, mnts, list, num);
222
223 free(list);
224}
225
226static void setup_mount_tree(struct __test_metadata *const _metadata,
227 int log2_num)
228{
229 int ret, i;
230
231 ret = mount("", "/", NULL, MS_SHARED, NULL);
232 ASSERT_EQ(ret, 0);
233
234 for (i = 0; i < log2_num; i++) {
235 ret = mount("/", "/", NULL, MS_BIND, NULL);
236 ASSERT_EQ(ret, 0);
237 }
238}
239
240TEST_F(fanotify, bind)
241{
242 int ret;
243 uint64_t mnts[2] = { self->root_id };
244
245 ret = mount("/", "/", NULL, MS_BIND, NULL);
246 ASSERT_EQ(ret, 0);
247
248 mnts[1] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
249 ASSERT_NE(mnts[0], mnts[1]);
250
251 check_mounted(_metadata, mnts, 2);
252
253 // Cleanup
254 uint64_t detach_id;
255 ret = umount("/");
256 ASSERT_EQ(ret, 0);
257
258 detach_id = expect_notify_mask(_metadata, self, FAN_MNT_DETACH);
259 ASSERT_EQ(detach_id, mnts[1]);
260
261 check_mounted(_metadata, mnts, 1);
262}
263
264TEST_F(fanotify, move)
265{
266 int ret;
267 uint64_t mnts[2] = { self->root_id };
268 uint64_t move_id;
269
270 ret = mount("/", "/a", NULL, MS_BIND, NULL);
271 ASSERT_EQ(ret, 0);
272
273 mnts[1] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
274 ASSERT_NE(mnts[0], mnts[1]);
275
276 check_mounted(_metadata, mnts, 2);
277
278 ret = move_mount(AT_FDCWD, "/a", AT_FDCWD, "/b", 0);
279 ASSERT_EQ(ret, 0);
280
281 move_id = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH | FAN_MNT_DETACH);
282 ASSERT_EQ(move_id, mnts[1]);
283
284 // Cleanup
285 ret = umount("/b");
286 ASSERT_EQ(ret, 0);
287
288 check_mounted(_metadata, mnts, 1);
289}
290
291TEST_F(fanotify, propagate)
292{
293 const unsigned int log2_num = 4;
294 const unsigned int num = (1 << log2_num);
295 uint64_t mnts[num];
296
297 setup_mount_tree(_metadata, log2_num);
298
299 expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH, num - 1, mnts + 1);
300
301 mnts[0] = self->root_id;
302 check_mounted(_metadata, mnts, num);
303
304 // Cleanup
305 int ret;
306 uint64_t mnts2[num];
307 ret = umount2("/", MNT_DETACH);
308 ASSERT_EQ(ret, 0);
309
310 ret = mount("", "/", NULL, MS_PRIVATE, NULL);
311 ASSERT_EQ(ret, 0);
312
313 mnts2[0] = self->root_id;
314 expect_notify_mask_n(_metadata, self, FAN_MNT_DETACH, num - 1, mnts2 + 1);
315 verify_mount_ids(_metadata, mnts, mnts2, num);
316
317 check_mounted(_metadata, mnts, 1);
318}
319
320TEST_F(fanotify, fsmount)
321{
322 int ret, fs, mnt;
323 uint64_t mnts[2] = { self->root_id };
324
325 fs = fsopen("tmpfs", 0);
326 ASSERT_GE(fs, 0);
327
328 ret = fsconfig(fs, FSCONFIG_CMD_CREATE, 0, 0, 0);
329 ASSERT_EQ(ret, 0);
330
331 mnt = fsmount(fs, 0, 0);
332 ASSERT_GE(mnt, 0);
333
334 close(fs);
335
336 ret = move_mount(mnt, "", AT_FDCWD, "/a", MOVE_MOUNT_F_EMPTY_PATH);
337 ASSERT_EQ(ret, 0);
338
339 close(mnt);
340
341 mnts[1] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
342 ASSERT_NE(mnts[0], mnts[1]);
343
344 check_mounted(_metadata, mnts, 2);
345
346 // Cleanup
347 uint64_t detach_id;
348 ret = umount("/a");
349 ASSERT_EQ(ret, 0);
350
351 detach_id = expect_notify_mask(_metadata, self, FAN_MNT_DETACH);
352 ASSERT_EQ(detach_id, mnts[1]);
353
354 check_mounted(_metadata, mnts, 1);
355}
356
357TEST_F(fanotify, reparent)
358{
359 uint64_t mnts[6] = { self->root_id };
360 uint64_t dmnts[3];
361 uint64_t masks[3];
362 unsigned int i;
363 int ret;
364
365 // Create setup with a[1] -> b[2] propagation
366 ret = mount("/", "/a", NULL, MS_BIND, NULL);
367 ASSERT_EQ(ret, 0);
368
369 ret = mount("", "/a", NULL, MS_SHARED, NULL);
370 ASSERT_EQ(ret, 0);
371
372 ret = mount("/a", "/b", NULL, MS_BIND, NULL);
373 ASSERT_EQ(ret, 0);
374
375 ret = mount("", "/b", NULL, MS_SLAVE, NULL);
376 ASSERT_EQ(ret, 0);
377
378 expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH, 2, mnts + 1);
379
380 check_mounted(_metadata, mnts, 3);
381
382 // Mount on a[3], which is propagated to b[4]
383 ret = mount("/", "/a", NULL, MS_BIND, NULL);
384 ASSERT_EQ(ret, 0);
385
386 expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH, 2, mnts + 3);
387
388 check_mounted(_metadata, mnts, 5);
389
390 // Mount on b[5], not propagated
391 ret = mount("/", "/b", NULL, MS_BIND, NULL);
392 ASSERT_EQ(ret, 0);
393
394 mnts[5] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
395
396 check_mounted(_metadata, mnts, 6);
397
398 // Umount a[3], which is propagated to b[4], but not b[5]
399 // This will result in b[5] "falling" on b[2]
400 ret = umount("/a");
401 ASSERT_EQ(ret, 0);
402
403 expect_notify_n(_metadata, self, 3, masks, dmnts);
404 verify_mount_ids(_metadata, mnts + 3, dmnts, 3);
405
406 for (i = 0; i < 3; i++) {
407 if (dmnts[i] == mnts[5]) {
408 ASSERT_EQ(masks[i], FAN_MNT_ATTACH | FAN_MNT_DETACH);
409 } else {
410 ASSERT_EQ(masks[i], FAN_MNT_DETACH);
411 }
412 }
413
414 mnts[3] = mnts[5];
415 check_mounted(_metadata, mnts, 4);
416
417 // Cleanup
418 ret = umount("/b");
419 ASSERT_EQ(ret, 0);
420
421 ret = umount("/a");
422 ASSERT_EQ(ret, 0);
423
424 ret = umount("/b");
425 ASSERT_EQ(ret, 0);
426
427 expect_notify_mask_n(_metadata, self, FAN_MNT_DETACH, 3, dmnts);
428 verify_mount_ids(_metadata, mnts + 1, dmnts, 3);
429
430 check_mounted(_metadata, mnts, 1);
431}
432
433TEST_F(fanotify, rmdir)
434{
435 uint64_t mnts[3] = { self->root_id };
436 int ret;
437
438 ret = mount("/", "/a", NULL, MS_BIND, NULL);
439 ASSERT_EQ(ret, 0);
440
441 ret = mount("/", "/a/b", NULL, MS_BIND, NULL);
442 ASSERT_EQ(ret, 0);
443
444 expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH, 2, mnts + 1);
445
446 check_mounted(_metadata, mnts, 3);
447
448 ret = chdir("/a");
449 ASSERT_EQ(ret, 0);
450
451 ret = fork();
452 ASSERT_GE(ret, 0);
453
454 if (ret == 0) {
455 chdir("/");
456 unshare(CLONE_NEWNS);
457 mount("", "/", NULL, MS_REC|MS_PRIVATE, NULL);
458 umount2("/a", MNT_DETACH);
459 // This triggers a detach in the other namespace
460 rmdir("/a");
461 exit(0);
462 }
463 wait(NULL);
464
465 expect_notify_mask_n(_metadata, self, FAN_MNT_DETACH, 2, mnts + 1);
466 check_mounted(_metadata, mnts, 1);
467
468 // Cleanup
469 ret = chdir("/");
470 ASSERT_EQ(ret, 0);
471}
472
473TEST_F(fanotify, pivot_root)
474{
475 uint64_t mnts[3] = { self->root_id };
476 uint64_t mnts2[3];
477 int ret;
478
479 ret = mount("tmpfs", "/a", "tmpfs", 0, NULL);
480 ASSERT_EQ(ret, 0);
481
482 mnts[2] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
483
484 ret = mkdir("/a/new", 0700);
485 ASSERT_EQ(ret, 0);
486
487 ret = mkdir("/a/old", 0700);
488 ASSERT_EQ(ret, 0);
489
490 ret = mount("/a", "/a/new", NULL, MS_BIND, NULL);
491 ASSERT_EQ(ret, 0);
492
493 mnts[1] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
494 check_mounted(_metadata, mnts, 3);
495
496 ret = syscall(SYS_pivot_root, "/a/new", "/a/new/old");
497 ASSERT_EQ(ret, 0);
498
499 expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH | FAN_MNT_DETACH, 2, mnts2);
500 verify_mount_ids(_metadata, mnts, mnts2, 2);
501 check_mounted(_metadata, mnts, 3);
502
503 // Cleanup
504 ret = syscall(SYS_pivot_root, "/old", "/old/a/new");
505 ASSERT_EQ(ret, 0);
506
507 ret = umount("/a/new");
508 ASSERT_EQ(ret, 0);
509
510 ret = umount("/a");
511 ASSERT_EQ(ret, 0);
512
513 check_mounted(_metadata, mnts, 1);
514}
515
516TEST_HARNESS_MAIN
tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c+195−0
@@ -20,12 +20,16 @@ FIXTURE(set_layers_via_fds) { · 19 unmodified lines
20FIXTURE_SETUP(set_layers_via_fds)20FIXTURE_SETUP(set_layers_via_fds)
21{21{
22 ASSERT_EQ(mkdir("/set_layers_via_fds", 0755), 0);22 ASSERT_EQ(mkdir("/set_layers_via_fds", 0755), 0);
23 ASSERT_EQ(mkdir("/set_layers_via_fds_tmpfs", 0755), 0);
23}24}
24 25
25FIXTURE_TEARDOWN(set_layers_via_fds)26FIXTURE_TEARDOWN(set_layers_via_fds)
26{27{
27 umount2("/set_layers_via_fds", 0);28 umount2("/set_layers_via_fds", 0);
28 ASSERT_EQ(rmdir("/set_layers_via_fds"), 0);29 ASSERT_EQ(rmdir("/set_layers_via_fds"), 0);
30
31 umount2("/set_layers_via_fds_tmpfs", 0);
32 ASSERT_EQ(rmdir("/set_layers_via_fds_tmpfs"), 0);
29}33}
30 34
31TEST_F(set_layers_via_fds, set_layers_via_fds)35TEST_F(set_layers_via_fds, set_layers_via_fds)
@@ -214,4 +218,195 @@ TEST_F(set_layers_via_fds, set_500_layers_via_fds) · 182 unmodified lines
214 ASSERT_EQ(close(fd_overlay), 0);218 ASSERT_EQ(close(fd_overlay), 0);
215}219}
216 220
221TEST_F(set_layers_via_fds, set_500_layers_via_opath_fds)
222{
223 int fd_context, fd_tmpfs, fd_overlay, fd_work, fd_upper, fd_lower;
224 int layer_fds[500] = { [0 ... 499] = -EBADF };
225
226 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
227 ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0);
228
229 fd_context = sys_fsopen("tmpfs", 0);
230 ASSERT_GE(fd_context, 0);
231
232 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
233 fd_tmpfs = sys_fsmount(fd_context, 0, 0);
234 ASSERT_GE(fd_tmpfs, 0);
235 ASSERT_EQ(close(fd_context), 0);
236
237 for (int i = 0; i < ARRAY_SIZE(layer_fds); i++) {
238 char path[100];
239
240 sprintf(path, "l%d", i);
241 ASSERT_EQ(mkdirat(fd_tmpfs, path, 0755), 0);
242 layer_fds[i] = openat(fd_tmpfs, path, O_DIRECTORY | O_PATH);
243 ASSERT_GE(layer_fds[i], 0);
244 }
245
246 ASSERT_EQ(mkdirat(fd_tmpfs, "w", 0755), 0);
247 fd_work = openat(fd_tmpfs, "w", O_DIRECTORY | O_PATH);
248 ASSERT_GE(fd_work, 0);
249
250 ASSERT_EQ(mkdirat(fd_tmpfs, "u", 0755), 0);
251 fd_upper = openat(fd_tmpfs, "u", O_DIRECTORY | O_PATH);
252 ASSERT_GE(fd_upper, 0);
253
254 ASSERT_EQ(mkdirat(fd_tmpfs, "l501", 0755), 0);
255 fd_lower = openat(fd_tmpfs, "l501", O_DIRECTORY | O_PATH);
256 ASSERT_GE(fd_lower, 0);
257
258 ASSERT_EQ(sys_move_mount(fd_tmpfs, "", -EBADF, "/tmp", MOVE_MOUNT_F_EMPTY_PATH), 0);
259 ASSERT_EQ(close(fd_tmpfs), 0);
260
261 fd_context = sys_fsopen("overlay", 0);
262 ASSERT_GE(fd_context, 0);
263
264 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "workdir", NULL, fd_work), 0);
265 ASSERT_EQ(close(fd_work), 0);
266
267 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "upperdir", NULL, fd_upper), 0);
268 ASSERT_EQ(close(fd_upper), 0);
269
270 for (int i = 0; i < ARRAY_SIZE(layer_fds); i++) {
271 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[i]), 0);
272 ASSERT_EQ(close(layer_fds[i]), 0);
273 }
274
275 ASSERT_NE(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower), 0);
276 ASSERT_EQ(close(fd_lower), 0);
277
278 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
279
280 fd_overlay = sys_fsmount(fd_context, 0, 0);
281 ASSERT_GE(fd_overlay, 0);
282 ASSERT_EQ(close(fd_context), 0);
283 ASSERT_EQ(close(fd_overlay), 0);
284}
285
286TEST_F(set_layers_via_fds, set_layers_via_detached_mount_fds)
287{
288 int fd_context, fd_tmpfs, fd_overlay, fd_tmp;
289 int layer_fds[] = { [0 ... 8] = -EBADF };
290 bool layers_found[] = { [0 ... 8] = false };
291 size_t len = 0;
292 char *line = NULL;
293 FILE *f_mountinfo;
294
295 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
296 ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0);
297
298 fd_context = sys_fsopen("tmpfs", 0);
299 ASSERT_GE(fd_context, 0);
300
301 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
302 fd_tmpfs = sys_fsmount(fd_context, 0, 0);
303 ASSERT_GE(fd_tmpfs, 0);
304 ASSERT_EQ(close(fd_context), 0);
305
306 ASSERT_EQ(mkdirat(fd_tmpfs, "u", 0755), 0);
307 ASSERT_EQ(mkdirat(fd_tmpfs, "u/upper", 0755), 0);
308 ASSERT_EQ(mkdirat(fd_tmpfs, "u/work", 0755), 0);
309 ASSERT_EQ(mkdirat(fd_tmpfs, "l1", 0755), 0);
310 ASSERT_EQ(mkdirat(fd_tmpfs, "l2", 0755), 0);
311 ASSERT_EQ(mkdirat(fd_tmpfs, "l3", 0755), 0);
312 ASSERT_EQ(mkdirat(fd_tmpfs, "l4", 0755), 0);
313 ASSERT_EQ(mkdirat(fd_tmpfs, "d1", 0755), 0);
314 ASSERT_EQ(mkdirat(fd_tmpfs, "d2", 0755), 0);
315 ASSERT_EQ(mkdirat(fd_tmpfs, "d3", 0755), 0);
316
317 ASSERT_EQ(sys_move_mount(fd_tmpfs, "", -EBADF, "/set_layers_via_fds_tmpfs", MOVE_MOUNT_F_EMPTY_PATH), 0);
318
319 fd_tmp = open_tree(fd_tmpfs, "u", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
320 ASSERT_GE(fd_tmp, 0);
321
322 layer_fds[0] = openat(fd_tmp, "upper", O_CLOEXEC | O_DIRECTORY | O_PATH);
323 ASSERT_GE(layer_fds[0], 0);
324
325 layer_fds[1] = openat(fd_tmp, "work", O_CLOEXEC | O_DIRECTORY | O_PATH);
326 ASSERT_GE(layer_fds[1], 0);
327
328 layer_fds[2] = open_tree(fd_tmpfs, "l1", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
329 ASSERT_GE(layer_fds[2], 0);
330
331 layer_fds[3] = open_tree(fd_tmpfs, "l2", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
332 ASSERT_GE(layer_fds[3], 0);
333
334 layer_fds[4] = open_tree(fd_tmpfs, "l3", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
335 ASSERT_GE(layer_fds[4], 0);
336
337 layer_fds[5] = open_tree(fd_tmpfs, "l4", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
338 ASSERT_GE(layer_fds[5], 0);
339
340 layer_fds[6] = open_tree(fd_tmpfs, "d1", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
341 ASSERT_GE(layer_fds[6], 0);
342
343 layer_fds[7] = open_tree(fd_tmpfs, "d2", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
344 ASSERT_GE(layer_fds[7], 0);
345
346 layer_fds[8] = open_tree(fd_tmpfs, "d3", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
347 ASSERT_GE(layer_fds[8], 0);
348
349 ASSERT_EQ(close(fd_tmpfs), 0);
350
351 fd_context = sys_fsopen("overlay", 0);
352 ASSERT_GE(fd_context, 0);
353
354 ASSERT_NE(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir", NULL, layer_fds[2]), 0);
355
356 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "upperdir", NULL, layer_fds[0]), 0);
357 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "workdir", NULL, layer_fds[1]), 0);
358 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[2]), 0);
359 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[3]), 0);
360 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[4]), 0);
361 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[5]), 0);
362 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "datadir+", NULL, layer_fds[6]), 0);
363 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "datadir+", NULL, layer_fds[7]), 0);
364 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "datadir+", NULL, layer_fds[8]), 0);
365
366 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_STRING, "metacopy", "on", 0), 0);
367
368 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
369
370 fd_overlay = sys_fsmount(fd_context, 0, 0);
371 ASSERT_GE(fd_overlay, 0);
372
373 ASSERT_EQ(sys_move_mount(fd_overlay, "", -EBADF, "/set_layers_via_fds", MOVE_MOUNT_F_EMPTY_PATH), 0);
374
375 f_mountinfo = fopen("/proc/self/mountinfo", "r");
376 ASSERT_NE(f_mountinfo, NULL);
377
378 while (getline(&line, &len, f_mountinfo) != -1) {
379 char *haystack = line;
380
381 if (strstr(haystack, "workdir=/tmp/w"))
382 layers_found[0] = true;
383 if (strstr(haystack, "upperdir=/tmp/u"))
384 layers_found[1] = true;
385 if (strstr(haystack, "lowerdir+=/tmp/l1"))
386 layers_found[2] = true;
387 if (strstr(haystack, "lowerdir+=/tmp/l2"))
388 layers_found[3] = true;
389 if (strstr(haystack, "lowerdir+=/tmp/l3"))
390 layers_found[4] = true;
391 if (strstr(haystack, "lowerdir+=/tmp/l4"))
392 layers_found[5] = true;
393 if (strstr(haystack, "datadir+=/tmp/d1"))
394 layers_found[6] = true;
395 if (strstr(haystack, "datadir+=/tmp/d2"))
396 layers_found[7] = true;
397 if (strstr(haystack, "datadir+=/tmp/d3"))
398 layers_found[8] = true;
399 }
400 free(line);
401
402 for (int i = 0; i < ARRAY_SIZE(layer_fds); i++) {
403 ASSERT_EQ(layers_found[i], true);
404 ASSERT_EQ(close(layer_fds[i]), 0);
405 }
406
407 ASSERT_EQ(close(fd_context), 0);
408 ASSERT_EQ(close(fd_overlay), 0);
409 ASSERT_EQ(fclose(f_mountinfo), 0);
410}
411
217TEST_HARNESS_MAIN412TEST_HARNESS_MAIN
tools/testing/selftests/filesystems/overlayfs/wrappers.h+17−0
@@ -44,4 +44,21 @@ static inline int sys_move_mount(int from_dfd, const char *from_pathname, · 43 unmodified lines
44 to_pathname, flags);44 to_pathname, flags);
45}45}
46 46
47#ifndef OPEN_TREE_CLONE
48#define OPEN_TREE_CLONE 1
49#endif
50
51#ifndef OPEN_TREE_CLOEXEC
52#define OPEN_TREE_CLOEXEC O_CLOEXEC
53#endif
54
55#ifndef AT_RECURSIVE
56#define AT_RECURSIVE 0x8000
57#endif
58
59static inline int sys_open_tree(int dfd, const char *filename, unsigned int flags)
60{
61 return syscall(__NR_open_tree, dfd, filename, flags);
62}
63
47#endif64#endif
tools/testing/selftests/filesystems/statmount/statmount.h+1−1
@@ -25,7 +25,7 @@ static inline int statmount(uint64_t mnt_id, uint64_t mnt_ns_id, uint64_t mask, · 24 unmodified lines
25 return syscall(__NR_statmount, &req, buf, bufsize, flags);25 return syscall(__NR_statmount, &req, buf, bufsize, flags);
26}26}
27 27
28static ssize_t listmount(uint64_t mnt_id, uint64_t mnt_ns_id,28static inline ssize_t listmount(uint64_t mnt_id, uint64_t mnt_ns_id,
29 uint64_t last_mnt_id, uint64_t list[], size_t num,29 uint64_t last_mnt_id, uint64_t list[], size_t num,
30 unsigned int flags)30 unsigned int flags)
31{31{