diff --git a/.github/workflows/proof.yml b/.github/workflows/proof.yml index 0b87ad548..03af34d8a 100644 --- a/.github/workflows/proof.yml +++ b/.github/workflows/proof.yml @@ -51,7 +51,7 @@ jobs: with: L4V_ARCH: ${{ matrix.arch }} isa_branch: ts-2020 - session: ExecSpec ASpec AInvs + session: ExecSpec ASpec AInvs EVTutorial refine: name: Refine diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 9781ee7cd..2368fdb09 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -68,6 +68,7 @@ order). * Thomas Sewell, Data61, NICTA & UNSW * Michael Sproul, Data61 * Rupert Shuttleworth, NICTA +* Robert Sison, The University of Melbourne * Miki Tanaka, Data61, NICTA * Vernon Tang, NICTA * Sophie Taylor, Data61, NICTA diff --git a/ROOTS b/ROOTS index 1610af891..2a6be940a 100644 --- a/ROOTS +++ b/ROOTS @@ -8,4 +8,5 @@ camkes sys-init lib lib/Word_Lib -lib/sep_algebra \ No newline at end of file +lib/sep_algebra +lib/EVTutorial diff --git a/lib/EVTutorial/EquivValidTutorial.thy b/lib/EVTutorial/EquivValidTutorial.thy new file mode 100644 index 000000000..870e30fda --- /dev/null +++ b/lib/EVTutorial/EquivValidTutorial.thy @@ -0,0 +1,717 @@ +(* + * Copyright 2020, The University of Melbourne (ABN 84 002 705 224) + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Developers of future substantial additions to this tutorial may wish to + * append their names to the author list in its document root.tex file. + *) + +theory EquivValidTutorial +imports Lib.EquivValid +begin + +text \ +This tutorial provides a basic introduction to the seL4 verification repository's +EquivValid library, which formalises proof machinery first +introduced by the CPP'12 paper: + ``Noninterference for Operating System Kernels'' + by Murray, Matichuk, Brassil, Gammie, and Klein \cite{Murray_MBGK_12}. +This mostly comes in the form of worked examples. + +EquivValid statements are used to phrase seL4's information-flow security lemmas, +because they can be used to assert that a function preserves (or establishes) +``observable equivalence'' of system state, as seen by some attacker model. +The ``Valid'' part of EquivValid is based on the fact that the Isabelle definition +for Hoare triples in the seL4 proof base is called \valid\. The EquivValid statements +\equiv_valid\, \equiv_valid_2\ are therefore the ``equivalence'' versions of \valid\. +In \cite{Murray_MBGK_12}, +EquivValid statements are referred to as ``ev'' or ``ev2'' statements. +These roughly (but not exactly) correspond to \equiv_valid\ and \equiv_valid_2\ +(resp.) in the Isabelle theories. + +This tutorial will assume that the reader knows how to use the weakest precondition tool, +``wp'', to discharge Hoare triples. More information on this is available in the +Lib.WPTutorial theory in the seL4 verification repo. +\ + + +section \ Preliminaries \ + +text \ It will be best to think of an EquivValid statement as akin to a Hoare triple. +Recall that a Hoare triple consists of a precondition, function, and postcondition. +This following basic example of a Hoare triple asserts that, for any \<^emph>\single\ run +of the function \f\, assuming the precondition \P\ holds prior to that run, +the postcondition \Q\ will hold afterwards. \ + +term "\ P \ f \ Q \" +thm valid_def + +text \ Similarly to a Hoare triple, an EquivValid statement makes an assertion +about the possible executions (or ``runs'') of some function. +However, rather than making an assertion about single runs of the function, +it instead makes assertions about \<^emph>\relations between\ runs of that function. +In this sense, EquivValid statements could be thought of as \<^emph>\relational\ Hoare triples. \ + +text \ This tutorial will introduce some syntactic sugar to emphasise the similarity +between Hoare triples and EquivValid statements. +(Here, \\\\ is an alias provided by Lib.NonDetMonad for the trivial binary predicate, +which always returns \True\; similarly, there is also \\\\ for \False\.) \ + +abbreviation + equiv_valid_sugar :: + "('s \ 's \ bool) \ ('s \ bool) \ ('s,'b) nondet_monad \ ('s \ 's \ bool) \ bool" + ("\|_|, _\/ _ /\|_|\") +where + "\|A|, P\ f \|B|\ \ equiv_valid \\ A B P f" + +text \ This most basic form of an EquivValid statement asserts that, +for any \<^emph>\pair\ of runs of the function \f\, +assuming the \<^emph>\pre-equivalence\ \A\ relates the initial states of the two runs +(and the precondition \P\ holds initially for both runs), +the \<^emph>\post-equivalence\ \B\ will relate the final states of the two runs afterwards. \ + +term "\|A|, P\ f \|B|\" +term "equiv_valid \\ A B P f" + +text \ The following Isabelle theorem in the EquivValid library gives +a definition for \equiv_valid\ that is closest to that of ``ev'' as presented in +\cite{Murray_MBGK_12}; +this is what we will use to unfold \equiv_valid\ statements in this tutorial: \ + +thm equiv_valid_def2[simplified equiv_valid_2_def] + +text \ In the seL4 EquivValid library, the \equiv_valid\ definition also includes, +as a convenience, an \<^emph>\invariant equivalence\ \I\ that it asserts as both pre- and +post-equivalence. We will ignore this convenience for the rest of this tutorial. \ + +lemma "equiv_valid I \\ \\ P f = equiv_valid \\ I I P f" + unfolding equiv_valid_def2 equiv_valid_2_def + by simp + +text \ Furthermore, the library version of \equiv_valid\ is defined in terms of a +version \spec_equiv_valid\ that supports restricting the attention of the statement to +a particular initial state. We will avoid encountering \spec_equiv_valid\ for the rest +of this tutorial, by unfolding \equiv_valid_def2\ instead of \equiv_valid_def\. \ + +\ \Specialised\ +thm equiv_valid_def + equiv_valid_def[simplified spec_equiv_valid_def equiv_valid_2_def] + +text \ Finally, the library also contains both simplified and more general forms of +EquivValid statement; the more general forms allow proof engineers to specify the +equivalences and functions on which they are asserted in a more fine-grained fashion +than is allowed by \equiv_valid\. These will be addressed further later in this tutorial. \ + +\ \Simplified for A = B.\ +lemma "equiv_valid_inv I A P f" unfolding equiv_valid_def2 oops +\ \Generalised to allow specifying equivalence R on return values.\ +lemma "equiv_valid_rv_inv I A R P f" unfolding equiv_valid_2_def oops +\ \Generalised further.\ +lemma "equiv_valid_rv I A B R P f" unfolding equiv_valid_2_def oops +lemma "equiv_valid_2 I A B R P P' f f'" unfolding equiv_valid_2_def oops + + +section \ Example setting: a room with a view \ + +text \ EquivValid statements assert equivalences between system states in alternative runs +of a given program; for this tutorial we define a basic structure for the system state: \ + +record 'val Room = + desk :: 'val + window :: 'val + outbox :: 'val + inbox :: 'val + job :: "'val \ 'val" + +text \ The state equivalences of interest will then be of the kind +``\desk\ has the same value in both states'', and so forth. +We will typically use these to specify the attacker's assumed ability to make +observations of (or otherwise know) the contents of those parts of the state. \ + +definition desk_equivalence :: "'val Room \ 'val Room \ bool" +where + "desk_equivalence r1 r2 \ desk r1 = desk r2" + +definition window_equivalence :: "'val Room \ 'val Room \ bool" +where + "window_equivalence r1 r2 \ window r1 = window r2" + +text \ We could just as well define equivalences similarly for +\inbox\, \outbox\, or \job\ -- we omit these here. \ + +text \ Furthermore, you can use the \And\ alias provided by Lib.NonDetMonad +to write the conjunction of two binary predicates. +(Similarly, there is also an \Or\ alias for disjunction.)\ + +thm bipred_conj_def bipred_disj_def +lemma + "(desk_equivalence And window_equivalence) r1 r2 = + (desk r1 = desk r2 \ window r1 = window r2)" + unfolding bipred_conj_def desk_equivalence_def window_equivalence_def + by simp + +text \ In this setting, we might consider a trivial program that just returns +the contents of \desk\; note, there is no difference between these two ways +of expressing it: \ +lemma "gets desk = do document \ gets desk; return document od" + by simp + +text \ Or, we might consider some programs that transfer values from one part +of the state to another, write constants to state, execute functions +that can themselves be found in state, or some combination of these: \ + +definition reveal_desk_to_window :: "('val Room, unit) nondet_monad" +where + "reveal_desk_to_window \ modify (\s. s\window := desk s\)" + +definition sanitise_desk :: "('val::zero Room, unit) nondet_monad" +where + "sanitise_desk \ modify (\s. s\desk := 0\)" + +definition work_at_desk :: "('val Room, unit) nondet_monad" +where + "work_at_desk \ + do modify (\s. s\desk := inbox s\); + modify (\s. s\desk := (job s) (desk s)\); + modify (\s. s\outbox := desk s\) + od" + +definition work_sanitise_reveal :: "('val::zero Room, unit) nondet_monad" +where + "work_sanitise_reveal \ + do work_at_desk; + sanitise_desk; + reveal_desk_to_window + od" + + +section \ Attacker models expressible using EquivValid statements \ + +subsection \ An attacker with access to return values \ + +text \ The most basic form of \equiv_valid\ asserts an information-flow security property +that would be appropriate against an attacker that can see only the program's return value: +that any two runs of this program will give the same return value.\footnote{If you think +this doesn't sound like a very useful program, you'd be spot on: Our goal here is +to prove that the program would be stubbornly uninformative to such an attacker.} + +Of course, we will find that we can't expect to prove this unless we place some +restrictions on the runs under consideration. +Consider the case where we are maximally permissive with the pre- and post-equivalences +(by supplying \\\\) and precondition (by supplying \\\): \ + +lemma gets_desk_return_leak: + \ \ No restrictions on pre-equivalence, precondition, or post-equivalence. \ + "\|\\|, \\ gets desk \|\\|\" + find_theorems intro + \ \ There happens to be an applicable \gets\ rule for \equiv_valid_inv\. \ + thm gets_ev'' + apply(rule gets_ev'') + \ \ \equiv_valid\ requires the return value to be the same in both runs. + As expected, we are stuck, as we don't know that the contents of \desk\ + were initially the same for both runs. \ + nitpick + oops + +text \ How might we know that \gets desk\ will return the same value for each of +a given pair of runs? + +One way we might know this is if the pre-equivalence tells us that we can assume +that \desk\ initially has the same value in both runs. +This might be appropriate to assume, for example: +(1) after executing some function that equalises the value of \desk\ between + all runs under consideration, or +(2) when the attacker already knows the contents of \desk\. +Note that these are just two ways of saying that we consider it to be acceptable +for the attacker to know the initial contents of \desk\. + +We can specify this formally by setting \desk_equivalence\ as the pre-equivalence.% +\footnote{To avoid complicating things for now, we'll also set the post-equivalence +to be the same as the pre-equivalence. Examples of proving \equiv_valid\ statements +with a different pre- and post-equivalence will be addressed later in this tutorial.} +The resulting EquivValid statement's demand for equal return values is easily provable +for \gets desk\, using the \gets\ rule for \equiv_valid\ we found earlier: \ + +lemma gets_desk_equiv_return: + \ \ Pre-equivalence (and post-equivalence): + The value of \desk\ is equal initially (and finally) for both runs. \ + "\|desk_equivalence|, \\ + gets desk + \|desk_equivalence|\" + find_theorems intro + apply(rule gets_ev'') + unfolding desk_equivalence_def + by simp + +text \ Note that the \equiv_valid_rv\ form of EquivValid allows you to customise the +relationship demanded between return values to be something other than equality: \ +lemma "\|\\|, \\ f \|\\|\ = equiv_valid_rv \\ \\ \\ (=) \ f" + by (simp add:equiv_valid_def2) \ \ Try replacing the \(=)\ here. \ + + +subsection \ An attacker with a window into the system state \ + +text \ As a rule of thumb, we use an EquivValid statement's pre-equivalence to specify +the secrecy (or initial attacker knowledge) of values in system state, and use the +post-equivalence to specify the attacker's powers of observation. + +Suppose now a scenario where the desk in our room initially contains secrets, +and we wish to prevent these secrets from affecting what is observable to an attacker +with binoculars pointed at the window. In this case: +\begin{enumerate} +\item We \<^emph>\do not\ include \desk_equivalence\ in the pre-equivalence, as we + do not consider it acceptable for the attacker to know the initial contents of \desk\. + +\item Furthermore, we \<^emph>\do\ include \window_equivalence\ in the post-equivalence, as we + do consider that the attacker will be able to observe the final contents of \window\. +\end{enumerate} + +Clearly, in this situation, using \modify\ to transfer the contents of \desk\ +to \window\ would constitute an unacceptable information leak. +So we should be encouraged to see that the following \equiv_valid\ +statement is not provable: \ + +lemma reveal_desk_window_leak: + \ \ Pre-equivalence and post-equivalence: + The value of \window\ is equal initially and finally for both runs. \ + "\|window_equivalence|, \\ + reveal_desk_to_window + \|window_equivalence|\" + unfolding reveal_desk_to_window_def + \ \ We find an applicable \modify\ rule for \equiv_valid_inv\. \ + find_theorems intro + apply(rule modify_ev'') + \ \ Applying it, we see that it demands that \window_equivalence\ holds + between the final states of both runs. \ + unfolding window_equivalence_def + apply clarsimp + \ \ We should not expect to be able to prove this, because we have + said nothing about the initial value of desk in these runs. \ + oops (* Try: nitpick *) + +text \ As before, however, we should expect this to hold with a pre-equivalence +that includes \desk_equivalence\. \ + +lemma reveal_desk_equiv_window_equiv: + "\|desk_equivalence And window_equivalence|, \\ + reveal_desk_to_window + \|desk_equivalence And window_equivalence|\" + unfolding reveal_desk_to_window_def + apply(rule modify_ev'') + unfolding bipred_conj_def desk_equivalence_def window_equivalence_def + by clarsimp + + +section \ The typical toolkit \ + +subsection \ Using and customising the \wp\ tool's rule set \ + +text \ Recall the lemma we proved for \gets desk\: \ +thm gets_desk_equiv_return +text \ Instead of using any of the \gets\ rules for \equiv_valid\ directly, we can +also try using the \wp\ tool to see if it has any applicable rules in its rule set: \ +thm wp_ev + +text \Before applying \wp\ to EquivValid statements in this fashion, we may need +to use the rule \pre_ev\ to weaken their precondition. +This allows us to apply rules that are designed to be applied when the precondition +is a schematic variable, so as to infer a weakest precondition for the statement to hold. +It then leaves a goal for later to show that our original precondition implies +the weaker one that was inferred.\ +thm pre_ev +\ \ Note: \pre_ev\ is just the standard \hoare_pre\ + \equiv_valid_guard_imp\ \ +thm hoare_pre +thm equiv_valid_guard_imp + +text \ Applying the \wp\ tactic then works because the \gets_ev\ rule happens to be +in the \wp\ tool's rule set: \ +thm gets_ev + +lemma gets_desk_equiv_return_using_wp: + "\|desk_equivalence|, \\ + gets desk + \|desk_equivalence|\" + \ \ Use \pre_ev\ to weaken the precondition of the \equiv_valid\ statement + and make the \wp\ method applicable. \ + apply(rule pre_ev) + apply wp + unfolding desk_equivalence_def + by simp + +text \ You can freely customise the \wp\ rule set as needed, whether to +add new rules, or to replace rules with ones that are more applicable +in a given situation. + +For example, the \modify_ev\ rule is not part of the default \wp\ rule set: \ + +thm reveal_desk_equiv_window_equiv + modify_ev + +lemma reveal_desk_equiv_window_equiv_using_wp: + "\|desk_equivalence And window_equivalence|, \\ + reveal_desk_to_window + \|desk_equivalence And window_equivalence|\" + unfolding reveal_desk_to_window_def + apply(rule pre_ev) + apply(wp add:modify_ev) + unfolding bipred_conj_def desk_equivalence_def window_equivalence_def + by clarsimp + +text \ As another example: +It might be the \<^emph>\precondition\ for both runs that tells us that \desk\ has +a fixed initial constant value \c\ that is common to both runs. +(This might be the case if, even if we might normally use \desk\ for +secrets, we happen to have just executed a ``flush'' function that writes \c\ to +\desk\ before this point in the program, for all pairs of runs we care to compare.) + +Here we can modify the wp rule set to invoke \gets_ev''\ for \equiv_valid\, +which is better than the default \gets_ev\ rule for situations like this +where we actually need to use the precondition: \ +thm gets_ev'' + +lemma example_precond_desk_return: + \ \ Precondition: The value of desk is some fixed value \c\. + \equiv_valid\ then assumes that this precondition applies to both runs. \ + "\|\\|, (\s. desk s = c)\ + gets desk + \|\\|\" + apply(wp del:gets_ev add:gets_ev'') + by force + +text \ Relying on such a precondition, a similar argument is possible +when proving that \reveal_desk_to_window\ preserves \window_equivalence\: \ +thm modify_ev'' + +lemma reveal_const_desk_preserves_window_equiv: + \ \ Precondition: Desk initially has a fixed constant \c\. + \equiv_valid\ then assumes that this precondition applies to both runs. \ + "\|window_equivalence|, (\s. desk s = c)\ + reveal_desk_to_window + \|window_equivalence|\" + unfolding reveal_desk_to_window_def + apply(wp add:modify_ev'') + unfolding window_equivalence_def + by clarsimp + +text \ Finally, new EquivValid rules that we expect to be exercised +often can be added to the \wp\ rule set using a declaration: \ +declare modify_ev[wp] + + +subsection \ Remainder of worked example using \wp\ tool \ + +text \ Let's use all this to prove that our overarching program, +\work_sanitise_reveal\, is secure against the attacker at the window +with the binoculars (i.e. preserves \window_equivalence\). \ + +thm work_sanitise_reveal_def + +text \ First, we expect these two statements to be provable, because +\work_at_desk\ and \sanitise_desk\ have nothing to do with the window. \ + +lemma work_at_desk_preserves_window_equiv: + "\|window_equivalence|, P\ + work_at_desk + \|window_equivalence|\" + unfolding work_at_desk_def + apply wp \ \ Instead of \apply(wp add:modify_ev)\ \ + unfolding window_equivalence_def + by force + +lemma sanitise_desk_preserves_window_equiv: + "\|window_equivalence|, P\ + sanitise_desk + \|window_equivalence|\" + unfolding sanitise_desk_def + apply(rule pre_ev) + apply wp \ \ Instead of \apply(wp add:modify_ev)\ \ + unfolding window_equivalence_def + by force + +text \ The consequence of all this is that \work_at_desk\ might freely +shuttle secrets between \inbox\ and \outbox\ via \desk\, and execute +a secret \job\ on them, but it does not allow any of these secrets +to affect what is visible at \window\. + +The mere fact of \<^emph>\excluding\ any equivalences on \inbox\, \outbox\, or +\job\ from the pre- and post-equivalence of these statements +implies both: +\begin{enumerate} +\item We \<^emph>\do not\ consider it acceptable for the attacker to know the + initial values of \inbox\ and \outbox\ in these locations; + even the \job\ to be executed may differ between the runs. + All of these are therefore secrets to be protected by the property. + +\item We \<^emph>\do\ consider it acceptable for \inbox\, \outbox\, and \job\ + to contain secret values after the program has finished executing. +\end{enumerate} \ + +text \ We will, however, need that \sanitise_desk\ establishes the precondition +demanded by our recently proved lemma: that \desk\ contains a constant. \ +thm reveal_const_desk_preserves_window_equiv + +text \ Note that this is a regular (non-EquivValid) Hoare triple: \ +lemma sanitise_desk_sets_zero: + "\P\ sanitise_desk \\r s. desk s = 0\" + unfolding sanitise_desk_def + apply(rule pre_ev) + apply wp + by force + +text \ We can now use all these lemmas to have \wp\ discharge that +our overarching program \work_sanitise_reveal\ preserves \window_equivalence\. \ + +lemma work_sanitise_reveal_preserves_window_equiv: + "\|window_equivalence|, \\ + work_sanitise_reveal + \|window_equivalence|\" + unfolding work_sanitise_reveal_def + apply(wp add:reveal_const_desk_preserves_window_equiv[where c=0] + sanitise_desk_preserves_window_equiv + sanitise_desk_sets_zero + work_at_desk_preserves_window_equiv) + by force + + +section \ The advanced toolkit \ + +subsection \ More general forms of EquivValid statements \ + +text \ Lib.EquivValid provides rules for discharging \equiv_valid_inv\ statements for +the basic monad primitives \return\ and \bind\, and some of the more basic functions +like \gets\ (already seen); potentially in a number of variants. \ + +thm return_ev + bind_ev + gets_ev gets_ev' gets_ev'' + modify_ev modify_ev' modify_ev'' + +text \ On rare occasions you may find a need to use some of the more general +forms of EquivValid. These are all defined in terms of the most general form, +\equiv_valid_2\, which allows full customisation of +(1) return value equivalence \R\, +(2) differing pre-equivalence \A\ vs post-equivalence \B\, and even +(3) differing preconditions \P,P'\ and functions \f,f'\ for each run. +(In \cite{Murray_MBGK_12}, \equiv_valid_2\ is referred to as ``ev2''.) \ + +\ \Generalised to allow specifying equivalence R on return values.\ +lemma "equiv_valid_rv_inv I A R P f" unfolding equiv_valid_2_def oops +\ \Generalised further.\ +lemma "equiv_valid_rv I A B R P f" unfolding equiv_valid_2_def oops +lemma "equiv_valid_2 I A B R P P' f f'" unfolding equiv_valid_2_def oops + +text \ If you ever have a need to unfold an \equiv_valid\ statement to its +\equiv_valid_2\ form -- perhaps as part of a more involved manual proof -- +it is often better to unfold \equiv_valid_def2\ rather than \equiv_valid_def\. + +Lib.EquivValid also provides various rules for discharging \equiv_valid_2\ +statements for the basic monad primitives. For example: \ + +thm return_ev2 + equiv_valid_2_bind equiv_valid_2_bind_pre equiv_valid_2_bind_general + modify_ev2 + +lemma reveal_desk_equiv_window_equiv_using_ev2: + "\|desk_equivalence And window_equivalence|, \\ + reveal_desk_to_window + \|desk_equivalence And window_equivalence|\" + unfolding reveal_desk_to_window_def + apply(clarsimp simp:equiv_valid_def2) + \ \ After peeling back to \equiv_valid_2\ form, we can use its \modify\ rule. \ + find_theorems intro + apply(rule modify_ev2) + unfolding desk_equivalence_def window_equivalence_def + by simp + +text \ The basic \equiv_valid\ form and its rule set may sometimes +be too restrictive, due to their demand for return values to be equal. + +For example, if we ever needed to prove an \equiv_valid\ statement about +\do s \ get; return (f s) od\, we would need to unfold it to \equiv_valid_2\ form. +This is because \equiv_valid\ and its bind rule \bind_ev_pre\ will both demand +that the return value of \get\ (the entire state) be the same for both runs; +however, we might only need (or know) the parts of the state inspected +by the function \f\ to be the same. Say \f\ was \desk\: \ + +thm bind_ev_pre + equiv_valid_def2[simplified equiv_valid_2_def] + +lemma pitfall1_using_bind_ev: + "\|\\|, (\s. desk s = c)\ + do + s \ get; + return (desk s) + od + \|\\|\" + \ \ Using the bind rule for \equiv_valid\ splits the goal into + two \equiv_valid\ statements, one for each of \get\ and \return\. + It will ask us to prove them in reverse order. \ + apply(rule bind_ev_pre) + \ \ The \wp\ tool discharges the \return (desk s)\ part trivially: \ + apply wp + \ \ But the return value of \get\ is the entire state: \ + apply(clarsimp simp:equiv_valid_def2 equiv_valid_2_def) + apply(clarsimp simp add:get_def) + \ \ This causes us to get stuck, because we have no idea whether the state + is equivalent for parts of the room other than the desk. \ + oops + +text \ Therefore we need to use \equiv_valid_2\ and its bind rule \equiv_valid_2_bind_pre\; +these will allow us to specify the equivalence \R\ to be asserted between +the return values of the \get\. \ + +thm equiv_valid_2_bind_pre + equiv_valid_2_def + +text \ Another anti-pattern to avoid when applying the bind rules directly is leaving +intermediate preconditions unspecified; the automation is liable to guess \False\, +which will later be unprovable. + +Here, the \force\ tactic correctly infers that \desk_equivalence\ is the equivalence \R\ +that we need between the return values from \get\. +However, it guesses an incorrect postcondition: \ + +lemma pitfall2_using_bind_ev2: + "\|\\|, (\s. desk s = c)\ + do + s \ get; + return (desk s) + od + \|\\|\" + \ \ First we need to peel it back to \equiv_valid_2\ form, so we can apply its bind rule. \ + apply(clarsimp simp:equiv_valid_def2) + apply(rule equiv_valid_2_bind_pre) + \ \ Here \wp\ infers correctly that the equivalence between the + intermediate return values needs to be \\rv rv'. desk rv = desk rv'\, + i.e. that \desk\ has the same value in the state returned by \get\ in both runs. \ + apply(wp add:return_ev2) + apply(clarsimp simp:equiv_valid_def spec_equiv_valid_def equiv_valid_2_def) + \ \ The \force\ tactic just guesses \False\ for the postcondition for both steps. \ + apply(force simp add:get_def) + \ \ As these next two goals are Hoare triples, we use the \wp\ tool, as usual for + Hoare triples in the seL4 proof base. See Lib.WPTutorial for more information. \ + apply wp + apply wp + \ \ Now we are stuck because \force\ guessed \False\ as a premise + to discharge the goal earlier, giving us an unsatisfiable goal here. \ + oops + +text \ We can avoid this by giving \equiv_valid_2\'s bind rule a little more information. \ + +lemma precond_get_return_desk: + "\|\\|, (\s. desk s = c)\ + do + s \ get; + return (desk s) + od + \|\\|\" + apply(clarsimp simp:equiv_valid_def2) + \ \ We want to use the fact that \desk\ contains \c\ initially for both runs. + So we give it here. \ + apply(rule_tac P="(\s. desk s = c)" and P'="(\s. desk s = c)" in equiv_valid_2_bind_pre) + apply(wp add:return_ev2) + apply(clarsimp simp:equiv_valid_def2 equiv_valid_2_def) + \ \ No need to guess anything. \ + apply(force simp add:get_def) + \ \ Use \wp\ tactic to discharge the two Hoare triples; see Lib.WPTutorial for more info. \ + apply wp + apply wp + apply force + apply force + done + +subsection \ A note on what is currently available and why \ + +text \ As noted in \cite{Murray_MBGK_12}, the machinery developed of this kind +(available in Lib.EquivValid's default \wp\ rule set) is mostly geared +towards \equiv_valid_inv\; this is an abbrevation for the simplified case of +\equiv_valid\ where the post-equivalence is the same as the pre-equivalence: \ + +lemma "equiv_valid_inv I A P f" unfolding equiv_valid_def2 equiv_valid_2_def oops + +text \ The reason for this is that the seL4 infoflow proofs take the approach of defining an +\emph{unwinding} relation \cite{Goguen_Meseguer_84}: an equivalence relation +flexible enough to describe what we think ought to continue to look the same between +all possible pairs of executions as seen by a given attacker model.% +\footnote{If every pair of executions being compared is like a wound-up rope ladder thrown +over the side of a ship, then the rungs of those ladders would be the unwinding relation.} + +However, the EquivValid library merely provides a way to reason about equivalences, +so it is not prescriptive about taking this approach. + +Furthermore, the overall unwinding relation for a system may be composed from a number of +equivalences, which may each hold or not at different times, in a manner that depends on +where we are in the system.% +\footnote{This is like saying that the first six rungs of the ladder may be made of wood, +but the next seven rungs may be made of aluminium, and so on.} +As it happens, this is the case for seL4's unwinding relation, but the number of ev sub-lemmas +needing to be proved for differing pre-/post-equivalences is rather limited at current time of +writing, hence the lack of machinery.% +\footnote{This may perhaps be the lemma covering the step between the sixth and seventh +rung of our imaginary wood-and-aluminium--runged ladder.} \ + + +subsection \ Proving EquivValid with differing pre- and post-equivalences \ + +text \ So far we have only proved \equiv_valid\ statements +whose pre-equivalence is the same as their post-equivalence. + +We will now attempt to prove an \equiv_valid\ statement where they differ. + +This allows us to say, for example, that although usually we use the desk +for secrets: +(1) at this point in the program we happened to make sure that + desk contains the same value for any two runs we care to check, and +(2) we don't care if desk contains the same value for both runs afterwards. \ + +lemma reveal_desk_equiv_to_window_equiv: + "\|desk_equivalence|, \\ \ \ Pre-equivalence: The value of \desk\ is + the same initially in both runs. \ + reveal_desk_to_window + \|window_equivalence|\" \ \ Post-equivalence: The value of \window\ is required to be + the same at the end of both runs; no longer so for \desk\. \ + unfolding reveal_desk_to_window_def + apply(rule modify_ev'') + unfolding window_equivalence_def desk_equivalence_def + by simp + +text \ This is handy, because we might subsequently copy secrets into the desk, +in which case \desk_equivalence\ would no longer hold in the post-equivalence. + +As before, the mere fact of \<^emph>\excluding\ any equivalence on \inbox\ from the +pre-equivalence implies we \<^emph>\do not\ consider it acceptable for the attacker +to know \inbox\'s initial value; it is therefore a secret to be protected by this property. +Conversely, the absence of \desk_equivalence\ from the post-equivalence implies +that we \<^emph>\do\ consider it acceptable for the desk to contain secrets after the program +has finished executing. + +Consequently, this \equiv_valid\ statement is provable: \ + +lemma desk_equiv_no_longer_needed: + "\|desk_equivalence|, \\ + do reveal_desk_to_window; + modify (\r. r\desk := inbox r\) + od + \|window_equivalence|\" + \ \ Use \pre_ev\ to weaken the precondition of the \equiv_valid\ statement. \ + apply(rule pre_ev) + \ \ Use \bind_ev_general\ to split the goal into \equiv_valid\ statements for + each of the two \modify\ commands. It will ask us to prove them in reverse order. \ + apply(rule bind_ev_general) + \ \ Prove \equiv_valid\ for \desk := inbox\ manually. \ + apply clarsimp + apply(rule modify_ev'') + \ \ The \force\ tactic has enough information here to figure out that + the intermediate equivalence \B\ needs to be \window_equivalence\. \ + apply(force simp:window_equivalence_def desk_equivalence_def) + \ \ This happens to be the post-equivalence for the \equiv_valid\ lemma + we just proved for \window := desk\, so we can reuse that lemma here. \ + using reveal_desk_equiv_to_window_equiv + unfolding window_equivalence_def + apply force + apply wp + apply force + done + +end diff --git a/lib/EVTutorial/ROOT b/lib/EVTutorial/ROOT new file mode 100644 index 000000000..e3fdbe838 --- /dev/null +++ b/lib/EVTutorial/ROOT @@ -0,0 +1,15 @@ +(* + * Copyright 2020, The University of Melbourne (ABN 84 002 705 224) + * + * SPDX-License-Identifier: BSD-2-Clause + *) + +chapter Lib + +session EVTutorial = Lib + + options [document = pdf] + theories + EquivValidTutorial + document_files + "root.bib" + "root.tex" diff --git a/lib/EVTutorial/document/root.bib b/lib/EVTutorial/document/root.bib new file mode 100644 index 000000000..2969ae754 --- /dev/null +++ b/lib/EVTutorial/document/root.bib @@ -0,0 +1,30 @@ +# Copyright 2020, The University of Melbourne (ABN 84 002 705 224) +# +# SPDX-License-Identifier: CC-BY-SA-4.0 +# + +@inproceedings{Murray_MBGK_12, + author = {Murray, Toby and Matichuk, Daniel and Brassil, Matthew and Gammie, Peter and Klein, Gerwin}, + editor = {{Chris Hawblitzel and Dale Miller}}, + month = dec, + year = {2012}, + keywords = {information flow, refinement, scheduling, state monads}, + address = {Kyoto, Japan}, + title = {Noninterference for Operating System Kernels}, + pages = {126--142}, + booktitle = {International Conference on Certified Programs and Proofs}, + paperurl = {https://ts.data61.csiro.au/publications/nicta_full_text/6004.pdf}, + publisher = {Springer}, + isbn = {978-3-642-35307-9} + } + +@INPROCEEDINGS{Goguen_Meseguer_84, + author={J. A. {Goguen} and J. {Meseguer}}, + booktitle={1984 IEEE Symposium on Security and Privacy}, + title={Unwinding and Inference Control}, + year={1984}, + volume={}, + number={}, + pages={75--87}, + publisher = {{IEEE} Computer Society}, +} diff --git a/lib/EVTutorial/document/root.tex b/lib/EVTutorial/document/root.tex new file mode 100644 index 000000000..534fd2ee9 --- /dev/null +++ b/lib/EVTutorial/document/root.tex @@ -0,0 +1,49 @@ +% +% Copyright 2020, The University of Melbourne (ABN 84 002 705 224) +% +% SPDX-License-Identifier: CC-BY-SA-4.0 +% + +\documentclass[11pt,a4paper]{article} +\usepackage{isabelle,isabellesym} + +% Ensure words with ligatures like 'fi' are searchable in pdf +% https://tex.stackexchange.com/a/57867 +\input{glyphtounicode} +\pdfgentounicode=1 + +% this should be the last package used +\usepackage{pdfsetup} + +% urls in roman style, theory text in math-similar italics +\urlstyle{rm} +\isabellestyle{it} + + +\begin{document} + +\title{EquivValid Tutorial\thanks{\copyright~The University of Melbourne (ABN 84 002 705 224); licensed under Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)}} +% Remove footnote mark for copyright notice. +% https://tex.stackexchange.com/a/14866 +\renewcommand\footnotemark{} +\author{Robert Sison} +\maketitle + +\tableofcontents + +% sane default for proof documents +\parindent 0pt\parskip 0.5ex + +% generated text of all theories +\input{session} + +% optional bibliography +\bibliographystyle{alpha} +\bibliography{root} + +\end{document} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: t +%%% End: diff --git a/lib/EquivValid.thy b/lib/EquivValid.thy index 939baeb69..27bb032b6 100644 --- a/lib/EquivValid.thy +++ b/lib/EquivValid.thy @@ -267,6 +267,30 @@ lemma modify_ev2: apply(clarsimp simp: equiv_valid_2_def in_monad) using assms by auto +lemma modify_ev: + "equiv_valid I A B + (\ s. \ s t. I s t \ A s t \ I (f s) (f t) \ B (f s) (f t)) + (modify f)" + apply(clarsimp simp:equiv_valid_def2) + apply(rule modify_ev2) + by auto + +lemma modify_ev': + "equiv_valid I A B + (\ s. \ t. I s t \ A s t \ I (f s) (f t) \ B (f s) (f t)) + (modify f)" + apply(clarsimp simp:equiv_valid_def2) + apply(rule modify_ev2) + by auto + +lemma modify_ev'': + assumes "\ s t. \I s t; A s t; P s; P t\ \ I (f s) (f t) \ B (f s) (f t)" + shows "equiv_valid I A B P (modify f)" + apply(clarsimp simp:equiv_valid_def2) + apply(rule modify_ev2) + using assms by auto + + lemma put_ev2: assumes "\ s t. \I s t; A s t; P s; P' t\ \ R () () \ I x x' \ B x x'" shows diff --git a/lib/tests.xml b/lib/tests.xml index 6c9612b24..4e2715818 100644 --- a/lib/tests.xml +++ b/lib/tests.xml @@ -20,6 +20,7 @@ ../isabelle/bin/isabelle build -v -d .. Concurrency ../isabelle/bin/isabelle build -v -d .. CLib ../isabelle/bin/isabelle build -v -d .. LibTest + ../isabelle/bin/isabelle build -v -d .. EVTutorial