summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/include/nolibc/.gitignore1
-rw-r--r--tools/include/nolibc/Makefile4
-rw-r--r--tools/include/nolibc/arch-i386.h7
-rw-r--r--tools/include/nolibc/arch-loongarch.h200
-rw-r--r--tools/include/nolibc/arch-x86_64.h5
-rw-r--r--tools/include/nolibc/arch.h2
-rw-r--r--tools/include/nolibc/nolibc.h1
-rw-r--r--tools/include/nolibc/stackprotector.h53
-rw-r--r--tools/include/nolibc/std.h15
-rw-r--r--tools/include/nolibc/stdint.h99
-rw-r--r--tools/include/nolibc/sys.h100
-rw-r--r--tools/include/nolibc/types.h30
-rw-r--r--tools/include/nolibc/unistd.h5
-rw-r--r--tools/testing/selftests/nolibc/Makefile90
-rw-r--r--tools/testing/selftests/nolibc/nolibc-test.c221
15 files changed, 718 insertions, 115 deletions
diff --git a/tools/include/nolibc/.gitignore b/tools/include/nolibc/.gitignore
new file mode 100644
index 000000000000..dea22eaaed2b
--- /dev/null
+++ b/tools/include/nolibc/.gitignore
@@ -0,0 +1 @@
+sysroot
diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile
index cfd06764b5ae..9839feafd38a 100644
--- a/tools/include/nolibc/Makefile
+++ b/tools/include/nolibc/Makefile
@@ -25,8 +25,8 @@ endif
nolibc_arch := $(patsubst arm64,aarch64,$(ARCH))
arch_file := arch-$(nolibc_arch).h
-all_files := ctype.h errno.h nolibc.h signal.h std.h stdio.h stdlib.h string.h \
- sys.h time.h types.h unistd.h
+all_files := ctype.h errno.h nolibc.h signal.h stackprotector.h std.h stdint.h \
+ stdio.h stdlib.h string.h sys.h time.h types.h unistd.h
# install all headers needed to support a bare-metal compiler
all: headers
diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h
index e8d0cf545bf1..2d98d78fd3f3 100644
--- a/tools/include/nolibc/arch-i386.h
+++ b/tools/include/nolibc/arch-i386.h
@@ -181,6 +181,8 @@ struct sys_stat_struct {
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));
+#define __ARCH_SUPPORTS_STACK_PROTECTOR
+
/* startup code */
/*
* i386 System V ABI mandates:
@@ -188,9 +190,12 @@ const unsigned long *_auxv __attribute__((weak));
* 2) The deepest stack frame should be set to zero
*
*/
-void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
+void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void)
{
__asm__ volatile (
+#ifdef NOLIBC_STACKPROTECTOR
+ "call __stack_chk_init\n" // initialize stack protector
+#endif
"pop %eax\n" // argc (first arg, %eax)
"mov %esp, %ebx\n" // argv[] (second arg, %ebx)
"lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx)
diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h
new file mode 100644
index 000000000000..029ee3cd6baf
--- /dev/null
+++ b/tools/include/nolibc/arch-loongarch.h
@@ -0,0 +1,200 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * LoongArch specific definitions for NOLIBC
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef _NOLIBC_ARCH_LOONGARCH_H
+#define _NOLIBC_ARCH_LOONGARCH_H
+
+/* Syscalls for LoongArch :
+ * - stack is 16-byte aligned
+ * - syscall number is passed in a7
+ * - arguments are in a0, a1, a2, a3, a4, a5
+ * - the system call is performed by calling "syscall 0"
+ * - syscall return comes in a0
+ * - the arguments are cast to long and assigned into the target
+ * registers which are then simply passed as registers to the asm code,
+ * so that we don't have to experience issues with register constraints.
+ *
+ * On LoongArch, select() is not implemented so we have to use pselect6().
+ */
+#define __ARCH_WANT_SYS_PSELECT6
+
+#define my_syscall0(num) \
+({ \
+ register long _num __asm__ ("a7") = (num); \
+ register long _arg1 __asm__ ("a0"); \
+ \
+ __asm__ volatile ( \
+ "syscall 0\n" \
+ : "=r"(_arg1) \
+ : "r"(_num) \
+ : "memory", "$t0", "$t1", "$t2", "$t3", \
+ "$t4", "$t5", "$t6", "$t7", "$t8" \
+ ); \
+ _arg1; \
+})
+
+#define my_syscall1(num, arg1) \
+({ \
+ register long _num __asm__ ("a7") = (num); \
+ register long _arg1 __asm__ ("a0") = (long)(arg1); \
+ \
+ __asm__ volatile ( \
+ "syscall 0\n" \
+ : "+r"(_arg1) \
+ : "r"(_num) \
+ : "memory", "$t0", "$t1", "$t2", "$t3", \
+ "$t4", "$t5", "$t6", "$t7", "$t8" \
+ ); \
+ _arg1; \
+})
+
+#define my_syscall2(num, arg1, arg2) \
+({ \
+ register long _num __asm__ ("a7") = (num); \
+ register long _arg1 __asm__ ("a0") = (long)(arg1); \
+ register long _arg2 __asm__ ("a1") = (long)(arg2); \
+ \
+ __asm__ volatile ( \
+ "syscall 0\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), \
+ "r"(_num) \
+ : "memory", "$t0", "$t1", "$t2", "$t3", \
+ "$t4", "$t5", "$t6", "$t7", "$t8" \
+ ); \
+ _arg1; \
+})
+
+#define my_syscall3(num, arg1, arg2, arg3) \
+({ \
+ register long _num __asm__ ("a7") = (num); \
+ register long _arg1 __asm__ ("a0") = (long)(arg1); \
+ register long _arg2 __asm__ ("a1") = (long)(arg2); \
+ register long _arg3 __asm__ ("a2") = (long)(arg3); \
+ \
+ __asm__ volatile ( \
+ "syscall 0\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), "r"(_arg3), \
+ "r"(_num) \
+ : "memory", "$t0", "$t1", "$t2", "$t3", \
+ "$t4", "$t5", "$t6", "$t7", "$t8" \
+ ); \
+ _arg1; \
+})
+
+#define my_syscall4(num, arg1, arg2, arg3, arg4) \
+({ \
+ register long _num __asm__ ("a7") = (num); \
+ register long _arg1 __asm__ ("a0") = (long)(arg1); \
+ register long _arg2 __asm__ ("a1") = (long)(arg2); \
+ register long _arg3 __asm__ ("a2") = (long)(arg3); \
+ register long _arg4 __asm__ ("a3") = (long)(arg4); \
+ \
+ __asm__ volatile ( \
+ "syscall 0\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \
+ "r"(_num) \
+ : "memory", "$t0", "$t1", "$t2", "$t3", \
+ "$t4", "$t5", "$t6", "$t7", "$t8" \
+ ); \
+ _arg1; \
+})
+
+#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
+({ \
+ register long _num __asm__ ("a7") = (num); \
+ register long _arg1 __asm__ ("a0") = (long)(arg1); \
+ register long _arg2 __asm__ ("a1") = (long)(arg2); \
+ register long _arg3 __asm__ ("a2") = (long)(arg3); \
+ register long _arg4 __asm__ ("a3") = (long)(arg4); \
+ register long _arg5 __asm__ ("a4") = (long)(arg5); \
+ \
+ __asm__ volatile ( \
+ "syscall 0\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
+ "r"(_num) \
+ : "memory", "$t0", "$t1", "$t2", "$t3", \
+ "$t4", "$t5", "$t6", "$t7", "$t8" \
+ ); \
+ _arg1; \
+})
+
+#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
+({ \
+ register long _num __asm__ ("a7") = (num); \
+ register long _arg1 __asm__ ("a0") = (long)(arg1); \
+ register long _arg2 __asm__ ("a1") = (long)(arg2); \
+ register long _arg3 __asm__ ("a2") = (long)(arg3); \
+ register long _arg4 __asm__ ("a3") = (long)(arg4); \
+ register long _arg5 __asm__ ("a4") = (long)(arg5); \
+ register long _arg6 __asm__ ("a5") = (long)(arg6); \
+ \
+ __asm__ volatile ( \
+ "syscall 0\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
+ "r"(_num) \
+ : "memory", "$t0", "$t1", "$t2", "$t3", \
+ "$t4", "$t5", "$t6", "$t7", "$t8" \
+ ); \
+ _arg1; \
+})
+
+char **environ __attribute__((weak));
+const unsigned long *_auxv __attribute__((weak));
+
+#if __loongarch_grlen == 32
+#define LONGLOG "2"
+#define SZREG "4"
+#define REG_L "ld.w"
+#define LONG_S "st.w"
+#define LONG_ADD "add.w"
+#define LONG_ADDI "addi.w"
+#define LONG_SLL "slli.w"
+#define LONG_BSTRINS "bstrins.w"
+#else // __loongarch_grlen == 64
+#define LONGLOG "3"
+#define SZREG "8"
+#define REG_L "ld.d"
+#define LONG_S "st.d"
+#define LONG_ADD "add.d"
+#define LONG_ADDI "addi.d"
+#define LONG_SLL "slli.d"
+#define LONG_BSTRINS "bstrins.d"
+#endif
+
+/* startup code */
+void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
+{
+ __asm__ volatile (
+ REG_L " $a0, $sp, 0\n" // argc (a0) was in the stack
+ LONG_ADDI " $a1, $sp, "SZREG"\n" // argv (a1) = sp + SZREG
+ LONG_SLL " $a2, $a0, "LONGLOG"\n" // envp (a2) = SZREG*argc ...
+ LONG_ADDI " $a2, $a2, "SZREG"\n" // + SZREG (skip null)
+ LONG_ADD " $a2, $a2, $a1\n" // + argv
+
+ "move $a3, $a2\n" // iterate a3 over envp to find auxv (after NULL)
+ "0:\n" // do {
+ REG_L " $a4, $a3, 0\n" // a4 = *a3;
+ LONG_ADDI " $a3, $a3, "SZREG"\n" // a3 += sizeof(void*);
+ "bne $a4, $zero, 0b\n" // } while (a4);
+ "la.pcrel $a4, _auxv\n" // a4 = &_auxv
+ LONG_S " $a3, $a4, 0\n" // store a3 into _auxv
+
+ "la.pcrel $a3, environ\n" // a3 = &environ
+ LONG_S " $a2, $a3, 0\n" // store envp(a2) into environ
+ LONG_BSTRINS " $sp, $zero, 3, 0\n" // sp must be 16-byte aligned
+ "bl main\n" // main() returns the status code, we'll exit with it.
+ "li.w $a7, 93\n" // NR_exit == 93
+ "syscall 0\n"
+ );
+ __builtin_unreachable();
+}
+
+#endif // _NOLIBC_ARCH_LOONGARCH_H
diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h
index 17f6751208e7..f7f2a11d4c3b 100644
--- a/tools/include/nolibc/arch-x86_64.h
+++ b/tools/include/nolibc/arch-x86_64.h
@@ -181,6 +181,8 @@ struct sys_stat_struct {
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));
+#define __ARCH_SUPPORTS_STACK_PROTECTOR
+
/* startup code */
/*
* x86-64 System V ABI mandates:
@@ -191,6 +193,9 @@ const unsigned long *_auxv __attribute__((weak));
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
{
__asm__ volatile (
+#ifdef NOLIBC_STACKPROTECTOR
+ "call __stack_chk_init\n" // initialize stack protector
+#endif
"pop %rdi\n" // argc (first arg, %rdi)
"mov %rsp, %rsi\n" // argv[] (second arg, %rsi)
"lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx)
diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h
index 78b067a4fa47..2d5386a8d6aa 100644
--- a/tools/include/nolibc/arch.h
+++ b/tools/include/nolibc/arch.h
@@ -29,6 +29,8 @@
#include "arch-riscv.h"
#elif defined(__s390x__)
#include "arch-s390.h"
+#elif defined(__loongarch__)
+#include "arch-loongarch.h"
#endif
#endif /* _NOLIBC_ARCH_H */
diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h
index b2bc48d3cfe4..04739a6293c4 100644
--- a/tools/include/nolibc/nolibc.h
+++ b/tools/include/nolibc/nolibc.h
@@ -104,6 +104,7 @@
#include "string.h"
#include "time.h"
#include "unistd.h"
+#include "stackprotector.h"
/* Used by programs to avoid std includes */
#define NOLIBC
diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h
new file mode 100644
index 000000000000..d119cbbbc256
--- /dev/null
+++ b/tools/include/nolibc/stackprotector.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * Stack protector support for NOLIBC
+ * Copyright (C) 2023 Thomas Weißschuh <linux@weissschuh.net>
+ */
+
+#ifndef _NOLIBC_STACKPROTECTOR_H
+#define _NOLIBC_STACKPROTECTOR_H
+
+#include "arch.h"
+
+#if defined(NOLIBC_STACKPROTECTOR)
+
+#if !defined(__ARCH_SUPPORTS_STACK_PROTECTOR)
+#error "nolibc does not support stack protectors on this arch"
+#endif
+
+#include "sys.h"
+#include "stdlib.h"
+
+/* The functions in this header are using raw syscall macros to avoid
+ * triggering stack protector errors themselves
+ */
+
+__attribute__((weak,noreturn,section(".text.nolibc_stack_chk")))
+void __stack_chk_fail(void)
+{
+ pid_t pid;
+ my_syscall3(__NR_write, STDERR_FILENO, "!!Stack smashing detected!!\n", 28);
+ pid = my_syscall0(__NR_getpid);
+ my_syscall2(__NR_kill, pid, SIGABRT);
+ for (;;);
+}
+
+__attribute__((weak,noreturn,section(".text.nolibc_stack_chk")))
+void __stack_chk_fail_local(void)
+{
+ __stack_chk_fail();
+}
+
+__attribute__((weak,section(".data.nolibc_stack_chk")))
+uintptr_t __stack_chk_guard;
+
+__attribute__((weak,no_stack_protector,section(".text.nolibc_stack_chk")))
+void __stack_chk_init(void)
+{
+ my_syscall3(__NR_getrandom, &__stack_chk_guard, sizeof(__stack_chk_guard), 0);
+ /* a bit more randomness in case getrandom() fails */
+ __stack_chk_guard ^= (uintptr_t) &__stack_chk_guard;
+}
+#endif // defined(NOLIBC_STACKPROTECTOR)
+
+#endif // _NOLIBC_STACKPROTECTOR_H
diff --git a/tools/include/nolibc/std.h b/tools/include/nolibc/std.h
index 1747ae125392..933bc0be7e1c 100644
--- a/tools/include/nolibc/std.h
+++ b/tools/include/nolibc/std.h
@@ -18,20 +18,7 @@
#define NULL ((void *)0)
#endif
-/* stdint types */
-typedef unsigned char uint8_t;
-typedef signed char int8_t;
-typedef unsigned short uint16_t;
-typedef signed short int16_t;
-typedef unsigned int uint32_t;
-typedef signed int int32_t;
-typedef unsigned long long uint64_t;
-typedef signed long long int64_t;
-typedef unsigned long size_t;
-typedef signed long ssize_t;
-typedef unsigned long uintptr_t;
-typedef signed long intptr_t;
-typedef signed long ptrdiff_t;
+#include "stdint.h"
/* those are commonly provided by sys/types.h */
typedef unsigned int dev_t;
diff --git a/tools/include/nolibc/stdint.h b/tools/include/nolibc/stdint.h
new file mode 100644
index 000000000000..c1ce4f5e0603
--- /dev/null
+++ b/tools/include/nolibc/stdint.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * Standard definitions and types for NOLIBC
+ * Copyright (C) 2023 Vincent Dagonneau <v@vda.io>
+ */
+
+#ifndef _NOLIBC_STDINT_H
+#define _NOLIBC_STDINT_H
+
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+typedef unsigned long size_t;
+typedef signed long ssize_t;
+typedef unsigned long uintptr_t;
+typedef signed long intptr_t;
+typedef signed long ptrdiff_t;
+
+typedef int8_t int_least8_t;
+typedef uint8_t uint_least8_t;
+typedef int16_t int_least16_t;
+typedef uint16_t uint_least16_t;
+typedef int32_t int_least32_t;
+typedef uint32_t uint_least32_t;
+typedef int64_t int_least64_t;
+typedef uint64_t uint_least64_t;
+
+typedef int8_t int_fast8_t;
+typedef uint8_t uint_fast8_t;
+typedef ssize_t int_fast16_t;
+typedef size_t uint_fast16_t;
+typedef ssize_t int_fast32_t;
+typedef size_t uint_fast32_t;
+typedef ssize_t int_fast64_t;
+typedef size_t uint_fast64_t;
+
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+/* limits of integral types */
+
+#define INT8_MIN (-128)
+#define INT16_MIN (-32767-1)
+#define INT32_MIN (-2147483647-1)
+#define INT64_MIN (-9223372036854775807LL-1)
+
+#define INT8_MAX (127)
+#define INT16_MAX (32767)
+#define INT32_MAX (2147483647)
+#define INT64_MAX (9223372036854775807LL)
+
+#define UINT8_MAX (255)
+#define UINT16_MAX (65535)
+#define UINT32_MAX (4294967295U)
+#define UINT64_MAX (18446744073709551615ULL)
+
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST64_MIN INT64_MIN
+
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MAX INT64_MAX
+
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+#define SIZE_MAX ((size_t)(__LONG_MAX__) * 2 + 1)
+#define INTPTR_MIN (-__LONG_MAX__ - 1)
+#define INTPTR_MAX __LONG_MAX__
+#define PTRDIFF_MIN INTPTR_MIN
+#define PTRDIFF_MAX INTPTR_MAX
+#define UINTPTR_MAX SIZE_MAX
+
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST16_MIN INTPTR_MIN
+#define INT_FAST32_MIN INTPTR_MIN
+#define INT_FAST64_MIN INTPTR_MIN
+
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MAX INTPTR_MAX
+#define INT_FAST32_MAX INTPTR_MAX
+#define INT_FAST64_MAX INTPTR_MAX
+
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX SIZE_MAX
+#define UINT_FAST32_MAX SIZE_MAX
+#define UINT_FAST64_MAX SIZE_MAX
+
+#endif /* _NOLIBC_STDINT_H */
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index b5f8cd35c03b..5d624dc63a42 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -11,7 +11,6 @@
#include "std.h"
/* system includes */
-#include <asm/fcntl.h> // for O_*
#include <asm/unistd.h>
#include <asm/signal.h> // for SIGCHLD
#include <asm/ioctls.h>
@@ -20,6 +19,8 @@
#include <linux/loop.h>
#include <linux/time.h>
#include <linux/auxvec.h>
+#include <linux/fcntl.h> // for O_* and AT_*
+#include <linux/stat.h> // for statx()
#include "arch.h"
#include "errno.h"
@@ -411,6 +412,27 @@ int getdents64(int fd, struct linux_dirent64 *dirp, int count)
/*
+ * uid_t geteuid(void);
+ */
+
+static __attribute__((unused))
+uid_t sys_geteuid(void)
+{
+#ifdef __NR_geteuid32
+ return my_syscall0(__NR_geteuid32);
+#else
+ return my_syscall0(__NR_geteuid);
+#endif
+}
+
+static __attribute__((unused))
+uid_t geteuid(void)
+{
+ return sys_geteuid();
+}
+
+
+/*
* pid_t getpgid(pid_t pid);
*/
@@ -545,6 +567,27 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
/*
+ * uid_t getuid(void);
+ */
+
+static __attribute__((unused))
+uid_t sys_getuid(void)
+{
+#ifdef __NR_getuid32
+ return my_syscall0(__NR_getuid32);
+#else
+ return my_syscall0(__NR_getuid);
+#endif
+}
+
+static __attribute__((unused))
+uid_t getuid(void)
+{
+ return sys_getuid();
+}
+
+
+/*
* int ioctl(int fd, unsigned long req, void *value);
*/
@@ -1048,12 +1091,66 @@ pid_t setsid(void)
return ret;
}
+#if defined(__NR_statx)
+/*
+ * int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf);
+ */
+
+static __attribute__((unused))
+int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
+{
+ return my_syscall5(__NR_statx, fd, path, flags, mask, buf);
+}
+
+static __attribute__((unused))
+int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
+{
+ int ret = sys_statx(fd, path, flags, mask, buf);
+
+ if (ret < 0) {
+ SET_ERRNO(-ret);
+ ret = -1;
+ }
+ return ret;
+}
+#endif
/*
* int stat(const char *path, struct stat *buf);
* Warning: the struct stat's layout is arch-dependent.
*/
+#if defined(__NR_statx) && !defined(__NR_newfstatat) && !defined(__NR_stat)
+/*
+ * Maybe we can just use statx() when available for all architectures?
+ */
+static __attribute__((unused))
+int sys_stat(const char *path, struct stat *buf)
+{
+ struct statx statx;
+ long ret;
+
+ ret = sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx);
+ buf->st_dev = ((statx.stx_dev_minor & 0xff)
+ | (statx.stx_dev_major << 8)
+ | ((statx.stx_dev_minor & ~0xff) << 12));
+ buf->st_ino = statx.stx_ino;
+ buf->st_mode = statx.stx_mode;
+ buf->st_nlink = statx.stx_nlink;
+ buf->st_uid = statx.stx_uid;
+ buf->st_gid = statx.stx_gid;
+ buf->st_rdev = ((statx.stx_rdev_minor & 0xff)
+ | (statx.stx_rdev_major << 8)
+ | ((statx.stx_rdev_minor & ~0xff) << 12));
+ buf->st_size = statx.stx_size;
+ buf->st_blksize = statx.stx_blksize;
+ buf->st_blocks = statx.stx_blocks;
+ buf->st_atime = statx.stx_atime.tv_sec;
+ buf->st_mtime = statx.stx_mtime.tv_sec;
+ buf->st_ctime = statx.stx_ctime.tv_sec;
+ return ret;
+}
+#else
static __attribute__((unused))
int sys_stat(const char *path, struct stat *buf)
{
@@ -1083,6 +1180,7 @@ int sys_stat(const char *path, struct stat *buf)
buf->st_ctime = stat.st_ctime;
return ret;
}
+#endif
static __attribute__((unused))
int stat(const char *path, struct stat *buf)
diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h
index fbbc0e68c001..aedd7d9e3f64 100644
--- a/tools/include/nolibc/types.h
+++ b/tools/include/nolibc/types.h
@@ -9,6 +9,7 @@
#include "std.h"
#include <linux/time.h>
+#include <linux/stat.h>
/* Only the generic macros and types may be defined here. The arch-specific
@@ -16,7 +17,11 @@
* the layout of sys_stat_struct must not be defined here.
*/
-/* stat flags (WARNING, octal here) */
+/* stat flags (WARNING, octal here). We need to check for an existing
+ * definition because linux/stat.h may omit to define those if it finds
+ * that any glibc header was already included.
+ */
+#if !defined(S_IFMT)
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFBLK 0060000
@@ -34,6 +39,22 @@
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+#endif
+
/* dirent types */
#define DT_UNKNOWN 0x0
#define DT_FIFO 0x1
@@ -60,11 +81,6 @@
#define MAXPATHLEN (PATH_MAX)
#endif
-/* Special FD used by all the *at functions */
-#ifndef AT_FDCWD
-#define AT_FDCWD (-100)
-#endif
-
/* whence values for lseek() */
#define SEEK_SET 0
#define SEEK_CUR 1
@@ -81,6 +97,8 @@
/* Macros used on waitpid()'s return status */
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
#define WIFEXITED(status) (((status) & 0x7f) == 0)
+#define WTERMSIG(status) ((status) & 0x7f)
+#define WIFSIGNALED(status) ((status) - 1 < 0xff)
/* waitpid() flags */
#define WNOHANG 1
diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h
index 1cfcd52106a4..ac7d53d986cd 100644
--- a/tools/include/nolibc/unistd.h
+++ b/tools/include/nolibc/unistd.h
@@ -13,6 +13,11 @@
#include "sys.h"
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+
static __attribute__((unused))
int msleep(unsigned int msecs)
{
diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile
index 8fe61d3e3cce..bbce57420465 100644
--- a/tools/testing/selftests/nolibc/Makefile
+++ b/tools/testing/selftests/nolibc/Makefile
@@ -1,6 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for nolibc tests
include ../../../scripts/Makefile.include
+# We need this for the "cc-option" macro.
+include ../../../build/Build.include
# we're in ".../tools/testing/selftests/nolibc"
ifeq ($(srctree),)
@@ -13,52 +15,56 @@ ARCH = $(SUBARCH)
endif
# kernel image names by architecture
-IMAGE_i386 = arch/x86/boot/bzImage
-IMAGE_x86_64 = arch/x86/boot/bzImage
-IMAGE_x86 = arch/x86/boot/bzImage
-IMAGE_arm64 = arch/arm64/boot/Image
-IMAGE_arm = arch/arm/boot/zImage
-IMAGE_mips = vmlinuz
-IMAGE_riscv = arch/riscv/boot/Image
-IMAGE_s390 = arch/s390/boot/bzImage
-IMAGE = $(IMAGE_$(ARCH))
-IMAGE_NAME = $(notdir $(IMAGE))
+IMAGE_i386 = arch/x86/boot/bzImage
+IMAGE_x86_64 = arch/x86/boot/bzImage
+IMAGE_x86 = arch/x86/boot/bzImage
+IMAGE_arm64 = arch/arm64/boot/Image
+IMAGE_arm = arch/arm/boot/zImage
+IMAGE_mips = vmlinuz
+IMAGE_riscv = arch/riscv/boot/Image
+IMAGE_s390 = arch/s390/boot/bzImage
+IMAGE_loongarch = arch/loongarch/boot/vmlinuz.efi
+IMAGE = $(IMAGE_$(ARCH))
+IMAGE_NAME = $(notdir $(IMAGE))
# default kernel configurations that appear to be usable
-DEFCONFIG_i386 = defconfig
-DEFCONFIG_x86_64 = defconfig
-DEFCONFIG_x86 = defconfig
-DEFCONFIG_arm64 = defconfig
-DEFCONFIG_arm = multi_v7_defconfig
-DEFCONFIG_mips = malta_defconfig
-DEFCONFIG_riscv = defconfig
-DEFCONFIG_s390 = defconfig
-DEFCONFIG = $(DEFCONFIG_$(ARCH))
+DEFCONFIG_i386 = defconfig
+DEFCONFIG_x86_64 = defconfig
+DEFCONFIG_x86 = defconfig
+DEFCONFIG_arm64 = defconfig
+DEFCONFIG_arm = multi_v7_defconfig
+DEFCONFIG_mips = malta_defconfig
+DEFCONFIG_riscv = defconfig
+DEFCONFIG_s390 = defconfig
+DEFCONFIG_loongarch = defconfig
+DEFCONFIG = $(DEFCONFIG_$(ARCH))
# optional tests to run (default = all)
TEST =
# QEMU_ARCH: arch names used by qemu
-QEMU_ARCH_i386 = i386
-QEMU_ARCH_x86_64 = x86_64
-QEMU_ARCH_x86 = x86_64
-QEMU_ARCH_arm64 = aarch64
-QEMU_ARCH_arm = arm
-QEMU_ARCH_mips = mipsel # works with malta_defconfig
-QEMU_ARCH_riscv = riscv64
-QEMU_ARCH_s390 = s390x
-QEMU_ARCH = $(QEMU_ARCH_$(ARCH))
+QEMU_ARCH_i386 = i386
+QEMU_ARCH_x86_64 = x86_64
+QEMU_ARCH_x86 = x86_64
+QEMU_ARCH_arm64 = aarch64
+QEMU_ARCH_arm = arm
+QEMU_ARCH_mips = mipsel # works with malta_defconfig
+QEMU_ARCH_riscv = riscv64
+QEMU_ARCH_s390 = s390x
+QEMU_ARCH_loongarch = loongarch64
+QEMU_ARCH = $(QEMU_ARCH_$(ARCH))
# QEMU_ARGS : some arch-specific args to pass to qemu
-QEMU_ARGS_i386 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)"
-QEMU_ARGS_x86_64 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)"
-QEMU_ARGS_x86 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)"
-QEMU_ARGS_arm64 = -M virt -cpu cortex-a53 -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)"
-QEMU_ARGS_arm = -M virt -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)"
-QEMU_ARGS_mips = -M malta -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)"
-QEMU_ARGS_riscv = -M virt -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
-QEMU_ARGS_s390 = -M s390-ccw-virtio -m 1G -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
-QEMU_ARGS = $(QEMU_ARGS_$(ARCH))
+QEMU_ARGS_i386 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+QEMU_ARGS_x86_64 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+QEMU_ARGS_x86 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+QEMU_ARGS_arm64 = -M virt -cpu cortex-a53 -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+QEMU_ARGS_arm = -M virt -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+QEMU_ARGS_mips = -M malta -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+QEMU_ARGS_riscv = -M virt -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+QEMU_ARGS_s390 = -M s390-ccw-virtio -m 1G -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+QEMU_ARGS = $(QEMU_ARGS_$(ARCH))
# OUTPUT is only set when run from the main makefile, otherwise
# it defaults to this nolibc directory.
@@ -70,8 +76,16 @@ else
Q=@
endif
+CFLAGS_STACKPROTECTOR = -DNOLIBC_STACKPROTECTOR \
+ $(call cc-option,-mstack-protector-guard=global) \
+ $(call cc-option,-fstack-protector-all)
+CFLAGS_STKP_i386 = $(CFLAGS_STACKPROTECTOR)
+CFLAGS_STKP_x86_64 = $(CFLAGS_STACKPROTECTOR)
+CFLAGS_STKP_x86 = $(CFLAGS_STACKPROTECTOR)
CFLAGS_s390 = -m64
-CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables $(CFLAGS_$(ARCH))
+CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables \
+ $(call cc-option,-fno-stack-protector) \
+ $(CFLAGS_STKP_$(ARCH)) $(CFLAGS_$(ARCH))
LDFLAGS := -s
help:
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index c4a0c915139c..21bacc928bf7 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -130,111 +130,111 @@ static int pad_spc(int llen, int cnt, const char *fmt, ...)
*/
#define EXPECT_ZR(cond, expr) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_zr(expr, llen); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_zr(expr, llen); } while (0)
static int expect_zr(int expr, int llen)
{
int ret = !(expr == 0);
llen += printf(" = %d ", expr);
- pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n");
+ pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_NZ(cond, expr, val) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_nz(expr, llen; } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_nz(expr, llen; } while (0)
static int expect_nz(int expr, int llen)
{
int ret = !(expr != 0);
llen += printf(" = %d ", expr);
- pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n");
+ pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_EQ(cond, expr, val) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_eq(expr, llen, val); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_eq(expr, llen, val); } while (0)
-static int expect_eq(int expr, int llen, int val)
+static int expect_eq(uint64_t expr, int llen, uint64_t val)
{
int ret = !(expr == val);
- llen += printf(" = %d ", expr);
- pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n");
+ llen += printf(" = %lld ", expr);
+ pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_NE(cond, expr, val) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_ne(expr, llen, val); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ne(expr, llen, val); } while (0)
static int expect_ne(int expr, int llen, int val)
{
int ret = !(expr != val);
llen += printf(" = %d ", expr);
- pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n");
+ pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_GE(cond, expr, val) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_ge(expr, llen, val); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ge(expr, llen, val); } while (0)
static int expect_ge(int expr, int llen, int val)
{
int ret = !(expr >= val);
llen += printf(" = %d ", expr);
- pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n");
+ pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_GT(cond, expr, val) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_gt(expr, llen, val); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_gt(expr, llen, val); } while (0)
static int expect_gt(int expr, int llen, int val)
{
int ret = !(expr > val);
llen += printf(" = %d ", expr);
- pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n");
+ pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_LE(cond, expr, val) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_le(expr, llen, val); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_le(expr, llen, val); } while (0)
static int expect_le(int expr, int llen, int val)
{
int ret = !(expr <= val);
llen += printf(" = %d ", expr);
- pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n");
+ pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_LT(cond, expr, val) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_lt(expr, llen, val); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_lt(expr, llen, val); } while (0)
static int expect_lt(int expr, int llen, int val)
{
int ret = !(expr < val);
llen += printf(" = %d ", expr);
- pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n");
+ pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_SYSZR(cond, expr) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_syszr(expr, llen); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syszr(expr, llen); } while (0)
static int expect_syszr(int expr, int llen)
{
@@ -243,17 +243,17 @@ static int expect_syszr(int expr, int llen)
if (expr) {
ret = 1;
llen += printf(" = %d %s ", expr, errorname(errno));
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
llen += printf(" = %d ", expr);
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
#define EXPECT_SYSEQ(cond, expr, val) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_syseq(expr, llen, val); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syseq(expr, llen, val); } while (0)
static int expect_syseq(int expr, int llen, int val)
{
@@ -262,17 +262,17 @@ static int expect_syseq(int expr, int llen, int val)
if (expr != val) {
ret = 1;
llen += printf(" = %d %s ", expr, errorname(errno));
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
llen += printf(" = %d ", expr);
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
#define EXPECT_SYSNE(cond, expr, val) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_sysne(expr, llen, val); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_sysne(expr, llen, val); } while (0)
static int expect_sysne(int expr, int llen, int val)
{
@@ -281,17 +281,17 @@ static int expect_sysne(int expr, int llen, int val)
if (expr == val) {
ret = 1;
llen += printf(" = %d %s ", expr, errorname(errno));
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
llen += printf(" = %d ", expr);
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
#define EXPECT_SYSER(cond, expr, expret, experr) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_syserr(expr, expret, experr, llen); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syserr(expr, expret, experr, llen); } while (0)
static int expect_syserr(int expr, int expret, int experr, int llen)
{
@@ -302,16 +302,16 @@ static int expect_syserr(int expr, int expret, int experr, int llen)
if (expr != expret || _errno != experr) {
ret = 1;
llen += printf(" != (%d %s) ", expret, errorname(experr));
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
#define EXPECT_PTRZR(cond, expr) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_ptrzr(expr, llen); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrzr(expr, llen); } while (0)
static int expect_ptrzr(const void *expr, int llen)
{
@@ -320,16 +320,16 @@ static int expect_ptrzr(const void *expr, int llen)
llen += printf(" = <%p> ", expr);
if (expr) {
ret = 1;
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
#define EXPECT_PTRNZ(cond, expr) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_ptrnz(expr, llen); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrnz(expr, llen); } while (0)
static int expect_ptrnz(const void *expr, int llen)
{
@@ -338,16 +338,16 @@ static int expect_ptrnz(const void *expr, int llen)
llen += printf(" = <%p> ", expr);
if (!expr) {
ret = 1;
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
#define EXPECT_STRZR(cond, expr) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_strzr(expr, llen); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strzr(expr, llen); } while (0)
static int expect_strzr(const char *expr, int llen)
{
@@ -356,16 +356,16 @@ static int expect_strzr(const char *expr, int llen)
llen += printf(" = <%s> ", expr);
if (expr) {
ret = 1;
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
#define EXPECT_STRNZ(cond, expr) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_strnz(expr, llen); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strnz(expr, llen); } while (0)
static int expect_strnz(const char *expr, int llen)
{
@@ -374,16 +374,16 @@ static int expect_strnz(const char *expr, int llen)
llen += printf(" = <%s> ", expr);
if (!expr) {
ret = 1;
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
#define EXPECT_STREQ(cond, expr, cmp) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_streq(expr, llen, cmp); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_streq(expr, llen, cmp); } while (0)
static int expect_streq(const char *expr, int llen, const char *cmp)
{
@@ -392,16 +392,16 @@ static int expect_streq(const char *expr, int llen, const char *cmp)
llen += printf(" = <%s> ", expr);
if (strcmp(expr, cmp) != 0) {
ret = 1;
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
#define EXPECT_STRNE(cond, expr, cmp) \
- do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_strne(expr, llen, cmp); } while (0)
+ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strne(expr, llen, cmp); } while (0)
static int expect_strne(const char *expr, int llen, const char *cmp)
{
@@ -410,9 +410,9 @@ static int expect_strne(const char *expr, int llen, const char *cmp)
llen += printf(" = <%s> ", expr);
if (strcmp(expr, cmp) == 0) {
ret = 1;
- llen += pad_spc(llen, 40, "[FAIL]\n");
+ llen += pad_spc(llen, 64, "[FAIL]\n");
} else {
- llen += pad_spc(llen, 40, " [OK]\n");
+ llen += pad_spc(llen, 64, " [OK]\n");
}
return ret;
}
@@ -477,6 +477,7 @@ static int test_getpagesize(void)
int run_syscall(int min, int max)
{
struct stat stat_buf;
+ int euid0;
int proc;
int test;
int tmp;
@@ -486,6 +487,9 @@ int run_syscall(int min, int max)
/* <proc> indicates whether or not /proc is mounted */
proc = stat("/proc", &stat_buf) == 0;
+ /* this will be used to skip certain tests that can't be run unprivileged */
+ euid0 = geteuid() == 0;
+
for (test = min; test >= 0 && test <= max; test++) {
int llen = 0; // line length
@@ -511,7 +515,7 @@ int run_syscall(int min, int max)
CASE_TEST(chmod_net); EXPECT_SYSZR(proc, chmod("/proc/self/net", 0555)); break;
CASE_TEST(chmod_self); EXPECT_SYSER(proc, chmod("/proc/self", 0555), -1, EPERM); break;
CASE_TEST(chown_self); EXPECT_SYSER(proc, chown("/proc/self", 0, 0), -1, EPERM); break;
- CASE_TEST(chroot_root); EXPECT_SYSZR(1, chroot("/")); break;
+ CASE_TEST(chroot_root); EXPECT_SYSZR(euid0, chroot("/")); break;
CASE_TEST(chroot_blah); EXPECT_SYSER(1, chroot("/proc/self/blah"), -1, ENOENT); break;
CASE_TEST(chroot_exe); EXPECT_SYSER(proc, chroot("/proc/self/exe"), -1, ENOTDIR); break;
CASE_TEST(close_m1); EXPECT_SYSER(1, close(-1), -1, EBADF); break;
@@ -536,7 +540,7 @@ int run_syscall(int min, int max)
CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break;
CASE_TEST(link_blah); EXPECT_SYSER(1, link("/proc/self/blah", "/blah"), -1, ENOENT); break;
- CASE_TEST(link_dir); EXPECT_SYSER(1, link("/", "/blah"), -1, EPERM); break;
+ CASE_TEST(link_dir); EXPECT_SYSER(euid0, link("/", "/blah"), -1, EPERM); break;
CASE_TEST(link_cross); EXPECT_SYSER(proc, link("/proc/self/net", "/blah"), -1, EXDEV); break;
CASE_TEST(lseek_m1); EXPECT_SYSER(1, lseek(-1, 0, SEEK_SET), -1, EBADF); break;
CASE_TEST(lseek_0); EXPECT_SYSER(1, lseek(0, 0, SEEK_SET), -1, ESPIPE); break;
@@ -602,6 +606,59 @@ int run_stdlib(int min, int max)
CASE_TEST(memcmp_e0_20); EXPECT_GT(1, memcmp("aaa\xe0", "aaa\x20", 4), 0); break;
CASE_TEST(memcmp_80_e0); EXPECT_LT(1, memcmp("aaa\x80", "aaa\xe0", 4), 0); break;
CASE_TEST(memcmp_e0_80); EXPECT_GT(1, memcmp("aaa\xe0", "aaa\x80", 4), 0); break;
+ CASE_TEST(limit_int8_max); EXPECT_EQ(1, INT8_MAX, (int8_t) 0x7f); break;
+ CASE_TEST(limit_int8_min); EXPECT_EQ(1, INT8_MIN, (int8_t) 0x80); break;
+ CASE_TEST(limit_uint8_max); EXPECT_EQ(1, UINT8_MAX, (uint8_t) 0xff); break;
+ CASE_TEST(limit_int16_max); EXPECT_EQ(1, INT16_MAX, (int16_t) 0x7fff); break;
+ CASE_TEST(limit_int16_min); EXPECT_EQ(1, INT16_MIN, (int16_t) 0x8000); break;
+ CASE_TEST(limit_uint16_max); EXPECT_EQ(1, UINT16_MAX, (uint16_t) 0xffff); break;
+ CASE_TEST(limit_int32_max); EXPECT_EQ(1, INT32_MAX, (int32_t) 0x7fffffff); break;
+ CASE_TEST(limit_int32_min); EXPECT_EQ(1, INT32_MIN, (int32_t) 0x80000000); break;
+ CASE_TEST(limit_uint32_max); EXPECT_EQ(1, UINT32_MAX, (uint32_t) 0xffffffff); break;
+ CASE_TEST(limit_int64_max); EXPECT_EQ(1, INT64_MAX, (int64_t) 0x7fffffffffffffff); break;
+ CASE_TEST(limit_int64_min); EXPECT_EQ(1, INT64_MIN, (int64_t) 0x8000000000000000); break;
+ CASE_TEST(limit_uint64_max); EXPECT_EQ(1, UINT64_MAX, (uint64_t) 0xffffffffffffffff); break;
+ CASE_TEST(limit_int_least8_max); EXPECT_EQ(1, INT_LEAST8_MAX, (int_least8_t) 0x7f); break;
+ CASE_TEST(limit_int_least8_min); EXPECT_EQ(1, INT_LEAST8_MIN, (int_least8_t) 0x80); break;
+ CASE_TEST(limit_uint_least8_max); EXPECT_EQ(1, UINT_LEAST8_MAX, (uint_least8_t) 0xff); break;
+ CASE_TEST(limit_int_least16_max); EXPECT_EQ(1, INT_LEAST16_MAX, (int_least16_t) 0x7fff); break;
+ CASE_TEST(limit_int_least16_min); EXPECT_EQ(1, INT_LEAST16_MIN, (int_least16_t) 0x8000); break;
+ CASE_TEST(limit_uint_least16_max); EXPECT_EQ(1, UINT_LEAST16_MAX, (uint_least16_t) 0xffff); break;
+ CASE_TEST(limit_int_least32_max); EXPECT_EQ(1, INT_LEAST32_MAX, (int_least32_t) 0x7fffffff); break;
+ CASE_TEST(limit_int_least32_min); EXPECT_EQ(1, INT_LEAST32_MIN, (int_least32_t) 0x80000000); break;
+ CASE_TEST(limit_uint_least32_max); EXPECT_EQ(1, UINT_LEAST32_MAX, (uint_least32_t) 0xffffffffU); break;
+ CASE_TEST(limit_int_least64_min); EXPECT_EQ(1, INT_LEAST64_MIN, (int_least64_t) 0x8000000000000000LL); break;
+ CASE_TEST(limit_int_least64_max); EXPECT_EQ(1, INT_LEAST64_MAX, (int_least64_t) 0x7fffffffffffffffLL); break;
+ CASE_TEST(limit_uint_least64_max); EXPECT_EQ(1, UINT_LEAST64_MAX, (uint_least64_t) 0xffffffffffffffffULL); break;
+ CASE_TEST(limit_int_fast8_max); EXPECT_EQ(1, INT_FAST8_MAX, (int_fast8_t) 0x7f); break;
+ CASE_TEST(limit_int_fast8_min); EXPECT_EQ(1, INT_FAST8_MIN, (int_fast8_t) 0x80); break;
+ CASE_TEST(limit_uint_fast8_max); EXPECT_EQ(1, UINT_FAST8_MAX, (uint_fast8_t) 0xff); break;
+ CASE_TEST(limit_int_fast16_min); EXPECT_EQ(1, INT_FAST16_MIN, (int_fast16_t) INTPTR_MIN); break;
+ CASE_TEST(limit_int_fast16_max); EXPECT_EQ(1, INT_FAST16_MAX, (int_fast16_t) INTPTR_MAX); break;
+ CASE_TEST(limit_uint_fast16_max); EXPECT_EQ(1, UINT_FAST16_MAX, (uint_fast16_t) UINTPTR_MAX); break;
+ CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) INTPTR_MIN); break;
+ CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) INTPTR_MAX); break;
+ CASE_TEST(limit_uint_fast32_max); EXPECT_EQ(1, UINT_FAST32_MAX, (uint_fast32_t) UINTPTR_MAX); break;
+ CASE_TEST(limit_int_fast64_min); EXPECT_EQ(1, INT_FAST64_MIN, (int_fast64_t) INTPTR_MIN); break;
+ CASE_TEST(limit_int_fast64_max); EXPECT_EQ(1, INT_FAST64_MAX, (int_fast64_t) INTPTR_MAX); break;
+ CASE_TEST(limit_uint_fast64_max); EXPECT_EQ(1, UINT_FAST64_MAX, (uint_fast64_t) UINTPTR_MAX); break;
+#if __SIZEOF_LONG__ == 8
+ CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x8000000000000000LL); break;
+ CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffffffffffffLL); break;
+ CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, (uintptr_t) 0xffffffffffffffffULL); break;
+ CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, (ptrdiff_t) 0x8000000000000000LL); break;
+ CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, (ptrdiff_t) 0x7fffffffffffffffLL); break;
+ CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, (size_t) 0xffffffffffffffffULL); break;
+#elif __SIZEOF_LONG__ == 4
+ CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x80000000); break;
+ CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffff); break;
+ CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, (uintptr_t) 0xffffffffU); break;
+ CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, (ptrdiff_t) 0x80000000); break;
+ CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, (ptrdiff_t) 0x7fffffff); break;
+ CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, (size_t) 0xffffffffU); break;
+#else
+# warning "__SIZEOF_LONG__ is undefined"
+#endif /* __SIZEOF_LONG__ */
case __LINE__:
return ret; /* must be last */
/* note: do not set any defaults so as to permit holes above */
@@ -610,6 +667,63 @@ int run_stdlib(int min, int max)
return ret;
}
+#if defined(__clang__)
+__attribute__((optnone))
+#elif defined(__GNUC__)
+__attribute__((optimize("O0")))
+#endif
+static int smash_stack(void)
+{
+ char buf[100];
+
+ for (size_t i = 0; i < 200; i++)
+ buf[i] = 'P';
+
+ return 1;
+}
+
+static int run_protection(int min, int max)
+{
+ pid_t pid;
+ int llen = 0, status;
+
+ llen += printf("0 -fstackprotector ");
+
+#if !defined(NOLIBC_STACKPROTECTOR)
+ llen += printf("not supported");
+ pad_spc(llen, 64, "[SKIPPED]\n");
+ return 0;
+#endif
+
+ pid = -1;
+ pid = fork();
+
+ switch (pid) {
+ case -1:
+ llen += printf("fork()");
+ pad_spc(llen, 64, "[FAIL]\n");
+ return 1;
+
+ case 0:
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ smash_stack();
+ return 1;
+
+ default:
+ pid = waitpid(pid, &status, 0);
+
+ if (pid == -1 || !WIFSIGNALED(status) || WTERMSIG(status) != SIGABRT) {
+ llen += printf("waitpid()");
+ pad_spc(llen, 64, "[FAIL]\n");
+ return 1;
+ }
+ pad_spc(llen, 64, " [OK]\n");
+ return 0;
+ }
+}
+
/* prepare what needs to be prepared for pid 1 (stdio, /dev, /proc, etc) */
int prepare(void)
{
@@ -660,10 +774,11 @@ int prepare(void)
}
/* This is the definition of known test names, with their functions */
-static struct test test_names[] = {
+static const struct test test_names[] = {
/* add new tests here */
- { .name = "syscall", .func = run_syscall },
- { .name = "stdlib", .func = run_stdlib },
+ { .name = "syscall", .func = run_syscall },
+ { .name = "stdlib", .func = run_stdlib },
+ { .name = "protection", .func = run_protection },
{ 0 }
};