Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 46 additions & 31 deletions arch/x86/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -1230,22 +1230,28 @@ NOKPROBE_SYMBOL(openpax_fault_is_trampoline);
static inline
bool openpax_emulate_trampoline_32(struct pt_regs *regs)
{
unsigned long ip = regs->ip;
unsigned int endbr;
int err;

/* With -fcf-protection, gcc starts its trampolines with endbr32. */
if (!get_user(endbr, (unsigned int __user *) ip) && endbr == 0xFB1E0FF3)
ip += 4;

/* libffi trampoline type 1, gcc trampoline type 2 */
do {
unsigned char mov, jmp;
unsigned int addr1, addr2;

#ifdef CONFIG_X86_64
if ((regs->ip + 9) >> 32)
if ((ip + 9) >> 32)
break;
#endif

err = get_user(mov, (unsigned char __user *) regs->ip);
err |= get_user(addr1, (unsigned int __user *) (regs->ip + 1));
err |= get_user(jmp, (unsigned char __user *) (regs->ip + 5));
err |= get_user(addr2, (unsigned int __user *) (regs->ip + 6));
err = get_user(mov, (unsigned char __user *) ip);
err |= get_user(addr1, (unsigned int __user *) (ip + 1));
err |= get_user(jmp, (unsigned char __user *) (ip + 5));
err |= get_user(addr2, (unsigned int __user *) (ip + 6));

if (err)
break;
Expand All @@ -1256,7 +1262,7 @@ bool openpax_emulate_trampoline_32(struct pt_regs *regs)
else
regs->cx = addr1;

regs->ip = (unsigned int)(regs->ip + addr2 + 10);
regs->ip = (unsigned int)(ip + addr2 + 10);
return true;
}
} while (0);
Expand All @@ -1268,15 +1274,15 @@ bool openpax_emulate_trampoline_32(struct pt_regs *regs)
unsigned int addr1, addr2;

#ifdef CONFIG_X86_64
if ((regs->ip + 11) >> 32)
if ((ip + 11) >> 32)
break;
#endif

err = get_user(mov1, (unsigned char __user *) regs->ip);
err |= get_user(addr1, (unsigned int __user *) (regs->ip + 1));
err |= get_user(mov2, (unsigned char __user *) (regs->ip + 5));
err |= get_user(addr2, (unsigned int __user *) (regs->ip + 6));
err |= get_user(jmp, (unsigned short __user *) (regs->ip + 10));
err = get_user(mov1, (unsigned char __user *) ip);
err |= get_user(addr1, (unsigned int __user *) (ip + 1));
err |= get_user(mov2, (unsigned char __user *) (ip + 5));
err |= get_user(addr2, (unsigned int __user *) (ip + 6));
err |= get_user(jmp, (unsigned short __user *) (ip + 10));

if (err)
break;
Expand All @@ -1297,21 +1303,30 @@ NOKPROBE_SYMBOL(openpax_emulate_trampoline_32);
static inline
bool openpax_emulate_trampoline_64(struct pt_regs *regs)
{
unsigned long ip = regs->ip;
unsigned int endbr;
int err;

/*
* gcc built with -fcf-protection, the default on Ubuntu and Fedora,
* starts its trampolines with endbr64.
*/
if (!get_user(endbr, (unsigned int __user *) ip) && endbr == 0xFA1E0FF3)
ip += 4;

/* libffi trampoline type 1 */
do {
unsigned short mov1, mov2, jmp1;
unsigned char stcclc, jmp2;
unsigned long addr1, addr2;

err = get_user(mov1, (unsigned short __user *) regs->ip);
err |= get_user(addr1, (unsigned long __user *) (regs->ip + 2));
err |= get_user(mov2, (unsigned short __user *) (regs->ip + 10));
err |= get_user(addr2, (unsigned long __user *) (regs->ip + 12));
err |= get_user(stcclc, (unsigned char __user *) (regs->ip + 20));
err |= get_user(jmp1, (unsigned short __user *) (regs->ip + 21));
err |= get_user(jmp2, (unsigned char __user *) (regs->ip + 23));
err = get_user(mov1, (unsigned short __user *) ip);
err |= get_user(addr1, (unsigned long __user *) (ip + 2));
err |= get_user(mov2, (unsigned short __user *) (ip + 10));
err |= get_user(addr2, (unsigned long __user *) (ip + 12));
err |= get_user(stcclc, (unsigned char __user *) (ip + 20));
err |= get_user(jmp1, (unsigned short __user *) (ip + 21));
err |= get_user(jmp2, (unsigned char __user *) (ip + 23));

if (err)
break;
Expand All @@ -1337,12 +1352,12 @@ bool openpax_emulate_trampoline_64(struct pt_regs *regs)
unsigned int addr1;
unsigned long addr2;

err = get_user(mov1, (unsigned short __user *) regs->ip);
err |= get_user(addr1, (unsigned int __user *) (regs->ip + 2));
err |= get_user(mov2, (unsigned short __user *) (regs->ip + 6));
err |= get_user(addr2, (unsigned long __user *) (regs->ip + 8));
err |= get_user(jmp1, (unsigned short __user *) (regs->ip + 16));
err |= get_user(jmp2, (unsigned char __user *) (regs->ip + 18));
err = get_user(mov1, (unsigned short __user *) ip);
err |= get_user(addr1, (unsigned int __user *) (ip + 2));
err |= get_user(mov2, (unsigned short __user *) (ip + 6));
err |= get_user(addr2, (unsigned long __user *) (ip + 8));
err |= get_user(jmp1, (unsigned short __user *) (ip + 16));
err |= get_user(jmp2, (unsigned char __user *) (ip + 18));

if (err)
break;
Expand All @@ -1361,12 +1376,12 @@ bool openpax_emulate_trampoline_64(struct pt_regs *regs)
unsigned char jmp2;
unsigned long addr1, addr2;

err = get_user(mov1, (unsigned short __user *) regs->ip);
err |= get_user(addr1, (unsigned long __user *) (regs->ip + 2));
err |= get_user(mov2, (unsigned short __user *) (regs->ip + 10));
err |= get_user(addr2, (unsigned long __user *) (regs->ip + 12));
err |= get_user(jmp1, (unsigned short __user *) (regs->ip + 20));
err |= get_user(jmp2, (unsigned char __user *) (regs->ip + 22));
err = get_user(mov1, (unsigned short __user *) ip);
err |= get_user(addr1, (unsigned long __user *) (ip + 2));
err |= get_user(mov2, (unsigned short __user *) (ip + 10));
err |= get_user(addr2, (unsigned long __user *) (ip + 12));
err |= get_user(jmp1, (unsigned short __user *) (ip + 20));
err |= get_user(jmp2, (unsigned char __user *) (ip + 22));

if (err)
break;
Expand Down