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