From 5830fb6b54f7167cc7c9d43612eb01c24312c7ca Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 13 Oct 2020 17:59:54 +0300 Subject: ovl: introduce new "uuid=off" option for inodes index feature This replaces uuid with null in overlayfs file handles and thus relaxes uuid checks for overlay index feature. It is only possible in case there is only one filesystem for all the work/upper/lower directories and bare file handles from this backing filesystem are unique. In other case when we have multiple filesystems lets just fallback to "uuid=on" which is and equivalent of how it worked before with all uuid checks. This is needed when overlayfs is/was mounted in a container with index enabled (e.g.: to be able to resolve inotify watch file handles on it to paths in CRIU), and this container is copied and started alongside with the original one. This way the "copy" container can't have the same uuid on the superblock and mounting the overlayfs from it later would fail. That is an example of the problem on top of loop+ext4: dd if=/dev/zero of=loopbackfile.img bs=100M count=10 losetup -fP loopbackfile.img losetup -a #/dev/loop0: [64768]:35 (/loop-test/loopbackfile.img) mkfs.ext4 loopbackfile.img mkdir loop-mp mount -o loop /dev/loop0 loop-mp mkdir loop-mp/{lower,upper,work,merged} mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\ upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged umount loop-mp/merged umount loop-mp e2fsck -f /dev/loop0 tune2fs -U random /dev/loop0 mount -o loop /dev/loop0 loop-mp mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\ upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged #mount: /loop-test/loop-mp/merged: #mount(2) system call failed: Stale file handle. If you just change the uuid of the backing filesystem, overlay is not mounting any more. In Virtuozzo we copy container disks (ploops) when create the copy of container and we require fs uuid to be unique for a new container. Signed-off-by: Pavel Tikhomirov Reviewed-by: Amir Goldstein Signed-off-by: Miklos Szeredi --- Documentation/filesystems/overlayfs.rst | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index 580ab9a0fe31..a3e588dc8437 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -563,6 +563,11 @@ This verification may cause significant overhead in some cases. Note: the mount options index=off,nfs_export=on are conflicting for a read-write mount and will result in an error. +Note: the mount option uuid=off can be used to replace UUID of the underlying +filesystem in file handles with null, and effectively disable UUID checks. This +can be useful in case the underlying disk is copied and the UUID of this copy +is changed. This is only applicable if all lower/upper/work directories are on +the same filesystem, otherwise it will fallback to normal behaviour. Volatile mount -------------- -- cgit v1.2.3 From 58afaf5d605f091abf7491774e34fa29d4a1994c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 12 Nov 2020 11:31:55 +0100 Subject: ovl: doc clarification Documentation says "The lower filesystem can be any filesystem supported by Linux". However, this is not the case, as Linux supports vfat and vfat doesn't work as a lower filesystem Reported-by: nerdopolis Signed-off-by: Miklos Szeredi --- Documentation/filesystems/overlayfs.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index a3e588dc8437..1ef4ef38b542 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -97,11 +97,13 @@ directory trees to be in the same filesystem and there is no requirement that the root of a filesystem be given for either upper or lower. -The lower filesystem can be any filesystem supported by Linux and does -not need to be writable. The lower filesystem can even be another -overlayfs. The upper filesystem will normally be writable and if it -is it must support the creation of trusted.* extended attributes, and -must provide valid d_type in readdir responses, so NFS is not suitable. +A wide range of filesystems supported by Linux can be the lower filesystem, +but not all filesystems that are mountable by Linux have the features +needed for OverlayFS to work. The lower filesystem does not need to be +writable. The lower filesystem can even be another overlayfs. The upper +filesystem will normally be writable and if it is it must support the +creation of trusted.* extended attributes, and must provide valid d_type in +readdir responses, so NFS is not suitable. A read-only overlay of two read-only filesystems may use any filesystem type. -- cgit v1.2.3 From 13c6ad0f45fd0382e77829a6c738f3e18739c15b Mon Sep 17 00:00:00 2001 From: Kevin Locke Date: Sat, 22 Aug 2020 20:22:57 -0600 Subject: ovl: document lower modification caveats Some overlayfs optional features are incompatible with offline changes to the lower tree and may result in -EXDEV, -EIO, or other errors. Such modification is not supported and the error behavior is intentionally not specified. Update the "Changes to underlying filesystems" section to note this restriction. Move the paragraph describing the offline behavior below the online behavior so it is adjacent to the following 3 paragraphs describing the NFS export offline modification behavior. Link: https://lore.kernel.org/linux-unionfs/20200708142353.GA103536@redhat.com/ Link: https://lore.kernel.org/linux-unionfs/CAOQ4uxi23Zsmfb4rCed1n=On0NNA5KZD74jjjeyz+et32sk-gg@mail.gmail.com/ Link: https://lore.kernel.org/linux-unionfs/20200817135651.GA637139@redhat.com/ Link: https://lore.kernel.org/linux-unionfs/20200709153616.GE150543@redhat.com/ Link: https://lore.kernel.org/linux-unionfs/20200812135529.GA122370@kevinolos/ Signed-off-by: Kevin Locke Signed-off-by: Miklos Szeredi --- Documentation/filesystems/overlayfs.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index 1ef4ef38b542..b86be7c6a952 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -469,14 +469,18 @@ summarized in the `Inode properties`_ table above. Changes to underlying filesystems --------------------------------- -Offline changes, when the overlay is not mounted, are allowed to either -the upper or the lower trees. - Changes to the underlying filesystems while part of a mounted overlay filesystem are not allowed. If the underlying filesystem is changed, the behavior of the overlay is undefined, though it will not result in a crash or deadlock. +Offline changes, when the overlay is not mounted, are allowed to the +upper tree. Offline changes to the lower tree are only allowed if the +"metadata only copy up", "inode index", and "redirect_dir" features +have not been used. If the lower tree is modified and any of these +features has been used, the behavior of the overlay is undefined, +though it will not result in a crash or deadlock. + When the overlay NFS export feature is enabled, overlay filesystems behavior on offline changes of the underlying lower layer is different than the behavior when NFS export is disabled. -- cgit v1.2.3 From 2d2f2d7322ff43e0fe92bf8cccdc0b09449bf2e1 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 14 Dec 2020 15:26:14 +0100 Subject: ovl: user xattr Optionally allow using "user.overlay." namespace instead of "trusted.overlay." This is necessary for overlayfs to be able to be mounted in an unprivileged namepsace. Make the option explicit, since it makes the filesystem format be incompatible. Disable redirect_dir and metacopy options, because these would allow privilege escalation through direct manipulation of the "user.overlay.redirect" or "user.overlay.metacopy" xattrs. Signed-off-by: Miklos Szeredi Reviewed-by: Amir Goldstein --- Documentation/filesystems/overlayfs.rst | 13 +++++-- fs/overlayfs/inode.c | 12 +++++-- fs/overlayfs/overlayfs.h | 8 +++-- fs/overlayfs/ovl_entry.h | 1 + fs/overlayfs/super.c | 61 ++++++++++++++++++++++++++++----- fs/overlayfs/util.c | 5 +-- 6 files changed, 82 insertions(+), 18 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index b86be7c6a952..587a93973929 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -102,8 +102,8 @@ but not all filesystems that are mountable by Linux have the features needed for OverlayFS to work. The lower filesystem does not need to be writable. The lower filesystem can even be another overlayfs. The upper filesystem will normally be writable and if it is it must support the -creation of trusted.* extended attributes, and must provide valid d_type in -readdir responses, so NFS is not suitable. +creation of trusted.* and/or user.* extended attributes, and must provide +valid d_type in readdir responses, so NFS is not suitable. A read-only overlay of two read-only filesystems may use any filesystem type. @@ -594,6 +594,15 @@ fresh one. In very limited cases where the user knows that the system has not crashed and contents of upperdir are intact, The "volatile" directory can be removed. + +User xattr +---------- + +The the "-o userxattr" mount option forces overlayfs to use the +"user.overlay." xattr namespace instead of "trusted.overlay.". This is +useful for unprivileged mounting of overlayfs. + + Testsuite --------- diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 1688ae7e3438..d739e14c6814 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -329,8 +329,14 @@ static const char *ovl_get_link(struct dentry *dentry, bool ovl_is_private_xattr(struct super_block *sb, const char *name) { - return strncmp(name, OVL_XATTR_PREFIX, - sizeof(OVL_XATTR_PREFIX) - 1) == 0; + struct ovl_fs *ofs = sb->s_fs_info; + + if (ofs->config.userxattr) + return strncmp(name, OVL_XATTR_USER_PREFIX, + sizeof(OVL_XATTR_USER_PREFIX) - 1) == 0; + else + return strncmp(name, OVL_XATTR_TRUSTED_PREFIX, + sizeof(OVL_XATTR_TRUSTED_PREFIX) - 1) == 0; } int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name, @@ -690,7 +696,7 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev) * For the first, copy up case, the union nlink does not change, whether the * operation succeeds or fails, but the upper inode nlink may change. * Therefore, before copy up, we store the union nlink value relative to the - * lower inode nlink in the index inode xattr trusted.overlay.nlink. + * lower inode nlink in the index inode xattr .overlay.nlink. * * For the second, upper hardlink case, the union nlink should be incremented * or decremented IFF the operation succeeds, aligned with nlink change of the diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 79a971fe8b13..b487e48c7fd4 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -22,7 +22,9 @@ enum ovl_path_type { #define OVL_TYPE_MERGE(type) ((type) & __OVL_PATH_MERGE) #define OVL_TYPE_ORIGIN(type) ((type) & __OVL_PATH_ORIGIN) -#define OVL_XATTR_PREFIX XATTR_TRUSTED_PREFIX "overlay." +#define OVL_XATTR_NAMESPACE "overlay." +#define OVL_XATTR_TRUSTED_PREFIX XATTR_TRUSTED_PREFIX OVL_XATTR_NAMESPACE +#define OVL_XATTR_USER_PREFIX XATTR_USER_PREFIX OVL_XATTR_NAMESPACE enum ovl_xattr { OVL_XATTR_OPAQUE, @@ -113,10 +115,10 @@ struct ovl_fh { #define OVL_FH_FID_OFFSET (OVL_FH_WIRE_OFFSET + \ offsetof(struct ovl_fb, fid)) -extern const char *ovl_xattr_table[]; +extern const char *const ovl_xattr_table[][2]; static inline const char *ovl_xattr(struct ovl_fs *ofs, enum ovl_xattr ox) { - return ovl_xattr_table[ox]; + return ovl_xattr_table[ox][ofs->config.userxattr]; } static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index b7a73ea147b8..fbd5e27ce66b 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -18,6 +18,7 @@ struct ovl_config { bool nfs_export; int xino; bool metacopy; + bool userxattr; bool ovl_volatile; }; diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 8cd6a45322fe..6366adf81fa3 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -418,6 +418,7 @@ enum { OPT_UUID_ON, OPT_UUID_OFF, OPT_NFS_EXPORT_ON, + OPT_USERXATTR, OPT_NFS_EXPORT_OFF, OPT_XINO_ON, OPT_XINO_OFF, @@ -436,6 +437,7 @@ static const match_table_t ovl_tokens = { {OPT_REDIRECT_DIR, "redirect_dir=%s"}, {OPT_INDEX_ON, "index=on"}, {OPT_INDEX_OFF, "index=off"}, + {OPT_USERXATTR, "userxattr"}, {OPT_UUID_ON, "uuid=on"}, {OPT_UUID_OFF, "uuid=off"}, {OPT_NFS_EXPORT_ON, "nfs_export=on"}, @@ -602,6 +604,10 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) config->ovl_volatile = true; break; + case OPT_USERXATTR: + config->userxattr = true; + break; + default: pr_err("unrecognized mount option \"%s\" or missing value\n", p); @@ -705,6 +711,28 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) } } + + /* Resolve userxattr -> !redirect && !metacopy dependency */ + if (config->userxattr) { + if (config->redirect_follow && redirect_opt) { + pr_err("conflicting options: userxattr,redirect_dir=%s\n", + config->redirect_mode); + return -EINVAL; + } + if (config->metacopy && metacopy_opt) { + pr_err("conflicting options: userxattr,metacopy=on\n"); + return -EINVAL; + } + /* + * Silently disable default setting of redirect and metacopy. + * This shall be the default in the future as well: these + * options must be explicitly enabled if used together with + * userxattr. + */ + config->redirect_dir = config->redirect_follow = false; + config->metacopy = false; + } + return 0; } @@ -1054,8 +1082,14 @@ ovl_posix_acl_default_xattr_handler = { .set = ovl_posix_acl_xattr_set, }; -static const struct xattr_handler ovl_own_xattr_handler = { - .prefix = OVL_XATTR_PREFIX, +static const struct xattr_handler ovl_own_trusted_xattr_handler = { + .prefix = OVL_XATTR_TRUSTED_PREFIX, + .get = ovl_own_xattr_get, + .set = ovl_own_xattr_set, +}; + +static const struct xattr_handler ovl_own_user_xattr_handler = { + .prefix = OVL_XATTR_USER_PREFIX, .get = ovl_own_xattr_get, .set = ovl_own_xattr_set, }; @@ -1066,12 +1100,22 @@ static const struct xattr_handler ovl_other_xattr_handler = { .set = ovl_other_xattr_set, }; -static const struct xattr_handler *ovl_xattr_handlers[] = { +static const struct xattr_handler *ovl_trusted_xattr_handlers[] = { +#ifdef CONFIG_FS_POSIX_ACL + &ovl_posix_acl_access_xattr_handler, + &ovl_posix_acl_default_xattr_handler, +#endif + &ovl_own_trusted_xattr_handler, + &ovl_other_xattr_handler, + NULL +}; + +static const struct xattr_handler *ovl_user_xattr_handlers[] = { #ifdef CONFIG_FS_POSIX_ACL &ovl_posix_acl_access_xattr_handler, &ovl_posix_acl_default_xattr_handler, #endif - &ovl_own_xattr_handler, + &ovl_own_user_xattr_handler, &ovl_other_xattr_handler, NULL }; @@ -1334,7 +1378,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, pr_warn("upper fs does not support RENAME_WHITEOUT.\n"); /* - * Check if upper/work fs supports trusted.overlay.* xattr + * Check if upper/work fs supports (trusted|user).overlay.* xattr */ err = ovl_do_setxattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE, "0", 1); if (err) { @@ -1473,10 +1517,10 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, /* * Verify upper root is exclusively associated with index dir. - * Older kernels stored upper fh in "trusted.overlay.origin" + * Older kernels stored upper fh in ".overlay.origin" * xattr. If that xattr exists, verify that it is a match to * upper dir file handle. In any case, verify or set xattr - * "trusted.overlay.upper" to indicate that index may have + * ".overlay.upper" to indicate that index may have * directory entries. */ if (ovl_check_origin_xattr(ofs, ofs->indexdir)) { @@ -2014,7 +2058,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) cap_lower(cred->cap_effective, CAP_SYS_RESOURCE); sb->s_magic = OVERLAYFS_SUPER_MAGIC; - sb->s_xattr = ovl_xattr_handlers; + sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers : + ovl_trusted_xattr_handlers; sb->s_fs_info = ofs; sb->s_flags |= SB_POSIXACL; sb->s_iflags |= SB_I_SKIP_SYNC; diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index ced63c79e9dd..e63e0587535f 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -585,9 +585,10 @@ bool ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry, #define OVL_XATTR_METACOPY_POSTFIX "metacopy" #define OVL_XATTR_TAB_ENTRY(x) \ - [x] = OVL_XATTR_PREFIX x ## _POSTFIX + [x] = { [false] = OVL_XATTR_TRUSTED_PREFIX x ## _POSTFIX, \ + [true] = OVL_XATTR_USER_PREFIX x ## _POSTFIX } -const char *ovl_xattr_table[] = { +const char *const ovl_xattr_table[][2] = { OVL_XATTR_TAB_ENTRY(OVL_XATTR_OPAQUE), OVL_XATTR_TAB_ENTRY(OVL_XATTR_REDIRECT), OVL_XATTR_TAB_ENTRY(OVL_XATTR_ORIGIN), -- cgit v1.2.3