Message ID | 20240721230420.3684982-1-hjl.tools@gmail.com |
---|---|
State | New |
Headers | show |
Series | [v2] x32/cet: Enable shadow stack during startup for Linux 6.10 | expand |
On Mon, Jul 22, 2024 at 7:04 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > Enable shadow stack during startup for Linux 6.10: > > commit 2883f01ec37dd8668e7222dfdb5980c86fdfe277 > Author: H.J. Lu <hjl.tools@gmail.com> > Date: Fri Mar 15 07:04:33 2024 -0700 > > x86/shstk: Enable shadow stacks for x32 > > 1. Add shadow stack support to x32 signal. > 2. Use the 64-bit map_shadow_stack syscall for x32. > 3. Set up shadow stack for x32. > > Add the map_shadow_stack system call to <fixup-asm-unistd.h> and regenerate > arch-syscall.h. Tested on Intel Tiger Lake. > --- > sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h | 1 + > sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h | 4 ++++ > sysdeps/x86_64/x32/dl-machine.h | 7 +++++-- > 3 files changed, 10 insertions(+), 2 deletions(-) > > diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h > index 3040a47d72..df3e22236d 100644 > --- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h > +++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h > @@ -155,6 +155,7 @@ > #define __NR_lsm_set_self_attr 1073742284 > #define __NR_lstat 1073741830 > #define __NR_madvise 1073741852 > +#define __NR_map_shadow_stack 1073742277 > #define __NR_mbind 1073742061 > #define __NR_membarrier 1073742148 > #define __NR_memfd_create 1073742143 > diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h > index 98124169e6..47fa8af4ce 100644 > --- a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h > +++ b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h > @@ -15,6 +15,10 @@ > License along with the GNU C Library; if not, see > <http://www.gnu.org/licenses/>. */ > > +#ifndef __NR_map_shadow_stack > +# define __NR_map_shadow_stack 1073742277 > +#endif > + > /* X32 uses the same 64-bit syscall interface for set_thread_area. */ > #ifndef __NR_set_thread_area > # define __NR_set_thread_area 1073742029 > diff --git a/sysdeps/x86_64/x32/dl-machine.h b/sysdeps/x86_64/x32/dl-machine.h > index c35cee9261..3eb59bde7c 100644 > --- a/sysdeps/x86_64/x32/dl-machine.h > +++ b/sysdeps/x86_64/x32/dl-machine.h > @@ -45,13 +45,16 @@ _start:\n\ > _dl_start_user:\n\ > # Save the user entry point address in %r12.\n\ > movl %eax, %r12d\n\ > + # Save %rsp value in %r13.\n\ > + movl %esp, %r13d\n\ > +"\ > + RTLD_START_ENABLE_X86_FEATURES \ > +"\ > # Read the original argument count.\n\ > movl (%rsp), %edx\n\ > # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\ > # argc -> rsi\n\ > movl %edx, %esi\n\ > - # Save %rsp value in %r13.\n\ > - movl %esp, %r13d\n\ > # And align stack for the _dl_init call.\n\ > and $-16, %esp\n\ > # _dl_loaded -> rdi\n\ > -- > 2.45.2 > Could the RTLD_START could be shared between x32/x64 using the: `sysdeps/x86_64/multiarch/reg-macros.h"? Thinking something like: ``` #define RTLD_RSP "%" STRINGIFY(VRSP) #define RTLD_RAX "%" STRINGIFY(VRAX) #define RTLD_RCX "%" STRINGIFY(VRCX) #define RTLD_RDX "%" STRINGIFY(VRDX) #define RTLD_RSI "%" STRINGIFY(VRSI) #define RTLD_RDI "%" STRINGIFY(VRDI) #define RTLD_R13 "%" STRINGIFY(VR13) #define RTLD_R12 "%" STRINGIFY(VR12) #define RTLD_START asm ("\n\ .text\n\ .p2align " STRINGIFY(RTLD_ALIGN) "\n \ .globl _start\n\ .globl _dl_start_user\n\ _start:\n\ movl " RTLD_RSP "," RTLD_RDI "\n\ call _dl_start\n\ _dl_start_user:\n\ # Save the user entry point address in %r12.\n\ movl " RTLD_RAX ", " RTLD_R12 "\n\ # Save %rsp value in %r13.\n\ movl " RTLD_RSP ", " RTLD_R13 "\n\ "\ RTLD_START_ENABLE_X86_FEATURES \ "\ # Read the original argument count.\n\ movl (%rsp), " RTLD_RDX "\n\ # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\ # argc -> rsi\n\ movl " RTLD_RDX ", " RTLD_RSI "\n\ # And align stack for the _dl_init call.\n\ and $-16, " RTLD_RSP "\n\ # _dl_loaded -> rdi\n\ movl _rtld_local(%rip), " RTLD_RDI "\n\ # env -> rcx\n\ lea 8(%r13,%rdx,4), " RTLD_RCX "\n\ # argv -> rdx\n\ lea 4(%r13), " RTLD_RDX "\n\ # Clear %rbp to mark outermost frame obviously even for constructors.\n\ xorl %ebp, %ebp\n\ # Call the function to run the initializers.\n\ call _dl_init\n\ # Pass our finalizer function to the user in %rdx, as per ELF ABI.\n\ lea _dl_fini(%rip), " RTLD_RDX "\n\ # And make sure %rsp points to argc stored on the stack.\n\ movl " RTLD_R13 ", " RTLD_RSP "\n\ # Jump to the user's entry point.\n\ jmp *%r12\n\ .previous\n\ "); ``` Width `REG_WIDTH` defined as 4 for x32 and 8 for x64. (And align as 4 and 16 respectively).
On Mon, Jul 22, 2024, 7:37 PM Noah Goldstein <goldstein.w.n@gmail.com> wrote: > On Mon, Jul 22, 2024 at 7:04 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > Enable shadow stack during startup for Linux 6.10: > > > > commit 2883f01ec37dd8668e7222dfdb5980c86fdfe277 > > Author: H.J. Lu <hjl.tools@gmail.com> > > Date: Fri Mar 15 07:04:33 2024 -0700 > > > > x86/shstk: Enable shadow stacks for x32 > > > > 1. Add shadow stack support to x32 signal. > > 2. Use the 64-bit map_shadow_stack syscall for x32. > > 3. Set up shadow stack for x32. > > > > Add the map_shadow_stack system call to <fixup-asm-unistd.h> and > regenerate > > arch-syscall.h. Tested on Intel Tiger Lake. > > --- > > sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h | 1 + > > sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h | 4 ++++ > > sysdeps/x86_64/x32/dl-machine.h | 7 +++++-- > > 3 files changed, 10 insertions(+), 2 deletions(-) > > > > diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h > b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h > > index 3040a47d72..df3e22236d 100644 > > --- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h > > +++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h > > @@ -155,6 +155,7 @@ > > #define __NR_lsm_set_self_attr 1073742284 > > #define __NR_lstat 1073741830 > > #define __NR_madvise 1073741852 > > +#define __NR_map_shadow_stack 1073742277 > > #define __NR_mbind 1073742061 > > #define __NR_membarrier 1073742148 > > #define __NR_memfd_create 1073742143 > > diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h > b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h > > index 98124169e6..47fa8af4ce 100644 > > --- a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h > > +++ b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h > > @@ -15,6 +15,10 @@ > > License along with the GNU C Library; if not, see > > <http://www.gnu.org/licenses/>. */ > > > > +#ifndef __NR_map_shadow_stack > > +# define __NR_map_shadow_stack 1073742277 > > +#endif > > + > > /* X32 uses the same 64-bit syscall interface for set_thread_area. */ > > #ifndef __NR_set_thread_area > > # define __NR_set_thread_area 1073742029 > > diff --git a/sysdeps/x86_64/x32/dl-machine.h > b/sysdeps/x86_64/x32/dl-machine.h > > index c35cee9261..3eb59bde7c 100644 > > --- a/sysdeps/x86_64/x32/dl-machine.h > > +++ b/sysdeps/x86_64/x32/dl-machine.h > > @@ -45,13 +45,16 @@ _start:\n\ > > _dl_start_user:\n\ > > # Save the user entry point address in %r12.\n\ > > movl %eax, %r12d\n\ > > + # Save %rsp value in %r13.\n\ > > + movl %esp, %r13d\n\ > > +"\ > > + RTLD_START_ENABLE_X86_FEATURES \ > > +"\ > > # Read the original argument count.\n\ > > movl (%rsp), %edx\n\ > > # Call _dl_init (struct link_map *main_map, int argc, char > **argv, char **env)\n\ > > # argc -> rsi\n\ > > movl %edx, %esi\n\ > > - # Save %rsp value in %r13.\n\ > > - movl %esp, %r13d\n\ > > # And align stack for the _dl_init call.\n\ > > and $-16, %esp\n\ > > # _dl_loaded -> rdi\n\ > > -- > > 2.45.2 > > > > Could the RTLD_START could be shared between x32/x64 using the: > `sysdeps/x86_64/multiarch/reg-macros.h"? > I sent the v3 patch set to remove x32 dl-machine.h. > Thinking something like: > ``` > #define RTLD_RSP "%" STRINGIFY(VRSP) > #define RTLD_RAX "%" STRINGIFY(VRAX) > #define RTLD_RCX "%" STRINGIFY(VRCX) > #define RTLD_RDX "%" STRINGIFY(VRDX) > #define RTLD_RSI "%" STRINGIFY(VRSI) > #define RTLD_RDI "%" STRINGIFY(VRDI) > #define RTLD_R13 "%" STRINGIFY(VR13) > #define RTLD_R12 "%" STRINGIFY(VR12) > > #define RTLD_START asm ("\n\ > .text\n\ > .p2align " STRINGIFY(RTLD_ALIGN) "\n \ > .globl _start\n\ > .globl _dl_start_user\n\ > _start:\n\ > movl " RTLD_RSP "," RTLD_RDI "\n\ > call _dl_start\n\ > _dl_start_user:\n\ > # Save the user entry point address in %r12.\n\ > movl " RTLD_RAX ", " RTLD_R12 "\n\ > # Save %rsp value in %r13.\n\ > movl " RTLD_RSP ", " RTLD_R13 "\n\ > "\ > RTLD_START_ENABLE_X86_FEATURES \ > "\ > # Read the original argument count.\n\ > movl (%rsp), " RTLD_RDX "\n\ > # Call _dl_init (struct link_map *main_map, int argc, char **argv, > char **env)\n\ > # argc -> rsi\n\ > movl " RTLD_RDX ", " RTLD_RSI "\n\ > # And align stack for the _dl_init call.\n\ > and $-16, " RTLD_RSP "\n\ > # _dl_loaded -> rdi\n\ > movl _rtld_local(%rip), " RTLD_RDI "\n\ > # env -> rcx\n\ > lea 8(%r13,%rdx,4), " RTLD_RCX "\n\ > # argv -> rdx\n\ > lea 4(%r13), " RTLD_RDX "\n\ > # Clear %rbp to mark outermost frame obviously even for constructors.\n\ > xorl %ebp, %ebp\n\ > # Call the function to run the initializers.\n\ > call _dl_init\n\ > # Pass our finalizer function to the user in %rdx, as per ELF ABI.\n\ > lea _dl_fini(%rip), " RTLD_RDX "\n\ > # And make sure %rsp points to argc stored on the stack.\n\ > movl " RTLD_R13 ", " RTLD_RSP "\n\ > # Jump to the user's entry point.\n\ > jmp *%r12\n\ > .previous\n\ > "); > > ``` > > Width `REG_WIDTH` defined as 4 for x32 and 8 for x64. (And align > as 4 and 16 respectively). > >
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h index 3040a47d72..df3e22236d 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h @@ -155,6 +155,7 @@ #define __NR_lsm_set_self_attr 1073742284 #define __NR_lstat 1073741830 #define __NR_madvise 1073741852 +#define __NR_map_shadow_stack 1073742277 #define __NR_mbind 1073742061 #define __NR_membarrier 1073742148 #define __NR_memfd_create 1073742143 diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h index 98124169e6..47fa8af4ce 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h +++ b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h @@ -15,6 +15,10 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +#ifndef __NR_map_shadow_stack +# define __NR_map_shadow_stack 1073742277 +#endif + /* X32 uses the same 64-bit syscall interface for set_thread_area. */ #ifndef __NR_set_thread_area # define __NR_set_thread_area 1073742029 diff --git a/sysdeps/x86_64/x32/dl-machine.h b/sysdeps/x86_64/x32/dl-machine.h index c35cee9261..3eb59bde7c 100644 --- a/sysdeps/x86_64/x32/dl-machine.h +++ b/sysdeps/x86_64/x32/dl-machine.h @@ -45,13 +45,16 @@ _start:\n\ _dl_start_user:\n\ # Save the user entry point address in %r12.\n\ movl %eax, %r12d\n\ + # Save %rsp value in %r13.\n\ + movl %esp, %r13d\n\ +"\ + RTLD_START_ENABLE_X86_FEATURES \ +"\ # Read the original argument count.\n\ movl (%rsp), %edx\n\ # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\ # argc -> rsi\n\ movl %edx, %esi\n\ - # Save %rsp value in %r13.\n\ - movl %esp, %r13d\n\ # And align stack for the _dl_init call.\n\ and $-16, %esp\n\ # _dl_loaded -> rdi\n\