[PATCH v6 10/11] erofs-utils: lib: set origin xattr on parent directory of whiteout

Jingbo Xu jefflexu at linux.alibaba.com
Tue Sep 5 20:02:26 AEST 2023


Whiteouts will be exposed in the overlayfs mount if the whiteouts are
from non-merged directory without origin xattr set on the directory.

To fix this, set origin xattr (with empty value) on parent directory of
whiteouts, marking the parent directory as copied-up to avoid exposing
whiteouts in the overlayfs mount.

To avoid setting multiple origin xattrs on the same directory when
there are multiple whiteouts under the directory, enhance
erofs_setxattr() so that it could skip duplicate xattrs.

Signed-off-by: Jingbo Xu <jefflexu at linux.alibaba.com>
---
 include/erofs/xattr.h |  3 ++-
 lib/rebuild.c         |  6 ++++++
 lib/tar.c             |  9 ++++++++-
 lib/xattr.c           | 27 ++++++++++++++++++++++++---
 4 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index 9fa1ad1..62d0b8b 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -55,8 +55,9 @@ void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi);
 int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi);
 
 int erofs_setxattr(struct erofs_inode *inode, char *key,
-		   const void *value, size_t size);
+		   const void *value, size_t size, bool nodup);
 int erofs_set_opaque_xattr(struct erofs_inode *inode);
+int erofs_set_origin_xattr(struct erofs_inode *inode);
 int erofs_read_xattrs_from_disk(struct erofs_inode *inode);
 
 #ifdef __cplusplus
diff --git a/lib/rebuild.c b/lib/rebuild.c
index 477d68d..b254dea 100644
--- a/lib/rebuild.c
+++ b/lib/rebuild.c
@@ -200,6 +200,12 @@ static int erofs_rebuild_fill_inode(struct erofs_inode *inode)
 
 	switch (inode->i_mode & S_IFMT) {
 	case S_IFCHR:
+		if (erofs_inode_is_whiteout(inode)) {
+			ret = erofs_set_origin_xattr(inode->i_parent);
+			if (ret)
+				break;
+		}
+		/* fallthrough */
 	case S_IFBLK:
 	case S_IFIFO:
 	case S_IFSOCK:
diff --git a/lib/tar.c b/lib/tar.c
index 8cb392c..b75b723 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -206,7 +206,7 @@ int tarerofs_apply_xattrs(struct erofs_inode *inode, struct list_head *xattrs)
 		item->kv[item->namelen] = '\0';
 		erofs_dbg("Recording xattr(%s)=\"%s\" (of %u bytes) to file %s",
 			  item->kv, v, vsz, inode->i_srcpath);
-		ret = erofs_setxattr(inode, item->kv, v, vsz);
+		ret = erofs_setxattr(inode, item->kv, v, vsz, false);
 		if (ret == -ENODATA)
 			erofs_err("Failed to set xattr(%s)=%s to file %s",
 				  item->kv, v, inode->i_srcpath);
@@ -740,6 +740,13 @@ new_inode:
 		inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFCHR;
 		inode->u.i_rdev = EROFS_WHITEOUT_DEV;
 		d->type = EROFS_FT_CHRDEV;
+		/*
+		 * Mark parent directory as copied-up to avoid exposing
+		 * whiteouts in the overlayfs mount.
+		 */
+		ret = erofs_set_origin_xattr(inode->i_parent);
+		if (ret)
+			goto out;
 	} else {
 		inode->i_mode = st.st_mode;
 		if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
diff --git a/lib/xattr.c b/lib/xattr.c
index cc6a393..feafe96 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -57,12 +57,18 @@
 #ifndef OVL_XATTR_OPAQUE_POSTFIX
 #define OVL_XATTR_OPAQUE_POSTFIX "opaque"
 #endif
+#ifndef OVL_XATTR_ORIGIN_POSTFIX
+#define OVL_XATTR_ORIGIN_POSTFIX "origin"
+#endif
 #ifndef OVL_XATTR_TRUSTED_PREFIX
 #define OVL_XATTR_TRUSTED_PREFIX XATTR_TRUSTED_PREFIX OVL_XATTR_NAMESPACE
 #endif
 #ifndef OVL_XATTR_OPAQUE
 #define OVL_XATTR_OPAQUE OVL_XATTR_TRUSTED_PREFIX OVL_XATTR_OPAQUE_POSTFIX
 #endif
+#ifndef OVL_XATTR_ORIGIN
+#define OVL_XATTR_ORIGIN OVL_XATTR_TRUSTED_PREFIX OVL_XATTR_ORIGIN_POSTFIX
+#endif
 
 #define EA_HASHTABLE_BITS 16
 
@@ -455,11 +461,12 @@ err:
 }
 
 int erofs_setxattr(struct erofs_inode *inode, char *key,
-		   const void *value, size_t size)
+		   const void *value, size_t size, bool nodup)
 {
 	char *kvbuf;
 	unsigned int len[2];
 	struct xattr_item *item;
+	struct inode_xattr_node *node;
 	u8 prefix;
 	u16 prefixlen;
 
@@ -481,12 +488,26 @@ int erofs_setxattr(struct erofs_inode *inode, char *key,
 	if (IS_ERR(item))
 		return PTR_ERR(item);
 
+	if (nodup) {
+		list_for_each_entry(node, &inode->i_xattrs, list) {
+			if (node->item == item) {
+				put_xattritem(item);
+				return 0;
+			}
+		}
+	}
+
 	return erofs_xattr_add(&inode->i_xattrs, item);
 }
 
 int erofs_set_opaque_xattr(struct erofs_inode *inode)
 {
-	return erofs_setxattr(inode, OVL_XATTR_OPAQUE, "y", 1);
+	return erofs_setxattr(inode, OVL_XATTR_OPAQUE, "y", 1, false);
+}
+
+int erofs_set_origin_xattr(struct erofs_inode *inode)
+{
+	return erofs_setxattr(inode, OVL_XATTR_ORIGIN, NULL, 0, true);
 }
 
 #ifdef WITH_ANDROID
@@ -599,7 +620,7 @@ int erofs_read_xattrs_from_disk(struct erofs_inode *inode)
 			DBG_BUGON(ret != size);
 		}
 
-		ret = erofs_setxattr(inode, key, value, size);
+		ret = erofs_setxattr(inode, key, value, size, false);
 		free(value);
 		if (ret)
 			break;
-- 
2.19.1.6.gb485710b



More information about the Linux-erofs mailing list