Basis Lab

Letting a Model Call Your Code Safely

Four Places the Boundary Can Go, and What Each One Stops

Last timeWhat Code Can Actually Do

Four boundaries in order of strength and cost, what each actually stops of the ten things a hostile submission tries, and the budget one run is allowed to spend.

The inventory says what has to be refused. The first decision is where the

thing doing the refusing sits, and there are only four places to put it.

They are usually presented as a shelf of products, which hides the only

question that matters about any of them. Each one is an answer to what the

submission still shares with the host after the wall is up, and the four

answers are the address space, the kernel, the hardware, and nothing at all.

Four places the wall can go

A restriction inside the runtime is the weakest. The submission runs in the

same process as the thing that interprets it, and that thing has been modified

to withhold some of what it offers: names removed, calls wrapped, a list of

permitted operations consulted before anything is done.

A separate process on the same machine is the first real wall. The submission

gets a process of its own, under an identity that owns nothing, with its own

view of the file system, limits the kernel applies whether the program agrees

or not, and no route out. This is what a container is, and it is worth naming

in terms of mechanism rather than product, because the mechanism is what the

argument turns on.

A separate kernel gives the submission a kernel of its own to ask, running on

hardware the host is dividing up. The requests it makes are answered by

something that belongs to it and that nobody else is relying on.

A separate machine shares nothing with the thing being protected except a

network, and the network is already cut.

FIG 1The four walls, by what each one leaves shared
Read the odd boxes going down and you have the four boundaries in order of strength. Read the even ones and you have what is left to go wrong at each step, which is the more useful reading: every boundary is exactly as strong as the thing it still shares is trustworthy.

A restriction inside the runtime stops almost nothing

This deserves to be said flatly, because it is the boundary most services

reach for first and it is the one that does not work.

The guard and the guarded run in the same process, under the same identity. The

kernel does not see a guard and a guest, it sees one process asking for things,

and it answers on the strength of that process's identity. So every request on

the inventory is still available to that identity, and the only thing standing

between the submission and the request is agreement from code sitting in the

same memory.

The restriction also works by closing a list, which is the wrong shape for the

problem. The author has to think of every route to each item on the inventory.

The attacker needs one route the author missed, and the set of routes grows

with every release of the runtime, because a new convenience is a new way to

reach the same kernel. The author's list is finished on the day it is written

and the runtime's is not.

And it fails silently. When a restriction of this kind is bypassed, nothing has

been refused anywhere, because no refusal ever reached the kernel. There is no

denied request in a log, no limit hit, no process killed. The operator's first

notice is the consequence rather than the attempt.

The honest score is zero. Not zero because nobody has made one work, but zero

against a submission that is trying, which is the only submission worth scoring

against. The clearest evidence is from the platform that invested most in this

idea: the Java security manager was the most serious in-runtime restriction

anybody built, and it was deprecated for removal, with its maintainers' own

account of why it had not served as a boundary for untrusted code.

This does not make such restrictions useless. They are useful as a guard rail

against honest accidents, and as a way to make a submission's intent visible

before it runs. They are not a wall, and the test is simple: if the thing doing

the enforcing can be reached by the thing being enforced, it is not a boundary.

The lesson stops here

6 more paragraphs to go

You have read the opening. The rest of the argument, the problems that check whether it landed, and the lines worth keeping at the end all come with a plan.

The first lesson of every course in the library reads the whole way through, free, so you can see exactly what the rest of them are.

See the planThe contents

This is the reading half

Starting the course gives you your own copy of it. Every idea on every page has problems standing under it, marked with a reason rather than a tick, and any sentence you do not believe can be opened and argued with. None of that can happen on a page nobody owns.

The contents

The rest of this course

  1. 01What a Submitted Program Can Actually Ask For
  2. 02Four Places the Boundary Can Go, and What Each One Stopsyou are here
  3. 03Run It as Nobody, Owning Nothingopening only
  4. 04Five Ceilings, and the Twenty Cores They Implyopening only
  5. 05Give It No Route Out, Then Name the Exceptionsopening only
  6. 06Nothing in the Environment Worth Stealingopening only
  7. 07The Narrow Door, and Nothing Elseopening only
  8. 08Ten Checks, and the One Wall That Can Still Fallopening only

Read alongside