From: Thomas Weißschuh linux@weissschuh.net
[ Upstream commit d5094bcb5bfdfea2cf0de8aaf77cc65db56cbdb5 ]
Nolibc assumes that the kernel ABI is using a time values that are as large as a long integer. For most ABIs this holds true. But for x32 this is not correct, as it uses 32bit longs but 64bit times.
Also the 'struct stat' implementation of nolibc relies on timespec::tv_sec and time_t being the same type. While timespec::tv_sec comes from the kernel and is of type __kernel_old_time_t, time_t is defined within nolibc.
Switch to the __kernel_old_time_t to always get the correct type.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net Link: https://lore.kernel.org/r/20250712-nolibc-x32-v1-1-6d81cb798710@weissschuh.n... Acked-by: Willy Tarreau w@1wt.eu Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
Based on my analysis of this commit, here is my assessment:
**Backport Status: YES**
This commit should be backported to stable kernel trees for the following reasons:
1. **Bug Fix**: This fixes a real ABI compatibility bug where nolibc incorrectly assumes `time_t` is always the same size as `long`. On x32 architecture (x86-64 with 32-bit pointers), `long` is 32-bit but kernel time values are 64-bit, causing type mismatches.
2. **Clear Impact**: The commit message clearly explains the issue - the `struct stat` implementation in nolibc relies on `timespec::tv_sec` and `time_t` being the same type. Looking at the code: - In `/include/uapi/linux/time.h:12`, `struct timespec` uses `__kernel_old_time_t tv_sec` - In the original nolibc code at `tools/include/nolibc/std.h:30`, `time_t` was defined as `signed long` - In `tools/include/nolibc/types.h:183-185`, the stat structure uses unions that expect `time_t` and `struct timespec` members to be compatible
3. **Small and Contained Fix**: The change is minimal - just changing one typedef from `signed long` to `__kernel_old_time_t` and adding the necessary include. This is exactly the kind of focused fix suitable for stable.
4. **No Feature Changes**: This doesn't add new functionality or change the API - it just corrects the type definition to match what the kernel actually uses.
5. **Low Risk**: The change uses the kernel's own type definition (`__kernel_old_time_t`) which is already defined as `__kernel_long_t` in the generic case, so for most architectures this is a no-op. It only changes behavior on architectures like x32 where it's actually needed.
6. **Prevents Runtime Failures**: Without this fix, nolibc programs on x32 would have incorrect stat structures where time fields don't align properly with kernel expectations, potentially causing data corruption or incorrect time values.
The commit follows stable kernel rules by fixing an important bug with minimal changes and low regression risk. It's a clear correctness fix for a specific architecture compatibility issue.
tools/include/nolibc/std.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/include/nolibc/std.h b/tools/include/nolibc/std.h index 933bc0be7e1c..a9d8b5b51f37 100644 --- a/tools/include/nolibc/std.h +++ b/tools/include/nolibc/std.h @@ -20,6 +20,8 @@
#include "stdint.h"
+#include <linux/types.h> + /* those are commonly provided by sys/types.h */ typedef unsigned int dev_t; typedef unsigned long ino_t; @@ -31,6 +33,6 @@ typedef unsigned long nlink_t; typedef signed long off_t; typedef signed long blksize_t; typedef signed long blkcnt_t; -typedef signed long time_t; +typedef __kernel_old_time_t time_t;
#endif /* _NOLIBC_STD_H */