Native Client

Note: These lecture notes were slightly modified from the ones posted on the 6.858 course website from 2014.

What's the goal of this paper?

Using Native Client:

Quick demo:

% urxvt -fn xft:Monospace-20
% export NACL_SDK_ROOT=/home/nickolai/tmp/nacl_sdk/pepper_35
% cd ~/6.858/git/fall14/web/lec/nacl-demo
## this is from NaCl's tutorial part1
% vi hello.cc
% vi index.html
% make
% make serve
## copy-paste and add --no-dir-check as the error message asks
## visit http://localhost:5103/
## change hello.cc to "memset(buf, 'A', 1024);"
% make
% !python
## visit http://localhost:5103/
## ctrl-shift-J, view console

What are some options for safely running x86 code?

Approach 0: trust the code developer.

Approach 1: hardware protection / OS sandboxing.

Approach 2: software fault isolation (Native Client's primary sandboxing plan).

What does safety mean for a Native Client module?

How to check if the module can execute a disallowed instruction?

Reliable disassembly

Computed jumps

Why are the rules from Table 1 in the paper necessary?

Homework question: what happens if verifier gets some instruction length wrong?

Answer: Depending on where you offset into a seamingly innocent x86 instruction stream, you can get unexpectedly useful instructions out (In the BROP paper, we got a "pop rsi; ret;" from offsetting at 0x7 into the BROP gadget).

If the checker incorrectly computes the length of an x86 instruction, then the attacker can exploit this. Suppose the checker computes bad_len(i) as the length of a certain instruction i at address a. The attacker, knowledgeable about x86, could write assembly code at address a + bad_len(i) that passes all the checks and seems harmless. This assembly code is what the NaCl checker would "see", given the instruction length bug. However, when the code is executed, the next instruction after instruction i would be at address a + real_len(i). And, the attacker carefully crafted his code such that the instructions at and after a + real_len(i) do something useful. Like jumping outside the sandbox, or a syscall.

How to prevent NaCl module from jumping to 32-byte multiple outside its code?

Segmentation

Limiting code/data to module's size:

What would be required to run Native Client on a system without segmentation?

Why doesn't Native Client support exceptions for modules?

What would happen if a NaCl module had a buffer overflow?

Limitations of the original NaCl design?

Invoking trusted code from sandbox

What's provided by the service runtime? (NaCl's "system call" equivalent)

How secure is Native Client?

How well does it perform?

How hard is it to port code to NaCl?

Additional references