[PATCH] erofs-utils: lib: fix base64 for tarerofs

Gao Xiang hsiangkao at linux.alibaba.com
Wed Sep 10 11:45:07 AEST 2025


The old kernel fscrypt variant (fs/crypto/fname.c) was not real
RFC 4648 base64, see kernel commit ba47b515f594 ("fscrypt: align
Base64 encoding with RFC 4648 base64url").

Fixes: c0063a73b01b ("erofs-utils: lib: support importing xattrs from tarerofs")
Reported-by: Chengyu Zhu <hudsonzhu at tencent.com>
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 lib/Makefile.am       |  3 +-
 lib/base64.c          | 69 +++++++++++++++++++++++++++++++++++++++++++
 lib/liberofs_base64.h |  9 ++++++
 lib/tar.c             | 45 ++--------------------------
 4 files changed, 83 insertions(+), 43 deletions(-)
 create mode 100644 lib/base64.c
 create mode 100644 lib/liberofs_base64.h

diff --git a/lib/Makefile.am b/lib/Makefile.am
index 87454e3..daf937c 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -27,6 +27,7 @@ noinst_HEADERS = $(top_srcdir)/include/erofs_fs.h \
       $(top_srcdir)/include/erofs/fragments.h \
       $(top_srcdir)/include/erofs/rebuild.h \
       $(top_srcdir)/include/erofs/importer.h \
+      $(top_srcdir)/lib/liberofs_base64.h \
       $(top_srcdir)/lib/liberofs_cache.h \
       $(top_srcdir)/lib/liberofs_private.h \
       $(top_srcdir)/lib/liberofs_xxhash.h \
@@ -40,7 +41,7 @@ liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c exclude.c \
 		      compress_hints.c hashmap.c sha256.c blobchunk.c dir.c \
 		      fragments.c dedupe.c uuid_unparse.c uuid.c tar.c \
 		      block_list.c rebuild.c diskbuf.c bitops.c dedupe_ext.c \
-		      vmdk.c metabox.c global.c importer.c
+		      vmdk.c metabox.c global.c importer.c base64.c
 
 liberofs_la_CFLAGS = -Wall ${libuuid_CFLAGS} -I$(top_srcdir)/include
 liberofs_la_LDFLAGS =
diff --git a/lib/base64.c b/lib/base64.c
new file mode 100644
index 0000000..c5f4ad8
--- /dev/null
+++ b/lib/base64.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
+#include "liberofs_base64.h"
+#include <string.h>
+
+static const char lookup_table[65] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int erofs_base64_encode(const u8 *src, int srclen, char *dst)
+{
+        u32 ac = 0;
+        int bits = 0;
+        int i;
+        char *cp = dst;
+
+        for (i = 0; i < srclen; i++) {
+                ac = (ac << 8) | src[i];
+                bits += 8;
+                do {
+                        bits -= 6;
+                        *cp++ = lookup_table[(ac >> bits) & 0x3f];
+                } while (bits >= 6);
+        }
+        if (bits) {
+                *cp++ = lookup_table[(ac << (6 - bits)) & 0x3f];
+                bits -= 6;
+        }
+        while (bits < 0) {
+                *cp++ = '=';
+                bits += 2;
+        }
+        return cp - dst;
+}
+
+int erofs_base64_decode(const char *src, int len, u8 *dst)
+{
+	int i, bits = 0, ac = 0;
+	const char *p;
+	u8 *cp = dst;
+	bool padding = false;
+
+	if(len && !(len % 4)) {
+		/* Check for and ignore any end padding */
+		if (src[len - 2] == '=' && src[len - 1] == '=')
+			len -= 2;
+		else if (src[len - 1] == '=')
+			--len;
+		padding = true;
+	}
+
+	for (i = 0; i < len; i++) {
+		p = strchr(lookup_table, src[i]);
+		if (!p || !src[i])
+			return -2;
+		ac = (ac << 6 | (p - lookup_table));
+		bits += 6;
+		if (bits >= 8) {
+			bits -= 8;
+			*cp++ = ac >> bits;
+		}
+	}
+	ac &= BIT(bits) - 1;
+	if (ac) {
+		if (padding || ac > 0xff)
+			return -1;
+		else
+			*cp++ = ac;
+	}
+	return cp - dst;
+}
diff --git a/lib/liberofs_base64.h b/lib/liberofs_base64.h
new file mode 100644
index 0000000..bcadb5f
--- /dev/null
+++ b/lib/liberofs_base64.h
@@ -0,0 +1,9 @@
+#ifndef __EROFS_LIB_LIBEROFS_BASE64_H
+#define __EROFS_LIB_LIBEROFS_BASE64_H
+
+#include "erofs/defs.h"
+
+int erofs_base64_encode(const u8 *src, int srclen, char *dst);
+int erofs_base64_decode(const char *src, int len, u8 *dst);
+
+#endif
diff --git a/lib/tar.c b/lib/tar.c
index c8fd48e..9dd1253 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -15,6 +15,7 @@
 #if defined(HAVE_ZLIB)
 #include <zlib.h>
 #endif
+#include "liberofs_base64.h"
 #include "liberofs_cache.h"
 
 /* This file is a tape/volume header.  Ignore it on extraction.  */
@@ -400,46 +401,6 @@ int tarerofs_apply_xattrs(struct erofs_inode *inode, struct list_head *xattrs)
 	return 0;
 }
 
-static const char lookup_table[65] =
-	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-static int base64_decode(const char *src, int len, u8 *dst)
-{
-	int i, bits = 0, ac = 0;
-	const char *p;
-	u8 *cp = dst;
-	bool padding = false;
-
-	if(len && !(len % 4)) {
-		/* Check for and ignore any end padding */
-		if (src[len - 2] == '=' && src[len - 1] == '=')
-			len -= 2;
-		else if (src[len - 1] == '=')
-			--len;
-		padding = true;
-	}
-
-	for (i = 0; i < len; i++) {
-		p = strchr(lookup_table, src[i]);
-		if (!p || !src[i])
-			return -2;
-		ac += (p - lookup_table) << bits;
-		bits += 6;
-		if (bits >= 8) {
-			*cp++ = ac & 0xff;
-			ac >>= 8;
-			bits -= 8;
-		}
-	}
-	if (ac) {
-		if (padding || ac > 0xff)
-			return -1;
-		else
-			*cp++ = ac & 0xff;
-	}
-	return cp - dst;
-}
-
 static int tohex(int c)
 {
 	if (c >= '0' && c <= '9')
@@ -594,8 +555,8 @@ int tarerofs_parse_pax_header(struct erofs_iostream *ios,
 				key = kv + sizeof("LIBARCHIVE.xattr.") - 1;
 				namelen = url_decode(key, value - key - 1);
 				--len; /* p[-1] == '\0' */
-				ret = base64_decode(value, len - (value - kv),
-						    (u8 *)value);
+				ret = erofs_base64_decode(value, len - (value - kv),
+							  (u8 *)value);
 				if (ret < 0) {
 					ret = -EFSCORRUPTED;
 					goto out;
-- 
2.43.5



More information about the Linux-erofs mailing list