Intel CET (Control-flow Enforcement Technology)

{endbr64, endbr32} at target of computed jmp/call; 'notrack' at source
	modified:   stub/src/amd64-linux.elf-entry.S
	modified:   stub/src/amd64-linux.elf-fold.S
	modified:   stub/src/amd64-linux.elf-main2.c
	modified:   stub/src/arch/amd64/macros.S
	modified:   stub/src/arch/i386/macros.S
	modified:   stub/src/i386-expand.S
	modified:   stub/src/i386-linux.elf-entry.S
	modified:   stub/src/i386-linux.elf-fold.S
	modified:   stub/src/i386-linux.elf-main2.c
This commit is contained in:
John Reiser 2024-08-02 12:56:09 -07:00
parent 7e75491e88
commit 3869a67180
9 changed files with 45 additions and 17 deletions

View File

@ -86,6 +86,7 @@ M_NRV2E_LE32=8
section ELFMAINX section ELFMAINX
sz_pack2= .-4 sz_pack2= .-4
_start: .globl _start _start: .globl _start
endbr64
//// nop; int3 # uncomment for debugging //// nop; int3 # uncomment for debugging
pop %rcx // argc pop %rcx // argc
@ -304,6 +305,7 @@ here: // OUT: %rdi= (2+ retaddrj) without disturbing shadow stack
ret ret
getbit: getbit:
.byte 0xf3,0x0f,0x1e,0xfa // endbr64 // from "call *%rdx"
addl bits,bits; jz refill // Carry= next bit addl bits,bits; jz refill // Carry= next bit
rep; ret rep; ret
refill: refill:

View File

@ -86,6 +86,7 @@ PAGE_MASK: .quad -1<<12 // default
// no 'section', thus '.text'; also loaded first in amd64-linux.elf-fold.bin. // no 'section', thus '.text'; also loaded first in amd64-linux.elf-fold.bin.
// Code from amd64-linux.elf-main.c is also .text, and is next. // Code from amd64-linux.elf-main.c is also .text, and is next.
fold_begin: fold_begin:
endbr64
//// int3 # DEBUG //// int3 # DEBUG
mov %r13,F_UNMAPA(%rbp) mov %r13,F_UNMAPA(%rbp)
mov %r13,%rax; and $is_ptinterp,%eax; or %eax,F_ELFA(%rbp) mov %r13,%rax; and $is_ptinterp,%eax; or %eax,F_ELFA(%rbp)
@ -202,7 +203,7 @@ no_pse_map:
pop %arg1 # ADRU: unfolded upx_main etc. pop %arg1 # ADRU: unfolded upx_main etc.
pop %arg2 # LENU pop %arg2 # LENU
push $__NR_munmap; pop %rax push $__NR_munmap; pop %rax
jmp *(%r14) # goto: syscall; pop %rdx; ret /*notrack*/ jmp *(%r14) # goto: syscall; pop %rdx; ret
get_page_mask: .globl get_page_mask get_page_mask: .globl get_page_mask
mov PAGE_MASK(%rip),%rax mov PAGE_MASK(%rip),%rax

View File

@ -253,16 +253,22 @@ make_hatch_x86_64(
) )
{ {
char *hatch = next_unc; char *hatch = next_unc;
unsigned const sz_code = 4; int code[3] = {
0xfa1e0ff3, // endbr64
0x585a050f, // syscall; pop %arg3{%rdx}; pop %rax
0x90e0ff3e, // notrack jmp *%rax; nop
};
DPRINTF("make_hatch %%p %%p %%x\\n", phdr, next_unc, frag_mask); DPRINTF("make_hatch %%p %%p %%x\\n", phdr, next_unc, frag_mask);
if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) { if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
if (sz_code <= (frag_mask & -(long)hatch)) { if (sizeof(code) <= (unsigned)(frag_mask & -(long)hatch)) {
((long *)hatch)[0] = 0xc35a050f; // syscall; pop %arg3{%rdx); ret ((int *)hatch)[0] = code[0]; // endbr64
((int *)hatch)[1] = code[1]; // syscall; pop %arg3{%rdx}; pop %rax
((int *)hatch)[2] = code[2]; // notrack jmp *%rax; nop
} }
else { // Does not fit at hi end of .text, so must use a new page "permanently" else { // Does not fit at hi end of .text, so must use a new page "permanently"
int mfd = upxfd_create(addr_string("upx"), MFD_EXEC); // the directory entry int mfd = upxfd_create(addr_string("upx"), MFD_EXEC); // the directory entry
write(mfd, addr_string("\x0f\x05\x5a\xc3"), sz_code); write(mfd, &code, sizeof(code));
hatch = mmap(0, sz_code, PROT_READ|PROT_EXEC, MAP_SHARED, mfd, 0); hatch = mmap(0, sizeof(code), PROT_READ|PROT_EXEC, MAP_SHARED, mfd, 0);
close(mfd); close(mfd);
} }
} }

View File

@ -41,4 +41,8 @@
.code64 .code64
.endm .endm
.macro endbr64
.byte 0xf3,0x0f,0x1e,0xfa
.endm
// vi:ts=8:et:nowrap // vi:ts=8:et:nowrap

View File

@ -717,4 +717,8 @@ section LXUNF035
ret ret
.endm .endm
.macro endbr32
.byte 0xf3,0x0f,0x1e,0xfb
.endm
// vi:ts=8:et:nowrap // vi:ts=8:et:nowrap

View File

