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 <hudson...@tencent.com>
Signed-off-by: Gao Xiang <hsiang...@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


Reply via email to