Skip to content

Commit

Permalink
Merge tag 'nolibc.2023.04.04a' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/paulmck/linux-rcu

Pull nolibc updates from Paul McKenney:

 - Add support for loongarch

 - Fix stack-protector issues

 - Support additional integral types and signal-related macros

 - Add support for stdin, stdout, and stderr

 - Add getuid() and geteuid()

 - Allow S_I* macros to be overridden by program

 - Defer to linux/fcntl.h and linux/stat.h to avoid duplicate
   definitions

 - Many improvements to the selftests

* tag 'nolibc.2023.04.04a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: (22 commits)
  tools/nolibc: x86_64: add stackprotector support
  tools/nolibc: i386: add stackprotector support
  tools/nolibc: tests: add test for -fstack-protector
  tools/nolibc: tests: fold in no-stack-protector cflags
  tools/nolibc: add support for stack protector
  tools/nolibc: tests: constify test_names
  tools/nolibc: add helpers for wait() signal exits
  tools/nolibc: add definitions for standard fds
  selftests/nolibc: Adjust indentation for Makefile
  selftests/nolibc: Add support for LoongArch
  tools/nolibc: Add support for LoongArch
  tools/nolibc: Add statx() and make stat() rely on statx() if necessary
  tools/nolibc: Include linux/fcntl.h and remove duplicate code
  tools/nolibc: check for S_I* macros before defining them
  selftests/nolibc: skip the chroot_root and link_dir tests when not privileged
  tools/nolibc: add getuid() and geteuid()
  tools/nolibc: add tests for the integer limits in stdint.h
  tools/nolibc: enlarge column width of tests
  tools/nolibc: add integer types and integer limit macros
  tools/nolibc: add stdint.h
  ...
  • Loading branch information
Linus Torvalds committed Apr 24, 2023
2 parents 4a4075a + 0d8c461 commit 5d77652
Show file tree
Hide file tree
Showing 15 changed files with 718 additions and 115 deletions.
1 change: 1 addition & 0 deletions tools/include/nolibc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sysroot
4 changes: 2 additions & 2 deletions tools/include/nolibc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion tools/include/nolibc/arch-i386.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,16 +181,21 @@ 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:
* 1) last pushed argument must be 16-byte aligned.
* 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)
Expand Down
200 changes: 200 additions & 0 deletions tools/include/nolibc/arch-loongarch.h
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions tools/include/nolibc/arch-x86_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions tools/include/nolibc/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
1 change: 1 addition & 0 deletions tools/include/nolibc/nolibc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions tools/include/nolibc/stackprotector.h
Original file line number Diff line number Diff line change
@@ -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
15 changes: 1 addition & 14 deletions tools/include/nolibc/std.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 5d77652

Please sign in to comment.