Re: [PATCH] erofs-utils: lib: tar: fix fractional PAX mtime parsing
Gao Xiang <[email protected]>
| Newsgroups | org.ozlabs.lists.linux-erofs |
|---|---|
| Message-ID | <[email protected]> |
Hi Vansh,
On 2026/3/30 01:36, Vansh Choudhary wrote:
> The fractional part of PAX mtime values was parsed as a plain integer,
> so "123.5" ended up with 5ns instead of 500000000ns.
>
> Scale the fractional part according to its decimal width before storing
> it as nanoseconds. Also normalize negative fractional timestamps and
> reject malformed mtime values with missing digits or trailing junk.
>
> Fixes: 95d315fd7958 ("erofs-utils: introduce tarerofs")
> Signed-off-by: Vansh Choudhary <[email protected]>
I try to apply as below, does it look good to you?
Also as before, could you write a regression test for this?
Your patches are also scattered, could you collect them
all and resend them as a patchset if I'm still missing any?
Thanks,
Gao Xiang
From 4cd618eaeebb7a5acf5e82074fb1c9d619995f72 Mon Sep 17 00:00:00 2001
From: Vansh Choudhary <[email protected]>
Date: Sun, 29 Mar 2026 17:36:39 +0000
Subject: [PATCH] erofs-utils: lib: tar: fix fractional PAX mtime parsing
The fractional part of PAX mtime values was parsed as a plain integer,
so "123.5" ended up with 5ns instead of 500000000ns.
Scale the fractional part according to its decimal width before storing
it as nanoseconds. Also normalize negative fractional timestamps and
reject malformed mtime values with missing digits or trailing junk.
Fixes: 95d315fd7958 ("erofs-utils: introduce tarerofs")
Signed-off-by: Vansh Choudhary <[email protected]>
---
include/erofs/defs.h | 9 +++++++++
lib/tar.c | 29 ++++++++++++++++++++++++++---
2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/include/erofs/defs.h b/include/erofs/defs.h
index 5724c2794ab0..9f3d0f9c35bc 100644
--- a/include/erofs/defs.h
+++ b/include/erofs/defs.h
@@ -387,6 +387,15 @@ unsigned long __roundup_pow_of_two(unsigned long n)
#define __erofs_stringify_1(x...) #x
#define __erofs_stringify(x...) __erofs_stringify_1(x)
+#define check_sub_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ __builtin_sub_overflow(__a, __b, __d); \
+})
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/tar.c b/lib/tar.c
index 16e9c22fbdc8..3755c1f5450d 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -2,6 +2,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include <sys/stat.h>
#include "erofs/print.h"
#include "erofs/diskbuf.h"
@@ -525,6 +526,9 @@ int tarerofs_parse_pax_header(struct erofs_iostream *ios,
eh->link = strdup(value);
} else if (!strncmp(kv, "mtime=",
sizeof("mtime=") - 1)) {
+ unsigned int ns = 0;
+ int digits = 0;
+
ret = sscanf(value, "%lld %n", &lln, &n);
if(ret < 1) {
ret = -EIO;
@@ -532,12 +536,31 @@ int tarerofs_parse_pax_header(struct erofs_iostream *ios,
}
eh->st.st_mtime = lln;
if (value[n] == '.') {
- ret = sscanf(value + n + 1, "%d", &n);
- if (ret < 1) {
+ while (value[n + 1] >= '0' &&
+ value[n + 1] <= '9') {
+ if (digits < 9)
+ ns = ns * 10 + value[n + 1] - '0';
+ ++digits;
+ ++n;
+ }
+ if (!digits || value[n + 1] != '\0') {
ret = -EIO;
goto out;
}
- ST_MTIM_NSEC_SET(&eh->st, n);
+ while (digits++ < 9)
+ ns *= 10;
+ if (ns && value[0] == '-') {
+ if (check_sub_overflow(eh->st.st_mtime, (time_t)1,
+ &eh->st.st_mtime)) {
+ ret = -EIO;
+ goto out;
+ }
+ ns = 1000000000 - ns;
+ }
+ ST_MTIM_NSEC_SET(&eh->st, ns);
+ } else if (value[n] != '\0') {
+ ret = -EIO;
+ goto out;
} else {
ST_MTIM_NSEC_SET(&eh->st, 0);
}
--
2.43.5