[PATCH 3/3] erofs-utils: lib: fix LIBARCHIVE.xattr URL-encoded keys
Gao Xiang
hsiangkao at linux.alibaba.com
Thu Dec 26 15:58:08 AEDT 2024
As tar(5) [1] mentioned: `The key value is URL-encoded: All non-ASCII
characters and the two special characters "=" and "%" are encoded as
"%" followed by two uppercase hexadecimal digits.`
Fix it now.
[1] https://man.freebsd.org/cgi/man.cgi?tar(5)
Fixes: c0063a73b01b ("erofs-utils: lib: support importing xattrs from tarerofs")
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
lib/tar.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 52 insertions(+), 7 deletions(-)
diff --git a/lib/tar.c b/lib/tar.c
index 9642e2e..2ea3858 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -438,6 +438,47 @@ static int base64_decode(const char *src, int len, u8 *dst)
return cp - dst;
}
+static int tohex(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
+}
+
+static unsigned int url_decode(char *str, unsigned int len)
+{
+ const char *s = str;
+ char *d = str;
+ int d1, d2;
+
+ for (; len && *s != '\0' && *s != '%'; ++d, ++s, --len);
+ if (!len || *s == '\0')
+ return d - str;
+
+ while (len && *s != '\0') {
+ if (*s == '%' && len > 2) {
+ /* Try to convert % escape */
+ d1 = tohex(s[1]), d2 = tohex(s[2]);
+
+ /* Look good, consume three chars */
+ if (d1 >= 0 && d2 >= 0) {
+ s += 3;
+ len -= 3;
+ *d++ = (d1 << 4) | d2;
+ continue;
+ }
+ /* Otherwise, treat '%' as normal char */
+ }
+ *d++ = *s++;
+ --len;
+ }
+ return d - str;
+}
+
int tarerofs_parse_pax_header(struct erofs_iostream *ios,
struct erofs_pax_header *eh, u32 size)
{
@@ -454,7 +495,7 @@ int tarerofs_parse_pax_header(struct erofs_iostream *ios,
goto out;
while (p < buf + size) {
- char *kv, *value;
+ char *kv, *key, *value;
int len, n;
/* extended records are of the format: "LEN NAME=VALUE\n" */
ret = sscanf(p, "%d %n", &len, &n);
@@ -537,8 +578,7 @@ int tarerofs_parse_pax_header(struct erofs_iostream *ios,
eh->use_gid = true;
} else if (!strncmp(kv, "SCHILY.xattr.",
sizeof("SCHILY.xattr.") - 1)) {
- char *key = kv + sizeof("SCHILY.xattr.") - 1;
-
+ key = kv + sizeof("SCHILY.xattr.") - 1;
--len; /* p[-1] == '\0' */
ret = tarerofs_insert_xattr(&eh->xattrs, key,
value - key - 1,
@@ -547,9 +587,10 @@ int tarerofs_parse_pax_header(struct erofs_iostream *ios,
goto out;
} else if (!strncmp(kv, "LIBARCHIVE.xattr.",
sizeof("LIBARCHIVE.xattr.") - 1)) {
- char *key;
- key = kv + sizeof("LIBARCHIVE.xattr.") - 1;
+ int namelen;
+ 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);
@@ -558,9 +599,13 @@ int tarerofs_parse_pax_header(struct erofs_iostream *ios,
goto out;
}
+ if (namelen != value - key - 1) {
+ key[namelen] = '=';
+ memmove(key + namelen + 1, value, ret);
+ value = key + namelen + 1;
+ }
ret = tarerofs_insert_xattr(&eh->xattrs, key,
- value - key - 1,
- value - key + ret, false);
+ namelen, namelen + 1 + ret, false);
if (ret)
goto out;
} else {
--
2.39.3 (Apple Git-146)
More information about the Linux-erofs
mailing list