(* * 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 Monads.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 @{theory Monads.Fun_Pred_Syntax} to write the conjunction of two binary predicates. (Similarly, there is also an \or\ alias for disjunction.)\ lemma "(desk_equivalence and window_equivalence) r1 r2 = (desk r1 = desk r2 \ window r1 = window r2)" unfolding 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 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 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