@ -77,6 +77,9 @@ sz_binfo= 3*4
f_unfilter: // (*f_unf)(xo->buf, out_len, h.b_cto8, h.b_ftid); f_unfilter: // (*f_unf)(xo->buf, out_len, h.b_cto8, h.b_ftid);
#include "arch/i386/bxx.S" #include "arch/i386/bxx.S"
.macro endbr32
.byte 0xf3,0x0f,0x1e,0xfb
.endm
// int f_expand(nrv_byte const *src, nrv_byte *dst, size_t *dstlen) // C-callable // int f_expand(nrv_byte const *src, nrv_byte *dst, size_t *dstlen) // C-callable
// Includes unfilter and cache flush. // Includes unfilter and cache flush.
@ -128,6 +131,7 @@ refill:
movzbl (%esi),%edx // pre-fetch: literal, or bottom 8 bits of offset movzbl (%esi),%edx // pre-fetch: literal, or bottom 8 bits of offset
rep; ret rep; ret
getbit: getbit:
endbr32 // from "call *%edx"
addl bits,bits; jz refill // Carry= next bit addl bits,bits; jz refill // Carry= next bit
rep; ret rep; ret

View File

@ -104,6 +104,7 @@ M_NRV2B_LE32= 2
section ELFMAINX section ELFMAINX
sz_pack2 = -NBPW+ _start sz_pack2 = -NBPW+ _start
_start: .globl _start _start: .globl _start
endbr32
/// nop; int3 // DEBUG i386 entry.S /// nop; int3 // DEBUG i386 entry.S
call L70 // MATCH_08 push $&getbit call L70 // MATCH_08 push $&getbit
L70ret: L70ret:
@ -322,7 +323,7 @@ eof_n2b:
mov F_ADRU(%ebp),%eax mov F_ADRU(%ebp),%eax
add $D_FOLD,%eax // PAGE_MASK, upxfd_path, mflg_data add $D_FOLD,%eax // PAGE_MASK, upxfd_path, mflg_data
jmp *%eax /*notrack*/ jmp *%eax
// %esp: // %esp:
// MATCH_13 ptr unfolded_code; for escape hatch // MATCH_13 ptr unfolded_code; for escape hatch
// MATCH_12 len unfolded code; for escape hatch // MATCH_12 len unfolded code; for escape hatch

View File

@ -101,7 +101,9 @@ upxfn_path= . - 2*NBPW // displacement to filename string
mflg_data= . - 1*NBPW // QNZ vs Linux mflg_data= . - 1*NBPW // QNZ vs Linux
fold_begin: fold_begin:
endbr32
//// int3 // DEBUG //// int3 // DEBUG
endbr32
pop ebx; push ebx // F_ADRX: elfaddr + (O_BINFO | is_ptinterp | unmap_all_pages) pop ebx; push ebx // F_ADRX: elfaddr + (O_BINFO | is_ptinterp | unmap_all_pages)
jmp L10 jmp L10
@ -285,7 +287,7 @@ L60:
push eax // 32 bytes of zeroes now on stack, ready for 'popa' push eax // 32 bytes of zeroes now on stack, ready for 'popa'
mov al, __NR_munmap // eax was 0 from L60 mov al, __NR_munmap // eax was 0 from L60
jmp [edi] // unmap ourselves via escape hatch, then goto entry /*notrack*/ jmp [edi] // unmap ourselves via escape hatch, then goto entry
section SYSCALLS section SYSCALLS
// Sometimes linux enforces page-aligned address // Sometimes linux enforces page-aligned address

View File

@ -289,27 +289,31 @@ make_hatch_i386(
unsigned frag_mask unsigned frag_mask
) )
{ {
char *hatch = 0; unsigned *hatch = 0;
unsigned code[2] = {
0x586180cd, // int #0x80; popa; pop %eax
0x90e0ff3e, // notrack jmp *%eax; nop
}
DPRINTF("make_hatch %%p %%p %%x\\n", phdr, next_unc, frag_mask); DPRINTF("make_hatch %%p %%p %%x\\n", phdr, next_unc, frag_mask);
if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) { if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
next_unc += phdr->p_memsz - phdr->p_filesz; // Skip over local .bss next_unc += phdr->p_memsz - phdr->p_filesz; // Skip over local .bss
frag_mask &= -(long)next_unc; // bytes left on page frag_mask &= -(long)next_unc; // bytes left on page
unsigned /*const*/ escape = 0xc36180cd; // "int $0x80; popa; ret" if (sizeof(code) <= frag_mask) {
if (4 <= frag_mask) { hatch = (unsigned *)next_unc;
hatch = next_unc; hatch[0] = code[0];
*(long *)&hatch[0] = escape; hatch[1] = code[1];
} }
else { // Does not fit at hi end of .text, so must use a new page "permanently" else { // Does not fit at hi end of .text, so must use a new page "permanently"
unsigned long fdmap = upx_mmap_and_fd((void *)0, sizeof(escape), nullptr); unsigned long fdmap = upx_mmap_and_fd((void *)0, sizeof(code), nullptr);
unsigned mfd = -1+ (0xfff& fdmap); unsigned mfd = -1+ (0xfff& fdmap);
write(mfd, &escape, sizeof(escape)); write(mfd, &code, sizeof(code));
hatch = mmap((void *)(fdmap & ~0xffful), sizeof(escape), hatch = mmap((void *)(fdmap & ~0xffful), sizeof(code),
PROT_READ|PROT_EXEC, MAP_PRIVATE, mfd, 0); PROT_READ|PROT_EXEC, MAP_PRIVATE, mfd, 0);
close(mfd); close(mfd);
} }
} }
DPRINTF("hatch=%%p\\n", hatch); DPRINTF("hatch=%%p\\n", hatch);
return hatch; return (char *)hatch;
} }
#elif defined(__arm__) /*}{*/ #elif defined(__arm__) /*}{*/
extern unsigned get_sys_munmap(void); extern unsigned get_sys_munmap(void);