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
sz_pack2= .-4
_start: .globl _start
endbr64
//// nop; int3 # uncomment for debugging
pop %rcx // argc
@ -304,6 +305,7 @@ here: // OUT: %rdi= (2+ retaddrj) without disturbing shadow stack
ret
getbit:
.byte 0xf3,0x0f,0x1e,0xfa // endbr64 // from "call *%rdx"
addl bits,bits; jz refill // Carry= next bit
rep; ret
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.
// Code from amd64-linux.elf-main.c is also .text, and is next.
fold_begin:
endbr64
//// int3 # DEBUG
mov %r13,F_UNMAPA(%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 %arg2 # LENU
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
mov PAGE_MASK(%rip),%rax

View File

@ -253,16 +253,22 @@ make_hatch_x86_64(
)
{
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);
if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
if (sz_code <= (frag_mask & -(long)hatch)) {
((long *)hatch)[0] = 0xc35a050f; // syscall; pop %arg3{%rdx); ret
if (sizeof(code) <= (unsigned)(frag_mask & -(long)hatch)) {
((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"
int mfd = upxfd_create(addr_string("upx"), MFD_EXEC); // the directory entry
write(mfd, addr_string("\x0f\x05\x5a\xc3"), sz_code);
hatch = mmap(0, sz_code, PROT_READ|PROT_EXEC, MAP_SHARED, mfd, 0);
write(mfd, &code, sizeof(code));
hatch = mmap(0, sizeof(code), PROT_READ|PROT_EXEC, MAP_SHARED, mfd, 0);
close(mfd);
}
}

View File

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

View File

@ -717,4 +717,8 @@ section LXUNF035
ret
.endm
.macro endbr32
.byte 0xf3,0x0f,0x1e,0xfb
.endm
// 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);
#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
// Includes unfilter and cache flush.
@ -128,6 +131,7 @@ refill:
movzbl (%esi),%edx // pre-fetch: literal, or bottom 8 bits of offset
rep; ret
getbit:
endbr32 // from "call *%edx"
addl bits,bits; jz refill // Carry= next bit
rep; ret

View File

@ -104,6 +104,7 @@ M_NRV2B_LE32= 2
section ELFMAINX
sz_pack2 = -NBPW+ _start
_start: .globl _start
endbr32
/// nop; int3 // DEBUG i386 entry.S
call L70 // MATCH_08 push $&getbit
L70ret:
@ -322,7 +323,7 @@ eof_n2b:
mov F_ADRU(%ebp),%eax
add $D_FOLD,%eax // PAGE_MASK, upxfd_path, mflg_data
jmp *%eax
/*notrack*/ jmp *%eax
// %esp:
// MATCH_13 ptr 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
fold_begin:
endbr32
//// int3 // DEBUG
endbr32
pop ebx; push ebx // F_ADRX: elfaddr + (O_BINFO | is_ptinterp | unmap_all_pages)
jmp L10
@ -285,7 +287,7 @@ L60:
push eax // 32 bytes of zeroes now on stack, ready for 'popa'
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
// Sometimes linux enforces page-aligned address

View File

@ -289,27 +289,31 @@ make_hatch_i386(
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);
if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
next_unc += phdr->p_memsz - phdr->p_filesz; // Skip over local .bss
frag_mask &= -(long)next_unc; // bytes left on page
unsigned /*const*/ escape = 0xc36180cd; // "int $0x80; popa; ret"
if (4 <= frag_mask) {
hatch = next_unc;
*(long *)&hatch[0] = escape;
if (sizeof(code) <= frag_mask) {
hatch = (unsigned *)next_unc;
hatch[0] = code[0];
hatch[1] = code[1];
}
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);
write(mfd, &escape, sizeof(escape));
hatch = mmap((void *)(fdmap & ~0xffful), sizeof(escape),
write(mfd, &code, sizeof(code));
hatch = mmap((void *)(fdmap & ~0xffful), sizeof(code),
PROT_READ|PROT_EXEC, MAP_PRIVATE, mfd, 0);
close(mfd);
}
}
DPRINTF("hatch=%%p\\n", hatch);
return hatch;
return (char *)hatch;
}
#elif defined(__arm__) /*}{*/
extern unsigned get_sys_munmap(void);