Theory ISK
subsection ‹ISK (Interruptible Separation Kernel)›
theory ISK
imports SK
begin
text ‹
At this point, the precondition linking action to state is generic and highly unconstrained.
We refine the previous locale by given generic functions ``precondition'' and ``realistic\_trace'' a definiton.
This yields a total run function, instead of the partial one of locale Separation\_Kernel.
This definition is based on a set of valid action sequences AS\_set.
Consider for example the following action sequence:
\[\gamma = [COPY\_INIT,COPY\_CHECK,COPY\_COPY]\]
If action sequence $\gamma$ is a member of AS\_set, this means that the attack surface contains an action COPY, which consists of three consecutive atomic kernel actions.
Interrupts can occur anywhere between these atomic actions.
Given a set of valid action sequences such as $\gamma$, generic function precondition can be defined.
It now consists of 1.) a generic invariant and 2.) more refined preconditions for the current action.
These preconditions need to be proven inductive only according to action sequences.
Assume, e.g., that $\gamma \in \mbox{AS\_set}$ and that $d$ is the currently active domain in state $s$.
The following constraints are assumed and must therefore be proven for the instantiation:
\begin{itemize}
\item ``AS\_precondition s d COPY\_INIT''\\ since COPY\_INIT is the start of an action sequence.
\item ``AS\_precondition (step s COPY\_INIT) d COPY\_CHECK''\\ since (COPY\_INIT, COPY\_CHECK) is a sub sequence.
\item ``AS\_precondition (step s COPY\_CHECK) d COPY\_COPY''\\ since (COPY\_CHECK, COPY\_COPY) is a sub sequence.
\end{itemize}
Additionally, the precondition for domain $d$ must be consistent when a context switch occurs, or when ever some other domain $d'$ performs an action.
Locale Interruptible\_Separation\_Kernel refines locale Separation\_Kernel in two ways.
First, there is a definition of realistic executions.
A realistic trace consists of action sequences from AS\_set.
Secondly, the generic @{term control} function has been refined by additional assumptions.
It is now assumed that control conforms to one of four possibilities:
\begin{enumerate}
\item The execution of the currently active domain is empty and the control function returns no action.
\item The currently active domain is executing the action sequence at the head of the execution. It returns the next kernel action of this sequence and updates the execution accordingly.
\item The action sequence is delayed.
\item The action sequence that is at the head of the execution is skipped and the execution is updated accordingly.
\end{enumerate}
As for the state update, this is still completely unconstrained and generic as long as it respects the generic invariant and the precondition.
›
locale Interruptible_Separation_Kernel = Separation_Kernel kstep output_f s0 current cswitch interrupt kprecondition realistic_execution control kinvolved ifp vpeq
for kstep :: "'state_t ⇒ 'action_t ⇒ 'state_t"
and output_f :: "'state_t ⇒ 'action_t ⇒ 'output_t"
and s0 :: 'state_t
and current :: "'state_t => 'dom_t"
and cswitch :: "time_t ⇒ 'state_t ⇒ 'state_t"
and interrupt :: "time_t ⇒ bool"
and kprecondition :: "'state_t ⇒ 'action_t ⇒ bool"
and realistic_execution :: "'action_t execution ⇒ bool"
and control :: "'state_t ⇒ 'dom_t ⇒ 'action_t execution ⇒ (('action_t option) × 'action_t execution × 'state_t)"
and kinvolved :: "'action_t ⇒ 'dom_t set"
and ifp :: "'dom_t ⇒ 'dom_t ⇒ bool"
and vpeq :: "'dom_t ⇒ 'state_t ⇒ 'state_t ⇒ bool"
+
fixes AS_set :: "('action_t list) set"
and invariant :: "'state_t ⇒ bool"
and AS_precondition :: "'state_t ⇒ 'dom_t ⇒ 'action_t ⇒ bool"
and aborting :: "'state_t ⇒ 'dom_t ⇒ 'action_t ⇒ bool"
and waiting :: "'state_t ⇒ 'dom_t ⇒ 'action_t ⇒ bool"
assumes empty_in_AS_set: "[] ∈ AS_set"
and invariant_s0: "invariant s0"
and invariant_after_cswitch: "∀ s n . invariant s ⟶ invariant (cswitch n s)"
and precondition_after_cswitch: "∀ s d n a. AS_precondition s d a ⟶ AS_precondition (cswitch n s) d a"
and AS_prec_first_action: "∀ s d aseq . invariant s ∧ aseq ∈ AS_set ∧ aseq ≠ [] ⟶ AS_precondition s d (hd aseq)"
and AS_prec_after_step: "∀ s a a' . (∃ aseq ∈ AS_set . is_sub_seq a a' aseq) ∧ invariant s ∧ AS_precondition s (current s) a ∧ ¬aborting s (current s) a ∧ ¬ waiting s (current s) a ⟶ AS_precondition (kstep s a) (current s) a'"
and AS_prec_dom_independent: "∀ s d a a' . current s ≠ d ∧ AS_precondition s d a ⟶ AS_precondition (kstep s a') d a"
and spec_of_invariant: "∀ s a . invariant s ⟶ invariant (kstep s a)"
and kprecondition_def: "kprecondition s a ≡ invariant s ∧ AS_precondition s (current s) a"
and realistic_execution_def: "realistic_execution aseq ≡ set aseq ⊆ AS_set"
and control_spec: "∀ s d aseqs . case control s d aseqs of (a,aseqs',s') ⇒
(thread_empty aseqs ∧ (a,aseqs') = (None,[])) ∨
(aseqs ≠ [] ∧ hd aseqs ≠ [] ∧ ¬aborting s' d (the a) ∧ ¬ waiting s' d (the a) ∧ (a,aseqs') = (Some (hd (hd aseqs)), (tl (hd aseqs))#(tl aseqs))) ∨
(aseqs ≠ [] ∧ hd aseqs ≠ [] ∧ waiting s' d (the a) ∧ (a,aseqs',s') = (Some (hd (hd aseqs)),aseqs,s)) ∨
(a,aseqs') = (None,tl aseqs)"
and next_action_after_cswitch: "∀ s n d aseqs . fst (control (cswitch n s) d aseqs) = fst (control s d aseqs)"
and next_action_after_next_state: "∀ s execs d . current s ≠ d ⟶ fst (control (next_state s execs) d (execs d)) = None ∨ fst (control (next_state s execs) d (execs d)) = fst (control s d (execs d))"
and next_action_after_step: "∀ s a d aseqs . current s ≠ d ⟶ fst (control (step s a) d aseqs) = fst (control s d aseqs)"
and next_state_precondition: "∀ s d a execs. AS_precondition s d a ⟶ AS_precondition (next_state s execs) d a"
and next_state_invariant: "∀ s execs . invariant s ⟶ invariant (next_state s execs)"
and spec_of_waiting: "∀ s a . waiting s (current s) a ⟶ kstep s a = s"
begin
text ‹
We can now formulate a total run function, since based on the new assumptions the case where the precondition does not hold, will never occur.
›
function run_total :: "time_t ⇒ 'state_t ⇒ ('dom_t ⇒ 'action_t execution) ⇒ 'state_t"
where "run_total 0 s execs = s"
| "interrupt (Suc n) ⟹ run_total (Suc n) s execs = run_total n (cswitch (Suc n) s) execs"
| "¬interrupt (Suc n) ⟹ thread_empty(execs (current s)) ⟹ run_total (Suc n) s execs = run_total n s execs"
| "¬interrupt (Suc n) ⟹ ¬thread_empty(execs (current s)) ⟹
run_total (Suc n) s execs = run_total n (step (next_state s execs) (next_action s execs)) (next_execs s execs)"
using not0_implies_Suc by (metis prod_cases3,auto)
termination by lexicographic_order
text ‹
The major part of the proofs in this locale consist of proving that function run\_total is equivalent to function run, i.e., that the precondition does always hold.
This assumes that the executions are \emph{realistic}.
This means that the execution of each domain contains action sequences that are from AS\_set.
This ensures, e.g, that a COPY\_CHECK is always preceded by a COPY\_INIT.
›
definition realistic_executions :: "('dom_t ⇒ 'action_t execution) ⇒ bool"
where "realistic_executions execs ≡ ∀ d . realistic_execution (execs d)"
text ‹
Lemma run\_total\_equals\_run is proven by doing induction.
It is however not inductive and can therefore not be proven directly: a realistic execution is not necessarily realistic after performing one action.
We generalize to do induction.
Predicate realistic\_executions\_ind is the inductive version of realistic\_executions. All action sequences in the tail of the executions must be complete action sequences (i.e., they must be from AS\_set).
The first action sequence, however, is being executed and is therefore not necessarily an action sequence from AS\_set, but it is \emph{the last part}
of some action sequence from AS\_set.
›
definition realistic_AS_partial :: "'action_t list ⇒ bool"
where "realistic_AS_partial aseq ≡ ∃ n aseq' . n ≤ length aseq' ∧ aseq' ∈ AS_set ∧ aseq = lastn n aseq'"
definition realistic_executions_ind :: "('dom_t ⇒ 'action_t execution) ⇒ bool"
where "realistic_executions_ind execs ≡ ∀ d . (case execs d of [] ⇒ True | (aseq#aseqs) ⇒ realistic_AS_partial aseq ∧ set aseqs ⊆ AS_set)"
text ‹
We need to know that invariably, the precondition holds.
As this precondition consists of 1.) a generic invariant and 2.) more refined preconditions for the current action, we have to know that these two are invariably true.
›
definition precondition_ind :: "'state_t ⇒ ('dom_t ⇒ 'action_t execution) ⇒ bool"
where "precondition_ind s execs ≡ invariant s ∧ (∀ d . fst(control s d (execs d)) ⇀ AS_precondition s d)"
text ‹
Proof that ``execution is realistic" is inductive, i.e.,
assuming the current execution is realistic, the execution returned by the control mechanism is realistic.
›
lemma next_execution_is_realistic_partial:
assumes na_def: "next_execs s execs d = aseq # aseqs"
and d_is_curr: "d = current s"
and realistic: "realistic_executions_ind execs"
and thread_not_empty: "¬thread_empty(execs (current s))"
shows "realistic_AS_partial aseq ∧ set aseqs ⊆ AS_set"
proof-
let ?c = "control s (current s) (execs (current s))"
{
assume c_empty: "let (a,aseqs',s') = ?c in
(a,aseqs') = (None,[])"
from na_def d_is_curr c_empty
have ?thesis
unfolding realistic_executions_ind_def next_execs_def by (auto)
}
moreover
{
let ?ct= "execs (current s)"
let ?execs' = "(tl (hd ?ct))#(tl ?ct)"
let ?a' = "Some (hd (hd ?ct))"
assume hd_thread_not_empty: "hd (execs (current s)) ≠ []"
assume c_executing: "let (a,aseqs',s') = ?c in
(a,aseqs') = (?a', ?execs')"
from na_def c_executing d_is_curr
have as_defs: "aseq = tl (hd ?ct) ∧ aseqs = tl ?ct"
unfolding next_execs_def by (auto)
from realistic[unfolded realistic_executions_ind_def,THEN spec,where x=d] d_is_curr
have subset: "set (tl ?execs') ⊆ AS_set"
unfolding Let_def realistic_AS_partial_def
by (cases "execs d",auto)
from d_is_curr thread_not_empty hd_thread_not_empty realistic[unfolded realistic_executions_ind_def,THEN spec,where x=d]
obtain n aseq' where n_aseq': "n ≤ length aseq' ∧ aseq' ∈ AS_set ∧ hd ?ct = lastn n aseq'"
unfolding realistic_AS_partial_def
by (cases "execs d",auto)
from this hd_thread_not_empty have "n > 0" unfolding lastn_def by(cases n,auto)
from this n_aseq' lastn_one_less[where n=n and x=aseq' and a="hd (hd ?ct)" and y="tl (hd ?ct)"] hd_thread_not_empty
have "n - 1 ≤ length aseq' ∧ aseq' ∈ AS_set ∧ tl (hd ?ct) = lastn (n - 1) aseq'"
by auto
from this as_defs subset have ?thesis
unfolding realistic_AS_partial_def
by auto
}
moreover
{
let ?ct= "execs (current s)"
let ?execs' = "?ct"
let ?a' = "Some (hd (hd ?ct))"
assume c_waiting: "let (a,aseqs',s') = ?c in
(a,aseqs') = (?a', ?execs')"
from na_def c_waiting d_is_curr
have as_defs: "aseq = hd ?execs' ∧ aseqs = tl ?execs'"
unfolding next_execs_def by (auto)
from realistic[unfolded realistic_executions_ind_def,THEN spec,where x=d] d_is_curr set_tl_is_subset[where x="?execs'"]
have subset: "set (tl ?execs') ⊆ AS_set"
unfolding Let_def realistic_AS_partial_def
by (cases "execs d",auto)
from na_def c_waiting d_is_curr
have "?execs' ≠ []" unfolding next_execs_def by auto
from realistic[unfolded realistic_executions_ind_def,THEN spec,where x=d] d_is_curr thread_not_empty
obtain n aseq' where witness: "n ≤ length aseq' ∧ aseq' ∈ AS_set ∧ hd(execs d) = lastn n aseq'"
unfolding realistic_AS_partial_def by (cases "execs d",auto)
from d_is_curr this subset as_defs have ?thesis
unfolding realistic_AS_partial_def
by auto
}
moreover
{
let ?ct= "execs (current s)"
let ?execs' = "tl ?ct"
let ?a' = "None"
assume c_aborting: "let (a,aseqs',s') = ?c in
(a,aseqs') = (?a', ?execs')"
from na_def c_aborting d_is_curr
have as_defs: "aseq = hd ?execs' ∧ aseqs = tl ?execs'"
unfolding next_execs_def by (auto)
from realistic[unfolded realistic_executions_ind_def,THEN spec,where x=d] d_is_curr set_tl_is_subset[where x="?execs'"]
have subset: "set (tl ?execs') ⊆ AS_set"
unfolding Let_def realistic_AS_partial_def
by (cases "execs d",auto)
from na_def c_aborting d_is_curr
have "?execs' ≠ []" unfolding next_execs_def by auto
from empty_in_AS_set this
realistic[unfolded realistic_executions_ind_def,THEN spec,where x=d] d_is_curr
have "length (hd ?execs') ≤ length (hd ?execs') ∧ (hd ?execs') ∈ AS_set ∧ hd ?execs' = lastn (length (hd ?execs')) (hd ?execs')"
unfolding lastn_def
by (cases "execs (current s)",auto)
from this subset as_defs have ?thesis
unfolding realistic_AS_partial_def
by auto
}
ultimately
show ?thesis
using control_spec[THEN spec,THEN spec,THEN spec,where x2=s and x1="current s" and x="execs (current s)"]
d_is_curr thread_not_empty
by (auto simp add: Let_def)
qed
text ‹
The lemma that proves that the total run function is equivalent to the partial run function, i.e., that in this refinement the case of the run function where the precondition is False will never occur.
›
lemma run_total_equals_run:
assumes realistic_exec: "realistic_executions execs"
and invariant: "invariant s"
shows "strict_equal (run n (Some s) execs) (run_total n s execs)"
proof-
{
fix n ms s execs
have "strict_equal ms s ∧ realistic_executions_ind execs ∧ precondition_ind s execs ⟶ strict_equal (run n ms execs) (run_total n s execs)"
proof (induct n ms execs arbitrary: s rule: run.induct)
case (1 s execs sa)
show ?case by auto
next
case (2 n execs s)
show ?case unfolding strict_equal_def by auto
next
case (3 n s execs sa)
assume interrupt: "interrupt (Suc n)"
assume IH: "(⋀sa. strict_equal (Some (cswitch (Suc n) s)) sa ∧ realistic_executions_ind execs ∧ precondition_ind sa execs ⟶
strict_equal (run n (Some (cswitch (Suc n) s)) execs) (run_total n sa execs))"
{
assume equal_s_sa: "strict_equal (Some s) sa"
assume realistic: "realistic_executions_ind execs"
assume inv_sa: "precondition_ind sa execs"
have inv_nsa: "precondition_ind (cswitch (Suc n) sa) execs"
proof-
{
fix d
have "fst (control (cswitch (Suc n) sa) d (execs d)) ⇀ AS_precondition (cswitch (Suc n) sa) d"
using next_action_after_cswitch inv_sa[unfolded precondition_ind_def,THEN conjunct2,THEN spec,where x=d]
precondition_after_cswitch
unfolding Let_def B_def precondition_ind_def
by(cases "fst (control (cswitch (Suc n) sa) d (execs d))",auto)
}
thus ?thesis using inv_sa invariant_after_cswitch unfolding precondition_ind_def by auto
qed
from equal_s_sa realistic inv_nsa inv_sa IH[where sa="cswitch (Suc n) sa"]
have equal_ns_nt: "strict_equal (run n (Some (cswitch (Suc n) s)) execs) (run_total n (cswitch (Suc n) sa) execs)"
unfolding strict_equal_def by(auto)
}
from this interrupt show ?case by auto
next
case (4 n execs s sa)
assume not_interrupt: "¬interrupt (Suc n)"
assume thread_empty: "thread_empty(execs (current s))"
assume IH: "(⋀sa. strict_equal (Some s) sa ∧ realistic_executions_ind execs ∧ precondition_ind sa execs ⟶ strict_equal (run n (Some s) execs) (run_total n sa execs))"
have current_s_sa: "strict_equal (Some s) sa ⟶ current s = current sa" unfolding strict_equal_def by auto
{
assume equal_s_sa: "strict_equal (Some s) sa"
assume realistic: "realistic_executions_ind execs"
assume inv_sa: "precondition_ind sa execs"
from equal_s_sa realistic inv_sa IH[where sa="sa"]
have equal_ns_nt: "strict_equal (run n (Some s) execs) (run_total n sa execs)"
unfolding strict_equal_def by(auto)
}
from this current_s_sa thread_empty not_interrupt show ?case by auto
next
case (5 n execs s sa)
assume not_interrupt: "¬interrupt (Suc n)"
assume thread_not_empty: "¬thread_empty(execs (current s))"
assume not_prec: "¬ precondition (next_state s execs) (next_action s execs)"
{
assume equal_s_sa: "strict_equal (Some s) sa"
assume realistic: "realistic_executions_ind execs"
assume inv_sa: "precondition_ind sa execs"
from equal_s_sa have s_sa: "s = sa" unfolding strict_equal_def by auto
from inv_sa have
"next_action sa execs ⇀ AS_precondition sa (current sa)"
unfolding precondition_ind_def B_def next_action_def
by (cases "next_action sa execs",auto)
from this next_state_precondition
have "next_action sa execs ⇀ AS_precondition (next_state sa execs) (current sa)"
unfolding precondition_ind_def B_def
by (cases "next_action sa execs",auto)
from inv_sa this s_sa next_state_invariant current_next_state
have prec_s: "precondition (next_state s execs) (next_action s execs)"
unfolding precondition_ind_def kprecondition_def precondition_def B_def
by (cases "next_action sa execs",auto)
from this not_prec have False by auto
}
thus ?case by auto
next
case (6 n execs s sa)
assume not_interrupt: "¬interrupt (Suc n)"
assume thread_not_empty: "¬thread_empty(execs (current s))"
assume prec: "precondition (next_state s execs) (next_action s execs)"
assume IH: "(⋀sa. strict_equal (Some (step (next_state s execs) (next_action s execs))) sa ∧
realistic_executions_ind (next_execs s execs) ∧ precondition_ind sa (next_execs s execs) ⟶
strict_equal (run n (Some (step (next_state s execs) (next_action s execs))) (next_execs s execs)) (run_total n sa (next_execs s execs)))"
have current_s_sa: "strict_equal (Some s) sa ⟶ current s = current sa" unfolding strict_equal_def by auto
{
assume equal_s_sa: "strict_equal (Some s) sa"
assume realistic: "realistic_executions_ind execs"
assume inv_sa: "precondition_ind sa execs"
from equal_s_sa have s_sa: "s = sa" unfolding strict_equal_def by auto
let ?a = "next_action s execs"
let ?ns = "step (next_state s execs) ?a"
let ?na = "next_execs s execs"
let ?c = "control s (current s) (execs (current s))"
have equal_ns_nsa: "strict_equal (Some ?ns) ?ns" unfolding strict_equal_def by auto
from inv_sa equal_s_sa have inv_s: "invariant s" unfolding strict_equal_def precondition_ind_def by auto
have realistic_na: "realistic_executions_ind ?na"
proof-
{
fix d
have "case ?na d of [] ⇒ True | aseq # aseqs ⇒ realistic_AS_partial aseq ∧ set aseqs ⊆ AS_set"
proof(cases "?na d",simp,rename_tac aseq aseqs,simp,cases "d = current s")
case False
fix aseq aseqs
assume "next_execs s execs d = aseq # aseqs"
from False this realistic[unfolded realistic_executions_ind_def,THEN spec,where x=d]
show "realistic_AS_partial aseq ∧ set aseqs ⊆ AS_set"
unfolding next_execs_def by simp
next
case True
fix aseq aseqs
assume na_def: "next_execs s execs d = aseq # aseqs"
from next_execution_is_realistic_partial na_def True realistic thread_not_empty
show "realistic_AS_partial aseq ∧ set aseqs ⊆ AS_set" by blast
qed
}
thus ?thesis unfolding realistic_executions_ind_def by auto
qed
have invariant_na: "precondition_ind ?ns ?na"
proof-
from spec_of_invariant inv_sa next_state_invariant s_sa have inv_ns: "invariant ?ns"
unfolding precondition_ind_def step_def
by (cases "next_action sa execs",auto)
have "∀d. fst (control ?ns d (?na d)) ⇀ AS_precondition ?ns d"
proof-
{
fix d
{
let ?a' = "fst (control ?ns d (?na d))"
assume snd_action_not_none: "?a' ≠ None"
have "AS_precondition ?ns d (the ?a')"
proof (cases "d = current s")
case True
{
have ?thesis
proof (cases "?a")
case (Some a)
show ?thesis
proof(cases "?na d = execs (current s)" rule :case_split[case_names waiting executing])
case executing
from executing True Some control_spec[THEN spec,THEN spec,THEN spec,where x2=s and x1=d and x="execs d"]
have a_def: "a = hd (hd (execs (current s))) ∧ ?na d = (tl (hd (execs (current s))))#(tl (execs (current s)))"
unfolding next_action_def next_execs_def Let_def
by(auto)
from a_def True snd_action_not_none control_spec[THEN spec,THEN spec,THEN spec,where x2="?ns" and x1=d and x="?na d"]
second_elt_is_hd_tl[where x=" hd (execs (current s))" and a="hd(tl(hd (execs (current s))))" and x'="tl (tl(hd (execs (current s))))"]
have na_def: "the ?a' = (hd (execs (current s)))!1"
unfolding next_execs_def
by(auto)
from Some realistic[unfolded realistic_executions_ind_def,THEN spec,where x=d] True thread_not_empty
obtain n aseq' where witness: "n ≤ length aseq' ∧ aseq' ∈ AS_set ∧ hd(execs d) = lastn n aseq'"
unfolding realistic_AS_partial_def by (cases "execs d",auto)
from True executing length_lt_2_implies_tl_empty[where x="hd (execs (current s))"]
Some control_spec[THEN spec,THEN spec,THEN spec,where x2=s and x1=d and x="execs d"]
snd_action_not_none control_spec[THEN spec,THEN spec,THEN spec,where x2="?ns" and x1=d and x="?na d"]
have in_action_sequence: "length (hd (execs (current s))) ≥ 2"
unfolding next_action_def next_execs_def
by auto
from this witness consecutive_is_sub_seq[where a=a and b="the ?a'" and n=n and y=aseq' and x="tl (tl (hd (execs (current s))))"]
a_def na_def True in_action_sequence
x_is_hd_snd_tl[where x="hd (execs (current s))"]
have 1: "∃ aseq' ∈ AS_set . is_sub_seq a (the ?a') aseq'"
by(auto)
from True Some inv_sa[unfolded precondition_ind_def,THEN conjunct2,THEN spec,where x="current s"] s_sa
have 2: "AS_precondition s (current s) a"
unfolding strict_equal_def next_action_def B_def by auto
from executing True Some control_spec[THEN spec,THEN spec,THEN spec,where x2=s and x1=d and x="execs d"]
have not_aborting: "¬aborting (next_state s execs) (current s) (the ?a)"
unfolding next_action_def next_state_def next_execs_def
by auto
from executing True Some control_spec[THEN spec,THEN spec,THEN spec,where x2=s and x1=d and x="execs d"]
have not_waiting: "¬waiting (next_state s execs) (current s) (the ?a)"
unfolding next_action_def next_state_def next_execs_def
by auto
from True this
1 2 inv_s
sub_seq_in_prefixes[where X=AS_set] Some next_state_invariant
current_next_state[THEN spec,THEN spec,where x1=s and x=execs]
AS_prec_after_step[THEN spec,THEN spec,THEN spec,where x2="next_state s execs" and x1="a" and x="the ?a'"]
next_state_precondition not_aborting not_waiting
show ?thesis
unfolding step_def
by auto
next
case waiting
from tl_hd_x_not_tl_x[where x="execs d"] True waiting control_spec[THEN spec,THEN spec,THEN spec,where x2=s and x1=d and x="execs d"] Some
have a_def: "?na d = execs (current s) ∧ next_state s execs = s ∧ waiting s d (the ?a)"
unfolding next_action_def next_execs_def next_state_def
by(auto)
from Some waiting a_def True snd_action_not_none control_spec[THEN spec,THEN spec,THEN spec,where x2="?ns" and x1=d and x="?na d"]
have na_def: "the ?a' = hd (hd (execs (current s)))"
unfolding next_action_def next_execs_def
by(auto)
from spec_of_waiting a_def True
have no_step: "step s ?a = s" unfolding step_def by (cases "next_action s execs",auto)
from no_step Some True a_def
inv_sa[unfolded precondition_ind_def,THEN conjunct2,THEN spec,where x="current s"] s_sa
have 2: "AS_precondition s (current s) (the ?a')"
unfolding next_action_def B_def
by(auto)
from a_def na_def this True Some no_step
show ?thesis
unfolding step_def
by(auto)
qed
next
case None
from None True snd_action_not_none control_spec[THEN spec,THEN spec,THEN spec,where x2="?ns" and x1=d and x="?na d"]
control_spec[THEN spec,THEN spec,THEN spec,where x2=s and x1=d and x="execs d"]
have na_def: "the ?a' = hd (hd (tl (execs (current s)))) ∧ ?na d = tl (execs (current s))"
unfolding next_action_def next_execs_def
by(auto)
from True None snd_action_not_none control_spec[THEN spec,THEN spec,THEN spec,where x2="?ns" and x1=d and x="?na d"]
this
have 1: "tl (execs (current s)) ≠ [] ∧ hd (tl (execs (current s))) ≠ []"
by auto
from this realistic[unfolded realistic_executions_ind_def,THEN spec,where x=d] True thread_not_empty
have "hd (tl (execs (current s))) ∈ AS_set"
by (cases "execs d",auto)
from True snd_action_not_none this
inv_ns this na_def 1
AS_prec_first_action[THEN spec,THEN spec,THEN spec,where x2="?ns" and x="hd (tl (execs (current s)))" and x1=d]
show ?thesis by auto
qed
}
thus ?thesis
using control_spec[THEN spec,THEN spec,THEN spec,where x2="?ns" and x1="current s" and x="?na (current s)"]
thread_not_empty True snd_action_not_none
by (auto simp add: Let_def)
next
case False
from False have equal_na_a: "?na d = execs d"
unfolding next_execs_def by auto
from this False current_next_state next_action_after_step
have "?a' = fst (control (next_state s execs) d (next_execs s execs d))"
unfolding next_action_def by auto
from inv_sa[unfolded precondition_ind_def,THEN conjunct2,THEN spec,where x=d] s_sa equal_na_a this
next_action_after_next_state[THEN spec,THEN spec,THEN spec,where x=d and x2=s and x1=execs]
snd_action_not_none False
have "AS_precondition s d (the ?a')"
unfolding precondition_ind_def next_action_def B_def by (cases "fst (control sa d (execs d))",auto)
from equal_na_a False this next_state_precondition current_next_state
AS_prec_dom_independent[THEN spec,THEN spec,THEN spec,THEN spec,where x3="next_state s execs" and x2=d and x="the ?a" and x1="the ?a'"]
show ?thesis
unfolding step_def
by (cases "next_action s execs",auto)
qed
}
hence "fst (control ?ns d (?na d)) ⇀ AS_precondition ?ns d" unfolding B_def
by (cases "fst (control ?ns d (?na d))",auto)
}
thus ?thesis by auto
qed
from this inv_ns show ?thesis
unfolding precondition_ind_def B_def Let_def
by (auto)
qed
from equal_ns_nsa realistic_na invariant_na s_sa IH[where sa="?ns"]
have equal_ns_nt: "strict_equal (run n (Some ?ns) ?na) (run_total n (step (next_state sa execs) (next_action sa execs)) (next_execs sa execs))"
by(auto)
}
from this current_s_sa thread_not_empty not_interrupt prec show ?case by auto
qed
}
hence thm_inductive: "∀ m s execs n . strict_equal m s ∧ realistic_executions_ind execs ∧ precondition_ind s execs ⟶ strict_equal (run n m execs) (run_total n s execs)" by blast
have 1: "strict_equal (Some s) s" unfolding strict_equal_def by simp
have 2: "realistic_executions_ind execs"
proof-
{
fix d
have "case execs d of [] ⇒ True | aseq # aseqs ⇒ realistic_AS_partial aseq ∧ set aseqs ⊆ AS_set"
proof(cases "execs d",simp)
case (Cons aseq aseqs)
from Cons realistic_exec[unfolded realistic_executions_def,THEN spec,where x=d]
have 0: "length aseq ≤ length aseq ∧ aseq ∈ AS_set ∧ aseq = lastn (length aseq) aseq"
unfolding lastn_def realistic_execution_def by auto
hence 1: "realistic_AS_partial aseq" unfolding realistic_AS_partial_def by auto
from Cons realistic_exec[unfolded realistic_executions_def,THEN spec,where x=d]
have 2: "set aseqs ⊆ AS_set"
unfolding realistic_execution_def by auto
from Cons 1 2 show ?thesis by auto
qed
}
thus ?thesis unfolding realistic_executions_ind_def by auto
qed
have 3: "precondition_ind s execs"
proof-
{
fix d
{
assume not_empty: "fst (control s d (execs d)) ≠ None"
from not_empty realistic_exec[unfolded realistic_executions_def,THEN spec,where x=d]
have current_aseq_is_realistic: "hd (execs d) ∈ AS_set"
using control_spec[THEN spec,THEN spec,THEN spec,where x="execs d" and x1=d and x2=s]
unfolding realistic_execution_def by(cases "execs d",auto)
from not_empty current_aseq_is_realistic invariant AS_prec_first_action[THEN spec,THEN spec,THEN spec, where x2=s and x1=d and x="hd (execs d)"]
have "AS_precondition s d (the (fst (control s d (execs d))))"
using control_spec[THEN spec,THEN spec,THEN spec,where x="execs d" and x1=d and x2=s]
by auto
}
hence "fst (control s d (execs d)) ⇀ AS_precondition s d"
unfolding B_def
by (cases " fst (control s d (execs d))",auto)
}
from this invariant show ?thesis unfolding precondition_ind_def by auto
qed
from thm_inductive 1 2 3 show ?thesis by auto
qed
text ‹
Theorem unwinding\_implies\_isecure gives security for all realistic executions.
For unrealistic executions, it holds vacuously and therefore does not tell us anything.
In order to prove security for this refinement (i.e., for function run\_total), we have to prove that purging yields realistic runs.
›
lemma realistic_purge:
shows "∀ execs d . realistic_executions execs ⟶ realistic_executions (purge execs d)"
proof-
{
fix execs d
assume "realistic_executions execs"
hence "realistic_executions (purge execs d)"
using someI[where P=realistic_execution and x="execs d"]
unfolding realistic_executions_def purge_def by(simp)
}
thus ?thesis by auto
qed
lemma remove_gateway_comm_subset:
shows "set (remove_gateway_communications d exec) ⊆ set exec ∪ {[]}"
by(induct exec,auto)
lemma realistic_ipurge_l:
shows "∀ execs d . realistic_executions execs ⟶ realistic_executions (ipurge_l execs d)"
proof-
{
fix execs d
assume 1: "realistic_executions execs"
from empty_in_AS_set remove_gateway_comm_subset[where d=d and exec="execs d"] 1 have "realistic_executions (ipurge_l execs d)"
unfolding realistic_execution_def realistic_executions_def ipurge_l_def by(auto)
}
thus ?thesis by auto
qed
lemma realistic_ipurge_r:
shows "∀ execs d . realistic_executions execs ⟶ realistic_executions (ipurge_r execs d)"
proof-
{
fix execs d
assume 1: "realistic_executions execs"
from empty_in_AS_set remove_gateway_comm_subset[where d=d and exec="execs d"] 1 have "realistic_executions (ipurge_r execs d)"
using someI[where P="λ x . realistic_execution x" and x="execs d"]
unfolding realistic_execution_def realistic_executions_def ipurge_r_def by(auto)
}
thus ?thesis by auto
qed
text ‹
We now have sufficient lemma's to prove security for run\_total.
The definition of security is similar to that in Section~\ref{sec:sep_kernel}.
It now assumes that the executions are realistic and concerns function run\_total instead of function run.
›
definition NI_unrelated_total::bool
where "NI_unrelated_total
≡ ∀ execs a n . realistic_executions execs ⟶
(let s_f = run_total n s0 execs in
output_f s_f a = output_f (run_total n s0 (purge execs (current s_f))) a
∧ current s_f = current (run_total n s0 (purge execs (current s_f))))"
definition NI_indirect_sources_total::bool
where "NI_indirect_sources_total
≡ ∀ execs a n. realistic_executions execs ⟶
(let s_f = run_total n s0 execs in
output_f (run_total n s0 (ipurge_l execs (current s_f))) a =
output_f (run_total n s0 (ipurge_r execs (current s_f))) a)"
definition isecure_total::bool
where "isecure_total ≡ NI_unrelated_total ∧ NI_indirect_sources_total"
theorem unwinding_implies_isecure_total:
shows isecure_total
proof-
from unwinding_implies_isecure have secure_partial: "NI_unrelated" unfolding isecure_def by blast
from unwinding_implies_isecure have isecure1_partial: "NI_indirect_sources" unfolding isecure_def by blast
have NI_unrelated_total: NI_unrelated_total
proof-
{
fix execs a n
assume realistic: "realistic_executions execs"
from invariant_s0 realistic run_total_equals_run[where n=n and s=s0 and execs=execs]
have 1: "strict_equal (run n (Some s0) execs) (run_total n s0 execs)" by auto
have "let s_f = run_total n s0 execs in output_f s_f a = output_f (run_total n s0 (purge execs (current s_f))) a ∧ current s_f = current (run_total n s0 (purge execs (current s_f)))"
proof (cases "run n (Some s0) execs")
case None
thus ?thesis using 1 unfolding NI_unrelated_total_def strict_equal_def by auto
next
case (Some s_f)
from realistic_purge invariant_s0 realistic run_total_equals_run[where n=n and s=s0 and execs="purge execs (current s_f)"]
have 2: "strict_equal (run n (Some s0) (purge execs (current s_f))) (run_total n s0 (purge execs (current s_f)))"
by auto
show ?thesis proof(cases "run n (Some s0) (purge execs (current s_f))")
case None
from 2 None show ?thesis using 2 unfolding NI_unrelated_total_def strict_equal_def by auto
next
case (Some s_f2)
from ‹run n (Some s0) execs = Some s_f› Some 1 2 secure_partial[unfolded NI_unrelated_def,THEN spec,THEN spec,THEN spec,where x=n and x2=execs]
show ?thesis
unfolding strict_equal_def NI_unrelated_def
by(simp add: Let_def B_def B2_def)
qed
qed
}
thus ?thesis unfolding NI_unrelated_total_def by auto
qed
have NI_indirect_sources_total: NI_indirect_sources_total
proof-
{
fix execs a n
assume realistic: "realistic_executions execs"
from invariant_s0 realistic run_total_equals_run[where n=n and s=s0 and execs=execs]
have 1: "strict_equal (run n (Some s0) execs) (run_total n s0 execs)" by auto
have "let s_f = run_total n s0 execs in output_f (run_total n s0 (ipurge_l execs (current s_f))) a = output_f (run_total n s0 (ipurge_r execs (current s_f))) a"
proof (cases "run n (Some s0) execs")
case None
thus ?thesis using 1 unfolding NI_unrelated_total_def strict_equal_def by auto
next
case (Some s_f)
from realistic_ipurge_l invariant_s0 realistic run_total_equals_run[where n=n and s=s0 and execs="ipurge_l execs (current s_f)"]
have 2: "strict_equal (run n (Some s0) (ipurge_l execs (current s_f))) (run_total n s0 (ipurge_l execs (current s_f)))"
by auto
from realistic_ipurge_r invariant_s0 realistic run_total_equals_run[where n=n and s=s0 and execs="ipurge_r execs (current s_f)"]
have 3: "strict_equal (run n (Some s0) (ipurge_r execs (current s_f))) (run_total n s0 (ipurge_r execs (current s_f)))"
by auto
show ?thesis proof(cases "run n (Some s0) (ipurge_l execs (current s_f))")
case None
from 2 None show ?thesis using 2 unfolding NI_unrelated_total_def strict_equal_def by auto
next
case (Some s_ipurge_l)
show ?thesis
proof(cases "run n (Some s0) (ipurge_r execs (current s_f))")
case None
from 3 None show ?thesis using 2 unfolding NI_unrelated_total_def strict_equal_def by auto
next
case (Some s_ipurge_r)
from ‹run n (Some s0) execs = Some s_f› ‹run n (Some s0) (ipurge_l execs (current s_f)) = Some s_ipurge_l›
Some 1 2 3 isecure1_partial[unfolded NI_indirect_sources_def,THEN spec,THEN spec,THEN spec,where x=n and x2=execs]
show ?thesis
unfolding strict_equal_def NI_unrelated_def
by(simp add: Let_def B_def B2_def)
qed
qed
qed
}
thus ?thesis unfolding NI_indirect_sources_total_def by auto
qed
from NI_unrelated_total NI_indirect_sources_total show ?thesis unfolding isecure_total_def by auto
qed
end
end