Runtime monitor requirement:
Trace condition: only depends on historical trace (no future)
Prefix closure: once policy is violated, all future extensions are also violating (no recovery)
Finite refutability: if a full trace violates the policy, then there exists a finite bad prefix after which all extensions still violate.
Programmer can define a state automata and a guard could be implemented to check if program execution performs transitions that is not defined in the automata. If not defined, it is a violation of safety.
Security Automation:
Countable set O of automation states
Countable set O_0 \subseteq O of initial states
Countable set \Sigma of transition symbols
Transition relation \delta \subseteq O \times \wp(\Sigma) \times O
Given transition symbols \sigma = \sigma_0, \sigma_1, \ldots, the automata accepts \sigma if exists sequence of state o = o_0, o_1, ... such that for each pair (\alpha_i, \alpha_{i + 1}): (1) there is a corresponding (o_i, o_{i + 1}) \in o and (2) there exist (o_i, P, o_{i + 1}) \in \delta such that \sigma_i \in P.
Taint analysis only cares about assignment (not conditional branch), underapproximates information flow.
It is often impossibly to un-taint variables even variable has no leak information, because we can't calculate alternative trace that is not executed (and possibly non-terminating)
Security automation enforcement: Let O_c be current set of states that the security automation is in. When transition to new state \omega, the automation do: (1) for each state o \in O_c that we can transition from, \delta(o, P, o') for all w \models P is added to new automation states. (2) If automation cannot transition from any current states, then program is not allowed to enter w.
Issues:
Automata with infinite number of states are not enforceable.
Monitor must determine within n realtime seconds.
The program cannot alter monitor's state
In practice:
we rewrite the program to include additional state to represnet automation states.
Before instruction executes: we (1) decide which automaton transitions are enabled next and (2) update the stored automaton state accordingly. If no transition is enabled, we abort.
We can change instructions at compile time to add security layers.
But we wish program itself to not generate instruction on-the-fly (will make our job difficult). This limits the program to not contain on-the-fly compilation and optimization.
We can't predict indirect jump statically.
We need to balance between the size of instructions near execution we look at:
If size too small: might miss opportunity to optimize code
If size too large: we can't predict code execution; may do unnecessary instrumentations
Basic block: contiguous sequence of instructions that ends in a control flow transfer instruction (e.g. jmp ,ret, call)
Table of Content