The Big Picture

Native Code + Web = Scary?

The OS is the Problem

HFILE file = OpenFile("tax_return.xls", &of, OF_READ);

Native Code + Web Security

url_loader_interface->Open(url_loader, request_info, callback_on_open);

Using Native Client

Process Model

Disassembling Native Code

You can't validate what you can't see.

Interesting Instructions

syscall  # 0f 05

Rejected: Swiss army knife of pwnage.

lock cmpxchg8b %eax  # f0 0f c7 c8

Rejected: can hang your computer.

pmulld %xmm1, %xmm0  # 66 0f 38 40 c1

Overwritten with halt (f4) instructions if not supported by CPU.

Direct Jumps

mov $0x02eb050f, %eax  # b8 0f 05 eb 02
jmp  . - 4  # eb fa - Rejected by NaCl's validator!

Indirect Jumps

f = get_function_pointer();
call get_function_pointer  # e8 [4 byte offset]
call *%rax  # ff d0 - Jumps anywhere
call get_function_pointer
and  $0xffffffffffffffe0, %rax  # Drop 5 lowest bits.
call *%rax  # Jumps to 1/32nd of anywhere?

Aligning Instruction Bundles

Aligning Instruction Bundles

Self-modifying Code?

/* Do not give permission to modify code. */
mprotect(&code, code_size, PROT_READ | PROT_EXEC);
/* Do not give permission to execute data. */
mprotect(&data, data_size, PROT_READ | PROT_WRITE);

Wait - what about dynamic libraries and JIT?

Wait - mprotect is now security critical?

Call a Function and Return

It's simple, right?

Returning from a function

retq  # c3 - Jump to whatever address is on top of stack.
pop %rcx  # 59
and  $0xffffffffffffffe0, %rcx  # 48 83 e1 e0 - Align to bundle
push %rcx  # 51
retq  # What if another thread writes to the stack first?
pop %rcx
and  $0xffffffffffffffe0, %rcx
jmp *%rcx  # ff e1

Wait - return is dangerous?


    jmp dangerous  # Rejected by NaCl's validator
    and  $0xffffffffffffffe0, %rcx
    jmp *%rcx

Must treat NaCl instruction sequences as a single instruction.

(For both direct jumps and instruction bundling.)

Calling a Function

actual_return: # Dropping lower 5 bits changes return address ... and $0xffffffffffffffe0, %rcx call *%rcx # ff d1 expected_return: # Not bundle aligned ...
    and  $0xffffffffffffffe0, %rcx
    call  *%rcx

actual_return: # Bundle aligned ...

Playing Well With Others

You are not Alone...

The Story, Thus Far

+System Stuff

+Chrome Code

+Bookkeeping Info

Confine It!

External Jumps

Jump Confinement

void foo() {}


and  $0xffffffffffffffe0, %rcx
jmp *%rcx


and $0xffffffe0, %ecx  # 83 e1 e0 - Truncate to 32 bits + bundle align
add %r15, %rcx  # 4c 01 f9 - Offset the address by r15
jmp *%rcx  # ff e1 - Jump to the computed address
2 bytes vs. 8 bytes

External Data Access

Data Access Confinement

void put_word(int *x) {
    *x = 0x100;


movl $0x100, (%rax)  # c7 00 00 01 00 00


mov %eax, %eax  # 89 c0 - Truncate to 32 bits
movl $0x100, (%r15, %rax, 1)  # 41 c7 04 07 00 01 00 - *(r15 + rax * 1) = 0x100
6 bytes vs. 9 bytes

+ Guard Regions


Syscall Trampoline

# Absolute address simplifies fixup.
mov syscall_address, %rax  # 48 b8 [8 byte constant]
# Address pushed on stack identifies requested syscall.
# Would not validate without a mask.
call *%rax  # ff d0
# Paranoia, should never return here.
hlt  # f4
13 Bytes

Talking to Chrome

url_loader_interface->Open(url_loader, request_info, callback_on_open);

Wrapping Up

Did everyone survive that?

The Rabbit Hole Continues...

  • Dynamic code loading + JIT
  • PNaCl
  • Sandbox all the things!

Recommended Reading

Thank You!