(* * Copyright 2014, NICTA * * This software may be distributed and modified according to the terms of * the GNU General Public License version 2. Note that NO WARRANTY is provided. * See "LICENSE_GPLv2.txt" for details. * * @TAG(NICTA_GPL) *) theory Access imports Deterministic_AC begin context begin interpretation Arch . (*FIXME: arch_split*) text{* The goal is to place limits on what untrusted agents can do while the trusted agents are not running. This supports a framing constraint in the descriptions (Hoare triples) of syscalls. Roughly the existing proofs show the effect of the syscall, and this proof summarises what doesn't (or isn't allowed to) change. The basic intuition is to map all object references to the agent they belong to and show that changes to the object reference graph are allowed by the policy specified by the user. The policy is a labelled graph amongst agents independent of the current state, i.e. a static external summary of what should be talking to what and how. The interesting cases occur between trusted and untrusted components: e.g. we assume that it is unsafe for untrusted components (UT) to send capabilities to trusted components (T), and so T must ensure that all endpoints it shares with UT that it receives on do not have the grant bit set. *} type_synonym 'a agent_map = "obj_ref \ 'a" type_synonym 'a agent_asid_map = "asid \ 'a" type_synonym 'a agent_irq_map = "10 word \ 'a" type_synonym 'a agent_domain_map = "domain \ 'a set" text{* What one agent can do to another. We allow multiple edges between agents in the graph. Control is special. It implies the ability to do pretty much anything, including get access the other rights, create, remove, etc. *} datatype auth = Control | Receive | SyncSend | Notify | Reset | Grant | Write | Read | ASIDPoolMapsASID text{* The interesting case is for endpoints. Consider an EP between T and UT (across a trust boundary). We want to be able to say that all EPs and tcbs that T does not expose to UT do not change when it is not running. If UT had a direct Send right to T then integrity (see below) could not guarantee this, as it doesn't know which EP can be changed by UT. Thus we set things up like this (all distinct labels): T -Receive-> EP <-Send- UT Now UT can interfere with EP and all of T's tcbs blocked for receive on EP, but not endpoints internal to T, or tcbs blocked on other (suitably labelled) EPs, etc. *} type_synonym 'a auth_graph = "('a \ auth \ 'a) set" text {* Each global namespace will need a labeling function. We map each scheduling domain to a single label; concretely, each tcb in a scheduling domain has to have the same label. We will want to weaken this in the future. The booleans @{text pasMayActivate} and @{text pasMayEditReadyQueues} are used to weaken the integrity property. When @{const True}, @{text pasMayActivate} causes the integrity property to permit activation of newly-scheduled threads. Likewise, @{text pasMayEditReadyQueues} has the integrity property permit the removal of threads from ready queues, as occurs when scheduling a new domain for instance. By setting each of these @{const False} we get a more constrained integrity property that is useful for establishing some of the proof obligations for the infoflow proofs, particularly those over @{const handle_event} that neither activates new threads nor schedules new domains. The @{text pasDomainAbs} relation describes which labels may run in a given scheduler domain. This relation is not relevant to integrity but will be used in the information flow theory (with additional constraints on its structure). *} end record 'a PAS = pasObjectAbs :: "'a agent_map" pasASIDAbs :: "'a agent_asid_map" pasIRQAbs :: "'a agent_irq_map" pasPolicy :: "'a auth_graph" pasSubject :: "'a" \ \The active label\ pasMayActivate :: "bool" pasMayEditReadyQueues :: "bool" pasMaySendIrqs :: "bool" pasDomainAbs :: "'a agent_domain_map" context begin interpretation Arch . (*FIXME: arch_split*) text{* Wellformedness of the agent authority function with respect to a label (the current thread): \begin{itemize} \item for (the current untrusted) @{term "agent"}, large enough authority must be contained within the agent's boundaries. \item @{term "agent"} has all the self authority it could want. \item If an agent can grant caps through an endpoint, then it is authority-equivalent to all agents that can receive on that endpoint. \item Anyone can send on any IRQ notification. \end{itemize} *} definition policy_wellformed where "policy_wellformed aag maySendIrqs irqs agent \ (\agent'. (agent, Control, agent') \ aag \ agent = agent') \ (\a. (agent, a, agent) \ aag) \ (\s r ep. (s, Grant, ep) \ aag \ (r, Receive, ep) \ aag \ (s, Control, r) \ aag \ (r, Control, s) \ aag) \ (maySendIrqs \ (\irq ntfn. irq \ irqs \ (irq, Notify, ntfn) \ aag \ (agent, Notify, ntfn) \ aag))" abbreviation "pas_wellformed aag \ policy_wellformed (pasPolicy aag) (pasMaySendIrqs aag) (range (pasIRQAbs aag)) (pasSubject aag)" lemma aag_wellformed_Control: "\ (x, Control, y) \ aag; policy_wellformed aag mirqs irqs x \ \ x = y" unfolding policy_wellformed_def by metis lemma aag_wellformed_refl: "\ policy_wellformed aag mirqs irqs x \ \ (x, a, x) \ aag" unfolding policy_wellformed_def by blast lemma aag_wellformed_grant_Control_to_recv: "\ (s, Grant, ep) \ aag; (r, Receive, ep) \ aag; policy_wellformed aag mirqs irqs l\ \ (s, Control, r) \ aag" unfolding policy_wellformed_def by blast lemma aag_wellformed_grant_Control_to_send: "\ (s, Grant, ep) \ aag; (r, Receive, ep) \ aag; policy_wellformed aag mirqs irqs l\ \ (r, Control, s) \ aag" unfolding policy_wellformed_def by blast text{* Abstract a graph by relabelling the nodes (agents). Clearly this can collapse (and not create) distinctions. *} definition auth_graph_map :: "('a \ 'b) \ 'a auth_graph \ 'b auth_graph" where "auth_graph_map f aag \ {(f x, auth, f y) | x auth y. (x, auth, y) \ aag}" lemma auth_graph_map_mem: "(x, auth, y) \ auth_graph_map f S = (\x' y'. x = f x' \ y = f y' \ (x', auth, y') \ S)" by (simp add: auth_graph_map_def) lemmas auth_graph_map_memD = auth_graph_map_mem[THEN iffD1] lemma auth_graph_map_memI: "\ (x', auth, y') \ S; x = f x'; y = f y' \ \ (x, auth, y) \ auth_graph_map f S" by (fastforce simp add: auth_graph_map_mem) lemma auth_graph_map_mono: "S \ S' \ auth_graph_map G S \ auth_graph_map G S'" unfolding auth_graph_map_def by auto text{* Very often we want to say that the agent currently running owns a given pointer. *} abbreviation is_subject :: "'a PAS \ word32 \ bool" where "is_subject aag ptr \ pasObjectAbs aag ptr = pasSubject aag" text{* Also we often want to say the current agent can do something to a pointer that he doesn't own but has some authority to. *} abbreviation(input) aag_has_auth_to :: "'a PAS \ auth \ word32 \ bool" where "aag_has_auth_to aag auth ptr \ (pasSubject aag, auth, pasObjectAbs aag ptr) \ pasPolicy aag" text{* Abstract the state to an agent authority graph. This definition states what authority is conferred by a particular capability to the obj_refs in it. *} definition cap_rights_to_auth :: "cap_rights \ bool \ auth set" where "cap_rights_to_auth r sync \ {Reset} \ (if AllowRead \ r then {Receive} else {}) \ (if AllowWrite \ r then (if sync then {SyncSend} else {Notify}) else {}) \ (if AllowGrant \ r then UNIV else {})" definition vspace_cap_rights_to_auth :: "cap_rights \ auth set" where "vspace_cap_rights_to_auth r \ (if AllowWrite \ r then {Write} else {}) \ (if AllowRead \ r then {Read} else {})" definition cap_auth_conferred :: "cap \ auth set" where "cap_auth_conferred cap \ case cap of Structures_A.NullCap \ {} | Structures_A.UntypedCap isdev oref bits freeIndex \ {Control} | Structures_A.EndpointCap oref badge r \ cap_rights_to_auth r True | Structures_A.NotificationCap oref badge r \ cap_rights_to_auth (r - {AllowGrant}) False | Structures_A.ReplyCap oref m \ {Control} | Structures_A.CNodeCap oref bits guard \ {Control} | Structures_A.ThreadCap obj_ref \ {Control} | Structures_A.DomainCap \ {Control} | Structures_A.IRQControlCap \ {Control} | Structures_A.IRQHandlerCap irq \ {Control} | Structures_A.Zombie ptr b n \ {Control} | Structures_A.ArchObjectCap arch_cap \ (if is_page_cap (the_arch_cap cap) then vspace_cap_rights_to_auth (acap_rights arch_cap) else {Control})" fun tcb_st_to_auth :: "Structures_A.thread_state \ (obj_ref \ auth) set" where "tcb_st_to_auth (Structures_A.BlockedOnNotification ntfn) = {(ntfn, Receive)}" | "tcb_st_to_auth (Structures_A.BlockedOnSend ep payl) = {(ep, SyncSend)} \ (if sender_can_grant payl then {(ep, Grant)} else {})" | "tcb_st_to_auth (Structures_A.BlockedOnReceive ep) = {(ep, Receive)}" | "tcb_st_to_auth _ = {}" definition "pte_ref pte \ case pte of SmallPagePTE addr atts rights \ Some (ptrFromPAddr addr, pageBitsForSize ARMSmallPage, vspace_cap_rights_to_auth rights) | LargePagePTE addr atts rights \ Some (ptrFromPAddr addr, pageBitsForSize ARMLargePage, vspace_cap_rights_to_auth rights) | _ \ None" definition "pde_ref2 pde \ case pde of SectionPDE addr atts domain rights \ Some (ptrFromPAddr addr, pageBitsForSize ARMSection, vspace_cap_rights_to_auth rights) | SuperSectionPDE addr atts rights \ Some (ptrFromPAddr addr, pageBitsForSize ARMSuperSection, vspace_cap_rights_to_auth rights) | PageTablePDE addr atts domain \ Some (ptrFromPAddr addr, 0, {Control}) (* The 0 is a hack, saying that we own only addr, although 12 would also be OK *) | _ \ None" definition "ptr_range p sz \ {p .. p + 2 ^ sz - 1}" (* We exclude the global page tables from the authority graph. Alternatively, we could include them and add a wellformedness constraint to policies that requires that every label has the necessary authority to whichever label owns the global page tables, so that when a new page directory is created and references to the global page tables are added to it, no new authority is gained. Note: excluding the references to global page tables in this way brings in some ARM arch-specific VM knowledge here *) definition vs_refs_no_global_pts :: "Structures_A.kernel_object \ (obj_ref \ vs_ref \ auth) set" where "vs_refs_no_global_pts \ \ko. case ko of ArchObj (ASIDPool pool) \ (\(r,p). (p, VSRef (ucast r) (Some AASIDPool), Control)) ` graph_of pool | ArchObj (PageDirectory pd) \ \(r,(p, sz, auth)) \ graph_of (pde_ref2 o pd) - {(x,y). (ucast (kernel_base >> 20) \ x)}. (\(p, a). (p, VSRef (ucast r) (Some APageDirectory), a)) ` (ptr_range p sz \ auth) | ArchObj (PageTable pt) \ \(r,(p, sz, auth)) \ graph_of (pte_ref o pt). (\(p, a). (p, VSRef (ucast r) (Some APageTable), a)) ` (ptr_range p sz \ auth) | _ \ {}" text {* sbta_caps/sbta_asid imply that a thread and it's vspace are labelled the same -- caps_of_state (tcb, vspace_index) will be the PD cap. Thus, a thread is completely managed or completely self-managed. We can (possibly) weaken this by only talking about addressable caps (i.e., only cspace in a tcb). This would also mean that we should use the current cspace for the current label ... a bit strange, though. The set of all objects affected by a capability. We cheat a bit and say that a DomainCap contains references to everything, as it intuitively grants its owners that sort of access. This allows us to reuse sbta for DomainCaps. The sbta definition is non-inductive. We use the "inductive" construct for convenience, i.e. to get a nice set of intro rules, cases, etc. *} primrec aobj_ref' :: "arch_cap \ obj_ref set" where "aobj_ref' (arch_cap.ASIDPoolCap p as) = {p}" | "aobj_ref' arch_cap.ASIDControlCap = {}" | "aobj_ref' (arch_cap.PageCap isdev x rs sz as4) = ptr_range x (pageBitsForSize sz)" | "aobj_ref' (arch_cap.PageDirectoryCap x as2) = {x}" | "aobj_ref' (arch_cap.PageTableCap x as3) = {x}" primrec obj_refs :: "cap \ obj_ref set" where "obj_refs cap.NullCap = {}" | "obj_refs (cap.ReplyCap r m) = {r}" | "obj_refs cap.IRQControlCap = {}" | "obj_refs (cap.IRQHandlerCap irq) = {}" | "obj_refs (cap.UntypedCap d r s f) = {}" | "obj_refs (cap.CNodeCap r bits guard) = {r}" | "obj_refs (cap.EndpointCap r b cr) = {r}" | "obj_refs (cap.NotificationCap r b cr) = {r}" | "obj_refs (cap.ThreadCap r) = {r}" | "obj_refs (cap.Zombie ptr b n) = {ptr}" | "obj_refs (cap.ArchObjectCap x) = aobj_ref' x" | "obj_refs cap.DomainCap = UNIV" (* hack, see above *) inductive_set state_bits_to_policy for caps thread_sts thread_bas cdt vrefs where sbta_caps: "\ caps ptr = Some cap; oref \ obj_refs cap; auth \ cap_auth_conferred cap \ \ (fst ptr, auth, oref) \ state_bits_to_policy caps thread_sts thread_bas cdt vrefs" | sbta_untyped: "\ caps ptr = Some cap; oref \ untyped_range cap \ \ (fst ptr, Control, oref) \ state_bits_to_policy caps thread_sts thread_bas cdt vrefs" | sbta_ts: "\ (oref', auth) \ thread_sts oref \ \ (oref, auth, oref') \ state_bits_to_policy caps thread_sts thread_bas cdt vrefs" | sbta_bounds: "\thread_bas oref = Some oref'; auth \ {Receive, Reset} \ \ (oref, auth, oref') \ state_bits_to_policy caps thread_sts thread_bas cdt vrefs" | sbta_cdt: "\ cdt slot' = Some slot \ \ (fst slot, Control, fst slot') \ state_bits_to_policy caps thread_sts thread_bas cdt vrefs" | sbta_vref: "\ (ptr', ref, auth) \ vrefs ptr \ \ (ptr, auth, ptr') \ state_bits_to_policy caps thread_sts thread_bas cdt vrefs" fun cap_asid' :: "cap \ asid set" where "cap_asid' (ArchObjectCap (PageCap _ _ _ _ mapping)) = fst ` set_option mapping" | "cap_asid' (ArchObjectCap (PageTableCap _ mapping)) = fst ` set_option mapping" | "cap_asid' (ArchObjectCap (PageDirectoryCap _ asid_opt)) = set_option asid_opt" | "cap_asid' (ArchObjectCap (ASIDPoolCap _ asid)) = {x. asid_high_bits_of x = asid_high_bits_of asid \ x \ 0}" | "cap_asid' (ArchObjectCap ASIDControlCap) = UNIV" | "cap_asid' _ = {}" inductive_set state_asids_to_policy_aux for aag caps asid_tab vrefs where sata_asid: "\ caps ptr = Some cap; asid \ cap_asid' cap \ \ ( pasObjectAbs aag (fst ptr), Control, pasASIDAbs aag asid) \ state_asids_to_policy_aux aag caps asid_tab vrefs" | sata_asid_lookup: "\ asid_tab (asid_high_bits_of asid) = Some poolptr; (pdptr, VSRef (asid && mask asid_low_bits) (Some AASIDPool), a) \ vrefs poolptr \ \ (pasASIDAbs aag asid, a, pasObjectAbs aag pdptr) \ state_asids_to_policy_aux aag caps asid_tab vrefs" | sata_asidpool: "\ asid_tab (asid_high_bits_of asid) = Some poolptr; asid \ 0 \ \ (pasObjectAbs aag poolptr, ASIDPoolMapsASID, pasASIDAbs aag asid) \ state_asids_to_policy_aux aag caps asid_tab vrefs" fun cap_irqs_controlled :: "cap \ irq set" where "cap_irqs_controlled cap.IRQControlCap = UNIV" | "cap_irqs_controlled (cap.IRQHandlerCap irq) = {irq}" | "cap_irqs_controlled _ = {}" inductive_set state_irqs_to_policy_aux for aag caps where sita_controlled: "\ caps ptr = Some cap; irq \ cap_irqs_controlled cap \ \ (pasObjectAbs aag (fst ptr), Control, pasIRQAbs aag irq) \ state_irqs_to_policy_aux aag caps" abbreviation "state_irqs_to_policy aag s \ state_irqs_to_policy_aux aag (caps_of_state s)" definition "irq_map_wellformed_aux aag irqs \ \irq. pasObjectAbs aag (irqs irq) = pasIRQAbs aag irq" abbreviation "irq_map_wellformed aag s \ irq_map_wellformed_aux aag (interrupt_irq_node s)" definition "state_vrefs s = case_option {} vs_refs_no_global_pts o kheap s" abbreviation "state_asids_to_policy aag s \ state_asids_to_policy_aux aag (caps_of_state s) (arm_asid_table (arch_state s)) (state_vrefs s)" definition "tcb_states_of_state s \ \p. option_map tcb_state (get_tcb p s)" definition "thread_states s = case_option {} tcb_st_to_auth \ tcb_states_of_state s" definition "thread_bound_ntfns s \ \p. case (get_tcb p s) of None \ None | Some tcb \ tcb_bound_notification tcb" definition "state_objs_to_policy s = state_bits_to_policy (caps_of_state s) (thread_states s) (thread_bound_ntfns s) (cdt s) (state_vrefs s)" lemmas state_objs_to_policy_mem = eqset_imp_iff[OF state_objs_to_policy_def] lemmas state_objs_to_policy_intros = state_bits_to_policy.intros[THEN state_objs_to_policy_mem[THEN iffD2]] lemmas sta_caps = state_objs_to_policy_intros(1) and sta_untyped = state_objs_to_policy_intros(2) and sta_ts = state_objs_to_policy_intros(3) and sta_bas = state_objs_to_policy_intros(4) and sta_cdt = state_objs_to_policy_intros(5) and sta_vref = state_objs_to_policy_intros(6) lemmas state_objs_to_policy_cases = state_bits_to_policy.cases[OF state_objs_to_policy_mem[THEN iffD1]] end context pspace_update_eq begin interpretation Arch . (*FIXME: arch_split*) lemma state_vrefs[iff]: "state_vrefs (f s) = state_vrefs s" by (simp add: state_vrefs_def pspace) lemma thread_states[iff]: "thread_states (f s) = thread_states s" by (simp add: thread_states_def pspace get_tcb_def swp_def tcb_states_of_state_def) lemma thread_bound_ntfns[iff]: "thread_bound_ntfns (f s) = thread_bound_ntfns s" by (simp add: thread_bound_ntfns_def pspace get_tcb_def swp_def split: option.splits) (* lemma ipc_buffers_of_state[iff]: "ipc_buffers_of_state (f s) = ipc_buffers_of_state s" by (simp add: ipc_buffers_of_state_def pspace get_tcb_def swp_def) *) end context begin interpretation Arch . (*FIXME: arch_split*) lemma tcb_states_of_state_preserved: "\ get_tcb thread s = Some tcb; tcb_state tcb' = tcb_state tcb \ \ tcb_states_of_state (s\kheap := kheap s(thread \ TCB tcb')\) = tcb_states_of_state s" apply rule apply (auto split: option.splits simp: tcb_states_of_state_def get_tcb_def) done lemma thread_states_preserved: "\ get_tcb thread s = Some tcb; tcb_state tcb' = tcb_state tcb \ \ thread_states (s\kheap := kheap s(thread \ TCB tcb')\) = thread_states s" by (simp add: tcb_states_of_state_preserved thread_states_def) lemma thread_bound_ntfns_preserved: "\ get_tcb thread s = Some tcb; tcb_bound_notification tcb' = tcb_bound_notification tcb \ \ thread_bound_ntfns (s\kheap := kheap s(thread \ TCB tcb')\) = thread_bound_ntfns s" by (auto simp: thread_bound_ntfns_def get_tcb_def split: option.splits) (* FIXME: move *) lemma null_filterI: "\ cs p = Some cap; cap \ cap.NullCap \ \ null_filter cs p = Some cap" unfolding null_filter_def by auto lemma sbta_null_filter: "state_bits_to_policy (null_filter cs) sr bar cd vr = state_bits_to_policy cs sr bar cd vr" apply (rule) apply clarsimp apply (erule state_bits_to_policy.induct, auto intro: state_bits_to_policy.intros elim: null_filterE)[1] apply clarsimp apply (erule state_bits_to_policy.induct, auto intro: sbta_caps [OF null_filterI] sbta_untyped [OF null_filterI] state_bits_to_policy.intros)[1] done lemma sata_null_filter: "state_asids_to_policy_aux aag (null_filter cs) asid_tab vrefs = state_asids_to_policy_aux aag cs asid_tab vrefs" by (auto elim!: state_asids_to_policy_aux.induct null_filterE intro: state_asids_to_policy_aux.intros sata_asid[OF null_filterI]) text{* We map scheduler domains to labels. This asserts that the labels on tcbs are consistent with the labels on the domains they run in. We need this to show that the ready queues are not reordered by unauthorised subjects (see integrity_ready_queues). *} inductive_set domains_of_state_aux for ekheap where domtcbs: "\ ekheap ptr = Some etcb; d = tcb_domain etcb \ \ (ptr, d) \ domains_of_state_aux ekheap" abbreviation "domains_of_state s \ domains_of_state_aux (ekheap s)" definition "tcb_domain_map_wellformed_aux aag etcbs_doms \ \(ptr, d) \ etcbs_doms. pasObjectAbs aag ptr \ pasDomainAbs aag d" abbreviation "tcb_domain_map_wellformed aag s \ tcb_domain_map_wellformed_aux aag (domains_of_state s)" lemma tcb_domain_map_wellformed_mono: "\ domains_of_state s' \ domains_of_state s; tcb_domain_map_wellformed pas s \ \ tcb_domain_map_wellformed pas s'" by (auto simp: tcb_domain_map_wellformed_aux_def get_etcb_def) text{* We sometimes need to know that our current subject may run in the current domain. *} abbreviation "pas_cur_domain aag s \ pasSubject aag \ pasDomainAbs aag (cur_domain s)" text{* The relation we want to hold between the current state and the policy: \begin{itemize} \item The policy should be well-formed. \item The abstraction of the state should respect the policy. \end{itemize} *} definition pas_refined :: "'a PAS \ det_ext state \ bool" where "pas_refined aag \ \s. pas_wellformed aag \ irq_map_wellformed aag s \ tcb_domain_map_wellformed aag s \ auth_graph_map (pasObjectAbs aag) (state_objs_to_policy s) \ pasPolicy aag \ state_asids_to_policy aag s \ pasPolicy aag \ state_irqs_to_policy aag s \ pasPolicy aag" lemma pas_refined_mem: "\ (x, auth, y) \ state_objs_to_policy s; pas_refined aag s \ \ (pasObjectAbs aag x, auth, pasObjectAbs aag y) \ pasPolicy aag" by (auto simp: pas_refined_def intro: auth_graph_map_memI) lemma pas_refined_wellformed: "pas_refined aag s \ pas_wellformed aag" unfolding pas_refined_def by simp lemmas pas_refined_Control = aag_wellformed_Control[OF _ pas_refined_wellformed] and pas_refined_refl = aag_wellformed_refl [OF pas_refined_wellformed] lemma caps_of_state_pasObjectAbs_eq: "\ caps_of_state s p = Some cap; Control \ cap_auth_conferred cap; is_subject aag (fst p); pas_refined aag s; x \ obj_refs cap \ \ is_subject aag x" apply (frule sta_caps, simp+) apply (drule pas_refined_mem, simp+) apply (drule pas_refined_Control, simp+) done lemma pas_refined_state_objs_to_policy_subset: "\ pas_refined aag s; state_objs_to_policy s' \ state_objs_to_policy s; state_asids_to_policy aag s' \ state_asids_to_policy aag s; state_irqs_to_policy aag s' \ state_irqs_to_policy aag s; domains_of_state s' \ domains_of_state s; interrupt_irq_node s' = interrupt_irq_node s \ \ pas_refined aag s'" by (simp add: pas_refined_def) (blast dest: tcb_domain_map_wellformed_mono dest: auth_graph_map_mono[where G="pasObjectAbs aag"]) lemma aag_wellformed_all_auth_is_owns': "\ Control \ S; pas_wellformed aag \ \ (\auth \ S. aag_has_auth_to aag auth x) = (is_subject aag x)" apply (rule iffI) apply (drule (1) bspec) apply (frule (1) aag_wellformed_Control ) apply fastforce apply (clarsimp simp: aag_wellformed_refl) done lemmas aag_wellformed_all_auth_is_owns = aag_wellformed_all_auth_is_owns'[where S=UNIV, simplified] aag_wellformed_all_auth_is_owns'[where S="{Control}", simplified] lemmas pas_refined_all_auth_is_owns = aag_wellformed_all_auth_is_owns[OF pas_refined_wellformed] lemma pas_refined_sita_mem: "\ (x, auth, y) \ state_irqs_to_policy aag s; pas_refined aag s \ \ (x, auth, y) \ pasPolicy aag" by (auto simp: pas_refined_def) (* **************************************** *) subsection{* How kernel objects can change *} fun blocked_on :: "obj_ref \ Structures_A.thread_state \ bool" where "blocked_on ref (Structures_A.BlockedOnReceive ref') = (ref = ref')" | "blocked_on ref (Structures_A.BlockedOnSend ref' _) = (ref = ref')" | "blocked_on ref (Structures_A.BlockedOnNotification ref') = (ref = ref')" | "blocked_on _ _ = False" lemma blocked_on_def2: "blocked_on ref ts = (ref \ fst ` tcb_st_to_auth ts)" by (cases ts, simp_all) fun receive_blocked_on :: "obj_ref \ Structures_A.thread_state \ bool" where "receive_blocked_on ref (Structures_A.BlockedOnReceive ref') = (ref = ref')" | "receive_blocked_on ref (Structures_A.BlockedOnNotification ref') = (ref = ref')" | "receive_blocked_on _ _ = False" lemma receive_blocked_on_def2: "receive_blocked_on ref ts = ((ref, Receive) \ tcb_st_to_auth ts)" by (cases ts, simp_all) fun send_blocked_on :: "obj_ref \ Structures_A.thread_state \ bool" where "send_blocked_on ref (Structures_A.BlockedOnSend ref' _) = (ref = ref')" | "send_blocked_on _ _ = False" lemma send_blocked_on_def2: "send_blocked_on ref ts = ((ref, SyncSend) \ tcb_st_to_auth ts)" by (cases ts, simp_all) fun send_is_call :: "Structures_A.thread_state \ bool" where "send_is_call (Structures_A.BlockedOnSend _ payl) = sender_is_call payl" | "send_is_call _ = False" abbreviation aag_subjects_have_auth_to :: "'a set \ 'a PAS \ auth \ obj_ref \ bool" where "aag_subjects_have_auth_to subs aag auth oref \ \s \ subs. (s, auth, pasObjectAbs aag oref) \ pasPolicy aag" text{* The integrity_obj relation captures the changes allowed to a particular kernel object between the initial and final states: @{text "integrity_obj aag l' ko ko'"} holds when the current label can change @{term "ko"} to @{term "ko'"} when the address of @{term "ko"} (and hence @{term "ko'"}) is labelled by @{term "l'"}. *} definition tcb_bound_notification_reset_integrity :: "obj_ref option \ obj_ref option \ 'a set \ 'a PAS \ bool" where "tcb_bound_notification_reset_integrity ntfn ntfn' subjects aag = ((ntfn = ntfn') (*NO CHANGE TO BOUND NTFN *) \ (ntfn' = None \ aag_subjects_have_auth_to subjects aag Reset (the ntfn)) (* NTFN IS UNBOUND *))" definition direct_send :: "'a set \ 'a PAS \ obj_ref \ tcb \ bool" where "direct_send subjects aag ep tcb \ receive_blocked_on ep (tcb_state tcb) \ (aag_subjects_have_auth_to subjects aag SyncSend ep \ aag_subjects_have_auth_to subjects aag Notify ep)" abbreviation ep_recv_blocked :: "obj_ref \ thread_state \ bool" where "ep_recv_blocked ep ts \ case ts of BlockedOnReceive w \ w = ep | _ \ False" definition indirect_send :: "'a set \ 'a PAS \ obj_ref \ obj_ref \ tcb \ bool" where "indirect_send subjects aag ntfn recv_ep tcb \ ep_recv_blocked recv_ep (tcb_state tcb) (* tcb is blocked on sync ep *) \ (tcb_bound_notification tcb = Some ntfn) \ aag_subjects_have_auth_to subjects aag Notify ntfn" inductive integrity_obj for aag activate subjects l' ko ko' where tro_lrefl: "\ l' \ subjects \ \ integrity_obj aag activate subjects l' ko ko'" | tro_orefl: "\ ko = ko' \ \ integrity_obj aag activate subjects l' ko ko'" | tro_ntfn: "\ ko = Some (Notification ntfn); ko' = Some (Notification ntfn'); auth \ {Receive, Notify, Reset}; (\s \ subjects. (s, auth, l') \ pasPolicy aag) \ \ integrity_obj aag activate subjects l' ko ko'" | tro_ep: "\ ko = Some (Endpoint ep); ko' = Some (Endpoint ep'); auth \ {Receive, SyncSend, Reset}; (\s \ subjects. (s, auth, l') \ pasPolicy aag) \ \ integrity_obj aag activate subjects l' ko ko'" | tro_ep_unblock: "\ ko = Some (Endpoint ep); ko' = Some (Endpoint ep'); \tcb ntfn. (tcb, Receive, pasObjectAbs aag ntfn) \ pasPolicy aag \ (tcb, Receive, l') \ pasPolicy aag \ aag_subjects_have_auth_to subjects aag Notify ntfn \ \ integrity_obj aag activate subjects l' ko ko'" | tro_tcb_send: "\ ko = Some (TCB tcb); ko' = Some (TCB tcb'); \ctxt'. tcb' = tcb \tcb_arch := arch_tcb_context_set ctxt' (tcb_arch tcb), tcb_state := Structures_A.Running, tcb_bound_notification := ntfn'\; tcb_bound_notification_reset_integrity (tcb_bound_notification tcb) ntfn' subjects aag; direct_send subjects aag ep tcb \ indirect_send subjects aag ep recv tcb \ \ integrity_obj aag activate subjects l' ko ko'" | tro_tcb_receive: "\ ko = Some (TCB tcb); ko' = Some (TCB tcb'); tcb' = tcb \tcb_state := new_st, tcb_bound_notification := ntfn'\; new_st = Structures_A.Running \ (new_st = Structures_A.Inactive \ (send_is_call (tcb_state tcb) \ tcb_fault tcb \ None)); (* maybe something about can_grant here? *) tcb_bound_notification_reset_integrity (tcb_bound_notification tcb) ntfn' subjects aag; send_blocked_on ep (tcb_state tcb); aag_subjects_have_auth_to subjects aag Receive ep \ \ integrity_obj aag activate subjects l' ko ko'" | tro_tcb_restart: "\ ko = Some (TCB tcb); ko' = Some (TCB tcb'); tcb' = tcb\ tcb_arch := arch_tcb_context_set (arch_tcb_context_get (tcb_arch tcb')) (tcb_arch tcb) , tcb_state := tcb_state tcb', tcb_bound_notification := ntfn'\; (tcb_state tcb' = Structures_A.Restart \ arch_tcb_context_get (tcb_arch tcb') = arch_tcb_context_get (tcb_arch tcb)) \ (* to handle activation *) (tcb_state tcb' = Structures_A.Running \ arch_tcb_context_get (tcb_arch tcb') = (arch_tcb_context_get (tcb_arch tcb))(LR_svc := arch_tcb_context_get (tcb_arch tcb) FaultInstruction)); tcb_bound_notification_reset_integrity (tcb_bound_notification tcb) ntfn' subjects aag; blocked_on ep (tcb_state tcb); aag_subjects_have_auth_to subjects aag Reset ep \ \ integrity_obj aag activate subjects l' ko ko'" | tro_tcb_unbind: "\ ko = Some (TCB tcb); ko' = Some (TCB tcb'); tcb' = tcb \tcb_bound_notification := None\; tcb_bound_notification_reset_integrity (tcb_bound_notification tcb) None subjects aag \ \ integrity_obj aag activate subjects l' ko ko'" | tro_asidpool_clear: "\ ko = Some (ArchObj (ASIDPool pool)); ko' = Some (ArchObj (ASIDPool pool')); \x. pool' x \ pool x \ pool' x = None \ aag_subjects_have_auth_to subjects aag Control (the (pool x)) \ \ integrity_obj aag activate subjects l' ko ko'" | tro_tcb_activate: "\ ko = Some (TCB tcb); ko' = Some (TCB tcb'); tcb' = tcb \ tcb_arch := arch_tcb_context_set ((arch_tcb_context_get (tcb_arch tcb))(LR_svc := (arch_tcb_context_get (tcb_arch tcb)) FaultInstruction)) (tcb_arch tcb) , tcb_state := Structures_A.Running, tcb_bound_notification := ntfn'\; tcb_state tcb = Structures_A.Restart; (* to handle unbind *) tcb_bound_notification_reset_integrity (tcb_bound_notification tcb) ntfn' subjects aag; activate \ (* Anyone can do this *) \ integrity_obj aag activate subjects l' ko ko'" text{* Assume two subjects can't interact. Then AINVS already implies that the ready queues of one won't change when the other is running. Assume two subjects can interact via an endpoint. (Probably an notification object for infoflow purposes.) Then the following says that the ready queues for the non-running subject can be extended by the running subject, e.g. by sending a message. Note these threads are added to the start of the queue. *} definition integrity_ready_queues where "integrity_ready_queues aag subjects queue_labels rq rq' \ pasMayEditReadyQueues aag \ (queue_labels \ subjects = {} \ (\threads. threads @ rq = rq'))" lemma integrity_ready_queues_refl[simp]: "integrity_ready_queues aag subjects ptr s s" unfolding integrity_ready_queues_def by simp inductive integrity_eobj for aag subjects l' eko eko' where tre_lrefl: "\ l' \ subjects \ \ integrity_eobj aag subjects l' eko eko'" | tre_orefl: "\ eko = eko' \ \ integrity_eobj aag subjects l' eko eko'" lemma integrity_obj_activate: "integrity_obj aag False subjects l' ko ko' \ integrity_obj aag activate subjects l' ko ko'" by (fast elim: integrity_obj.cases intro: integrity_obj.intros) abbreviation "object_integrity aag \ integrity_obj (aag :: 'a PAS) (pasMayActivate aag) {pasSubject aag}" definition auth_ipc_buffers :: "'z::state_ext state \ word32 \ word32 set" where "auth_ipc_buffers s \ \p. case (get_tcb p s) of None \ {} | Some tcb \ case tcb_ipcframe tcb of cap.ArchObjectCap (arch_cap.PageCap False p' R vms _) \ if AllowWrite \ R then (ptr_range (p' + (tcb_ipc_buffer tcb && mask (pageBitsForSize vms))) msg_align_bits) else {} | _ \ {}" (* MOVE *) lemma caps_of_state_tcb: "\ get_tcb p s = Some tcb; option_map fst (tcb_cap_cases idx) = Some getF \ \ caps_of_state s (p, idx) = Some (getF tcb)" apply (drule get_tcb_SomeD) apply clarsimp apply (drule (1) cte_wp_at_tcbI [where t = "(p, idx)" and P = "(=) (getF tcb)", simplified]) apply simp apply (clarsimp simp: cte_wp_at_caps_of_state) done (* MOVE *) lemma caps_of_state_tcb_cap_cases: "\ get_tcb p s = Some tcb; idx \ dom tcb_cap_cases \ \ caps_of_state s (p, idx) = Some ((the (option_map fst (tcb_cap_cases idx))) tcb)" apply (clarsimp simp: dom_def) apply (erule caps_of_state_tcb) apply simp done lemma auth_ipc_buffers_member_def: "x \ auth_ipc_buffers s p = (\tcb p' R vms xx. get_tcb p s = Some tcb \ tcb_ipcframe tcb = (cap.ArchObjectCap (arch_cap.PageCap False p' R vms xx)) \ caps_of_state s (p, tcb_cnode_index 4) = Some (cap.ArchObjectCap (arch_cap.PageCap False p' R vms xx)) \ AllowWrite \ R \ x \ ptr_range (p' + (tcb_ipc_buffer tcb && mask (pageBitsForSize vms))) msg_align_bits)" unfolding auth_ipc_buffers_def by (clarsimp simp: caps_of_state_tcb split: option.splits cap.splits arch_cap.splits bool.splits) text {* Inductive for now, we should add something about user memory/transitions. This relies on tro to tell us when a tcb state can change to avoid duplicating the defs etc. *} inductive integrity_mem for aag subjects p ts ts' ipcbufs globals w w' where trm_lrefl: "\ pasObjectAbs aag p \ subjects \ \ integrity_mem aag subjects p ts ts' ipcbufs globals w w'" (* implied by wf and write *) | trm_orefl: "\ w = w' \ \ integrity_mem aag subjects p ts ts' ipcbufs globals w w'" | trm_write: "\ aag_subjects_have_auth_to subjects aag Write p \ \ integrity_mem aag subjects p ts ts' ipcbufs globals w w'" | trm_globals: "\ p \ globals \ \ integrity_mem aag subjects p ts ts' ipcbufs globals w w'" | trm_ipc: "\ case_option False (receive_blocked_on ep) (ts p'); ts' p' = Some Structures_A.Running; p \ ipcbufs p'; pasObjectAbs aag p' \ subjects \ \ integrity_mem aag subjects p ts ts' ipcbufs globals w w'" abbreviation "memory_integrity X aag x t1 t2 ipc == integrity_mem (aag :: 'a PAS) {pasSubject aag} x t1 t2 ipc X" inductive integrity_device for aag subjects p ts ts' w w' where trd_lrefl: "\ pasObjectAbs aag p \ subjects \ \ integrity_device aag subjects p ts ts' w w'" (* implied by wf and write *) | trd_orefl: "\ w = w' \ \ integrity_device aag subjects p ts ts' w w'" | trd_write: "\ aag_subjects_have_auth_to subjects aag Write p \ \ integrity_device aag subjects p ts ts' w w'" lemmas integrity_obj_simps [simp] = tro_orefl[OF refl] tro_lrefl[OF singletonI] trm_orefl[OF refl] trd_orefl[OF refl] tre_lrefl[OF singletonI] tre_orefl[OF refl] definition integrity_cdt :: "'a PAS \ 'a set \ cslot_ptr \ (cslot_ptr option \ bool) \ (cslot_ptr option \ bool) \ bool" where "integrity_cdt aag subjects ptr v v' \ v = v' \ pasObjectAbs aag (fst ptr) \ subjects" abbreviation "cdt_integrity aag == integrity_cdt (aag :: 'a PAS) {pasSubject aag}" lemma integrity_cdt_refl[simp]: "integrity_cdt aag subjects ptr v v" by (simp add: integrity_cdt_def) definition integrity_cdt_list :: "'a PAS \ 'a set \ cslot_ptr \ (cslot_ptr list) \ (cslot_ptr list) \ bool" where "integrity_cdt_list aag subjects ptr v v' \ (filtered_eq (\x. pasObjectAbs aag (fst x) \ subjects) v v') \ pasObjectAbs aag (fst ptr) \ subjects" abbreviation "cdt_list_integrity aag == integrity_cdt_list (aag :: 'a PAS) {pasSubject aag}" lemma integrity_cdt_list_refl[simp]: "integrity_cdt_list aag subjects ptr v v" by (simp add: integrity_cdt_list_def) definition integrity_interrupts :: "'a PAS \ 'a set \ irq \ (obj_ref \ irq_state) \ (obj_ref \ irq_state) \ bool" where "integrity_interrupts aag subjects irq v v' \ v = v' \ pasIRQAbs aag irq \ subjects" lemma integrity_interrupts_refl[simp]: "integrity_interrupts aag subjects ptr v v" by (simp add: integrity_interrupts_def) definition integrity_asids :: "'a PAS \ 'a set \ asid \ word32 option \ word32 option \ bool" where "integrity_asids aag subjects asid pp_opt pp_opt' \ pp_opt = pp_opt' \ (\ asid'. asid' \ 0 \ asid_high_bits_of asid' = asid_high_bits_of asid \ pasASIDAbs aag asid' \ subjects)" lemma integrity_asids_refl[simp]: "integrity_asids aag subjects ptr s s" by (simp add: integrity_asids_def) text{* Half of what we ultimately want to say: that the parts of the system state that change are allowed to by the labelling @{term "aag"}. The other half involves showing that @{term "aag"} concords with the policy. See @{term "state_objs_to_policy s"}. *} definition integrity_subjects :: "'a set \ 'a PAS \ bool \ obj_ref set \ det_ext state \ det_ext state \ bool" where "integrity_subjects subjects aag activate X s s' \ (\x. integrity_obj aag activate subjects (pasObjectAbs aag x) (kheap s x) (kheap s' x)) \ (\x. integrity_eobj aag subjects (pasObjectAbs aag x) (ekheap s x) (ekheap s' x)) \ (\x. integrity_mem aag subjects x (tcb_states_of_state s) (tcb_states_of_state s') (auth_ipc_buffers s) X (underlying_memory (machine_state s) x) (underlying_memory (machine_state s') x)) \ (\x. integrity_device aag subjects x (tcb_states_of_state s) (tcb_states_of_state s') (device_state (machine_state s) x) (device_state (machine_state s') x)) \ (\x. integrity_cdt aag subjects x (cdt s x, is_original_cap s x) (cdt s' x, is_original_cap s' x)) \ (\x. integrity_cdt_list aag subjects x (cdt_list s x) (cdt_list s' x)) \ (\x. integrity_interrupts aag subjects x (interrupt_irq_node s x, interrupt_states s x) (interrupt_irq_node s' x, interrupt_states s' x)) \ (\x. integrity_asids aag subjects x (arm_asid_table (arch_state s) (asid_high_bits_of x)) (arm_asid_table (arch_state s') (asid_high_bits_of x))) \ (\d p. integrity_ready_queues aag subjects (pasDomainAbs aag d) (ready_queues s d p) (ready_queues s' d p))" abbreviation "integrity pas \ integrity_subjects {pasSubject pas} pas (pasMayActivate pas)" lemma clear_asidpool_trans: "\ \x. pool' x \ pool x \ pool' x = None \ aag_subjects_have_auth_to es aag Control (the (pool x)); \x. pool'' x \ pool' x \ pool'' x = None \ aag_subjects_have_auth_to es aag Control (the (pool' x)) \ \ \x. pool'' x \ pool x \ pool'' x = None \ aag_subjects_have_auth_to es aag Control (the (pool x))" apply clarsimp apply (drule_tac x=x in spec)+ apply auto done lemma tcb_bound_notification_reset_integrity_trans[elim]: "\ tcb_bound_notification_reset_integrity ntfn ntfn' subjects aag; tcb_bound_notification_reset_integrity ntfn' ntfn'' subjects aag \ \ tcb_bound_notification_reset_integrity ntfn ntfn'' subjects aag" by (auto simp: tcb_bound_notification_reset_integrity_def) lemma tro_trans: (* this takes a long time to process *) "\(\x. integrity_obj aag activate es (pasObjectAbs aag x) (kheap s x) (kheap s' x)); (\x. integrity_obj aag activate es (pasObjectAbs aag x) (kheap s' x) (kheap s'' x)) \ \ (\x. integrity_obj aag activate es (pasObjectAbs aag x) (kheap s x) (kheap s'' x))" apply clarsimp apply (drule_tac x = x in spec)+ apply (erule integrity_obj.cases) prefer 10 apply ((clarsimp | erule integrity_obj.cases | erule disjE | drule(1) clear_asidpool_trans | drule sym[where s = "Some x" for x] | blast intro: integrity_obj.intros)+)[1] by (((fastforce intro: integrity_obj.intros simp: indirect_send_def direct_send_def) | erule integrity_obj.cases)+) lemma tre_trans: "\(\x. integrity_eobj aag es (pasObjectAbs aag x) (ekh x) (ekh' x)); (\x. integrity_eobj aag es (pasObjectAbs aag x) (ekh' x) (ekh'' x)) \ \ (\x. integrity_eobj aag es (pasObjectAbs aag x) (ekh x) (ekh'' x))" by (fastforce elim!: integrity_eobj.cases intro: integrity_eobj.intros)+ lemma trcdt_trans: "\ (\x. integrity_cdt aag subjects x (cdt s x, is_original_cap s x) (cdt s' x, is_original_cap s' x)); (\x. integrity_cdt aag subjects x (cdt s' x, is_original_cap s' x) (cdt s'' x, is_original_cap s'' x)) \ \ (\x. integrity_cdt aag subjects x (cdt s x, is_original_cap s x) (cdt s'' x, is_original_cap s'' x))" apply (simp add: integrity_cdt_def del: split_paired_All) apply metis done lemma trcdtlist_trans: "\ (\x. integrity_cdt_list aag subjects x (t x) (t' x)); (\x. integrity_cdt_list aag subjects x (t' x) (t'' x)) \ \ (\x. integrity_cdt_list aag subjects x (t x) (t'' x))" apply (simp add: integrity_cdt_list_def del: split_paired_All) apply metis done lemma trinterrupts_trans: "\ (\x. integrity_interrupts aag subjects x (interrupt_irq_node s x, interrupt_states s x) (interrupt_irq_node s' x, interrupt_states s' x)); (\x. integrity_interrupts aag subjects x (interrupt_irq_node s' x, interrupt_states s' x) (interrupt_irq_node s'' x, interrupt_states s'' x)) \ \ (\x. integrity_interrupts aag subjects x (interrupt_irq_node s x, interrupt_states s x) (interrupt_irq_node s'' x, interrupt_states s'' x))" apply (simp add: integrity_interrupts_def del: split_paired_All) apply metis done lemma trasids_trans: "\ (\x. integrity_asids aag subjects x (arm_asid_table (arch_state s) (asid_high_bits_of x)) (arm_asid_table (arch_state s') (asid_high_bits_of x))); (\x. integrity_asids aag subjects x (arm_asid_table (arch_state s') (asid_high_bits_of x)) (arm_asid_table (arch_state s'') (asid_high_bits_of x)))\ \ (\x. integrity_asids aag subjects x (arm_asid_table (arch_state s) (asid_high_bits_of x)) (arm_asid_table (arch_state s'') (asid_high_bits_of x)))" apply (clarsimp simp: integrity_asids_def) apply metis done lemma trrqs_trans: "\ (\d p. integrity_ready_queues aag subjects (pasDomainAbs aag d) (ready_queues s d p) (ready_queues s' d p)); (\d p. integrity_ready_queues aag subjects (pasDomainAbs aag d) (ready_queues s' d p) (ready_queues s'' d p)) \ \ (\d p. integrity_ready_queues aag subjects (pasDomainAbs aag d) (ready_queues s d p) (ready_queues s'' d p))" apply (clarsimp simp: integrity_ready_queues_def) apply (metis append_assoc) done lemma tsos_tro: "\\x. integrity_obj aag activate subjects (pasObjectAbs aag x) (kheap s x) (kheap s' x); tcb_states_of_state s' p = Some a; receive_blocked_on ep a; pasObjectAbs aag p \ subjects \ \ tcb_states_of_state s p = Some a" apply (drule_tac x = p in spec) apply (erule integrity_obj.cases, simp_all add: tcb_states_of_state_def get_tcb_def) apply clarsimp apply fastforce apply fastforce done lemma auth_ipc_buffers_tro: "\\x. integrity_obj aag activate subjects (pasObjectAbs aag x) (kheap s x) (kheap s' x); x \ auth_ipc_buffers s' p; pasObjectAbs aag p \ subjects \ \ x \ auth_ipc_buffers s p " apply (drule_tac x = p in spec) apply (erule integrity_obj.cases, simp_all add: tcb_states_of_state_def get_tcb_def auth_ipc_buffers_def split: cap.split_asm arch_cap.split_asm if_split_asm bool.splits) apply fastforce done lemma auth_ipc_buffers_tro_fwd: "\\x. integrity_obj aag activate subjects (pasObjectAbs aag x) (kheap s x) (kheap s' x); x \ auth_ipc_buffers s p; pasObjectAbs aag p \ subjects \ \ x \ auth_ipc_buffers s' p " apply (drule_tac x = p in spec) apply (erule integrity_obj.cases, simp_all add: tcb_states_of_state_def get_tcb_def auth_ipc_buffers_def split: cap.split_asm arch_cap.split_asm if_split_asm bool.splits) apply fastforce done lemma tsos_tro_running: "\\x. integrity_obj aag activate subjects (pasObjectAbs aag x) (kheap s x) (kheap s' x); tcb_states_of_state s p = Some Structures_A.Running; pasObjectAbs aag p \ subjects \ \ tcb_states_of_state s' p = Some Structures_A.Running" apply (drule_tac x = p in spec) apply (erule integrity_obj.cases, simp_all add: tcb_states_of_state_def get_tcb_def indirect_send_def direct_send_def) done lemma integrity_trans: assumes t1: "integrity_subjects subjects aag activate X s s'" and t2: "integrity_subjects subjects aag activate X s' s''" shows "integrity_subjects subjects aag activate X s s''" proof - from t1 have tro1: "\x. integrity_obj aag activate subjects (pasObjectAbs aag x) (kheap s x) (kheap s' x)" unfolding integrity_subjects_def by simp from t2 have tro2: "\x. integrity_obj aag activate subjects (pasObjectAbs aag x) (kheap s' x) (kheap s'' x)" unfolding integrity_subjects_def by simp have intm: "\x. integrity_mem aag subjects x (tcb_states_of_state s) (tcb_states_of_state s'') (auth_ipc_buffers s) X (underlying_memory (machine_state s) x) (underlying_memory (machine_state s'') x)" (is "\x. ?P x s s''") proof fix x from t1 t2 have m1: "?P x s s'" and m2: "?P x s' s''" unfolding integrity_subjects_def by auto from m1 show "?P x s s''" proof cases case trm_lrefl thus ?thesis by (rule integrity_mem.intros) next case trm_globals thus ?thesis by (rule integrity_mem.intros) next case trm_orefl from m2 show ?thesis proof cases case (trm_ipc ep p') show ?thesis proof (rule integrity_mem.trm_ipc) from trm_ipc show "case_option False (receive_blocked_on ep) (tcb_states_of_state s p')" by (fastforce split: option.splits dest: tsos_tro [OF tro1]) from trm_ipc show "x \ auth_ipc_buffers s p'" by (fastforce split: option.splits intro: auth_ipc_buffers_tro [OF tro1]) qed (simp_all add: trm_ipc) qed (auto simp add: trm_orefl intro: integrity_mem.intros) next case trm_write thus ?thesis by (rule integrity_mem.intros) next case (trm_ipc ep p') note trm_ipc1 = trm_ipc from m2 show ?thesis proof cases case trm_orefl thus ?thesis using trm_ipc1 by (auto intro!: integrity_mem.trm_ipc simp add: restrict_map_Some_iff elim!: tsos_tro_running [OF tro2, rotated]) next case (trm_ipc ep' p'') show ?thesis proof (cases "p' = p''") case True thus ?thesis using trm_ipc trm_ipc1 by (simp add: restrict_map_Some_iff) next (* 2 tcbs sharing same IPC buffer, we can appeal to either t1 or t2 *) case False thus ?thesis using trm_ipc1 by (auto intro!: integrity_mem.trm_ipc simp add: restrict_map_Some_iff elim!: tsos_tro_running [OF tro2, rotated]) qed qed (auto simp add: trm_ipc intro: integrity_mem.intros) qed qed moreover have "\x. integrity_device aag subjects x (tcb_states_of_state s) (tcb_states_of_state s'') (device_state (machine_state s) x) (device_state (machine_state s'') x)" (is "\x. ?P x s s''") proof fix x from t1 t2 have m1: "?P x s s'" and m2: "?P x s' s''" unfolding integrity_subjects_def by auto from m1 show "?P x s s''" proof cases case trd_lrefl thus ?thesis by (rule integrity_device.intros) next case torel1: trd_orefl from m2 show ?thesis proof cases case (trd_lrefl) thus ?thesis by (rule integrity_device.trd_lrefl) next case trd_orefl thus ?thesis by (simp add:torel1) next case trd_write thus ?thesis by (rule integrity_device.trd_write) qed next case trd_write thus ?thesis by (rule integrity_device.intros) qed qed thus ?thesis using tro_trans[OF tro1 tro2] t1 t2 intm apply (clarsimp simp add: integrity_subjects_def) apply (drule(1) trcdt_trans[simplified]) apply (drule(1) trcdtlist_trans[simplified]) apply (drule(1) trinterrupts_trans[simplified]) apply (drule(1) trasids_trans[simplified]) apply (drule(1) tre_trans[simplified]) apply (drule(1) trrqs_trans) apply simp done qed lemma integrity_refl [simp]: "integrity_subjects S aag activate X s s" unfolding integrity_subjects_def by simp subsection{* Generic stuff *} (* Tom says that Gene Wolfe says that autarchy \ self authority. *) lemma integrity_update_autarch: "\ integrity aag X st s; is_subject aag ptr \ \ integrity aag X st (s\kheap := kheap s(ptr \ obj)\)" unfolding integrity_subjects_def apply (intro conjI,simp_all) apply clarsimp apply (drule_tac x = x in spec, erule integrity_mem.cases) apply ((auto intro: integrity_mem.intros)+)[4] apply (erule trm_ipc, simp_all) apply (clarsimp simp: restrict_map_Some_iff tcb_states_of_state_def get_tcb_def) apply clarsimp apply (drule_tac x = x in spec, erule integrity_device.cases) apply (erule integrity_device.trd_lrefl) apply (erule integrity_device.trd_orefl) apply (erule integrity_device.trd_write) done lemma set_object_integrity_autarch: "\integrity aag X st and K (is_subject aag ptr)\ set_object ptr obj \\rv. integrity aag X st\" apply (simp add: set_object_def) apply (wp gets_the_wp) apply (rule integrity_update_autarch, simp_all) done lemma tcb_states_of_state_trans_state[simp]: "tcb_states_of_state (trans_state f s) = tcb_states_of_state s" apply (simp add: tcb_states_of_state_def get_tcb_exst_update) done lemma eintegrity_sa_update[simp]: "integrity aag X st (scheduler_action_update f s) = integrity aag X st s" apply (simp add: integrity_subjects_def trans_state_update'[symmetric]) done lemma trans_state_back[simp]: "trans_state (\_. exst s) s = s" by simp declare wrap_ext_op_det_ext_ext_def[simp] crunch integrity[wp]: set_thread_state_ext "integrity aag X st" crunch integrity_autarch: set_thread_state "integrity aag X st" lemmas integrity_def = integrity_subjects_def end context pspace_update_eq begin interpretation Arch . (*FIXME: arch_split*) lemma integrity_update_eq[iff]: "tcb_states_of_state (f s) = tcb_states_of_state s" by (simp add: pspace tcb_states_of_state_def get_tcb_def) end context begin interpretation Arch . (*FIXME: arch_split*) definition label_owns_asid_slot :: "'a PAS \ 'a \ asid \ bool" where "label_owns_asid_slot aag l asid \ (l, Control, pasASIDAbs aag asid) \ pasPolicy aag" definition cap_links_asid_slot :: "'a PAS \ 'a \ cap \ bool" where "cap_links_asid_slot aag l cap \ (\asid \ cap_asid' cap. label_owns_asid_slot aag l asid)" abbreviation is_subject_asid :: "'a PAS \ asid \ bool" where "is_subject_asid aag asid \ pasASIDAbs aag asid = pasSubject aag" lemma clas_no_asid: "cap_asid' cap = {} \ cap_links_asid_slot aag l cap" unfolding cap_links_asid_slot_def by simp definition "cap_links_irq aag l cap \ \irq \ cap_irqs_controlled cap. (l, Control, pasIRQAbs aag irq) \ pasPolicy aag" lemma cli_no_irqs: "cap_irqs_controlled cap = {} \ cap_links_irq aag l cap" unfolding cap_links_irq_def by simp abbreviation is_subject_irq :: "'a PAS \ irq \ bool" where "is_subject_irq aag irq \ pasIRQAbs aag irq = pasSubject aag" definition aag_cap_auth :: "'a PAS \ 'a \ cap \ bool" where "aag_cap_auth aag l cap \ (\x \ obj_refs cap. \auth \ cap_auth_conferred cap. (l, auth, pasObjectAbs aag x) \ pasPolicy aag) \ (\x \ untyped_range cap. (l, Control, pasObjectAbs aag x) \ pasPolicy aag) \ cap_links_asid_slot aag l cap \ cap_links_irq aag l cap" abbreviation pas_cap_cur_auth :: "'a PAS \ cap \ bool" where "pas_cap_cur_auth aag cap \ aag_cap_auth aag (pasSubject aag) cap" crunch integrity_autarch: as_user "integrity aag X st" lemma owns_thread_owns_cspace: "\ is_subject aag thread; pas_refined aag s; get_tcb thread s = Some tcb; is_cnode_cap (tcb_ctable tcb); x \ obj_refs (tcb_ctable tcb)\ \ is_subject aag x" apply (drule get_tcb_SomeD) apply (drule cte_wp_at_tcbI[where t="(thread, tcb_cnode_index 0)" and P="\cap. cap = tcb_ctable tcb", simplified]) apply (auto simp: cte_wp_at_caps_of_state is_cap_simps cap_auth_conferred_def elim: caps_of_state_pasObjectAbs_eq [where p = "(thread, tcb_cnode_index 0)"]) done lemma aag_cdt_link_Control: "\ cdt s x = Some y; pas_refined aag s \ \ (pasObjectAbs aag (fst y), Control, pasObjectAbs aag (fst x)) \ pasPolicy aag" by (fastforce dest: sta_cdt pas_refined_mem pas_refined_Control) lemma is_subject_into_is_subject_asid: "\ cap_links_asid_slot aag (pasObjectAbs aag p) cap; is_subject aag p; pas_refined aag s; asid \ cap_asid' cap \ \ is_subject_asid aag asid" apply (clarsimp simp add: cap_links_asid_slot_def label_owns_asid_slot_def) apply (drule (1) bspec) apply (drule (1) pas_refined_Control) apply simp done (* MOVE *) lemma clas_caps_of_state: "\ caps_of_state s slot = Some cap; pas_refined aag s \ \ cap_links_asid_slot aag (pasObjectAbs aag (fst slot)) cap" apply (clarsimp simp add: cap_links_asid_slot_def label_owns_asid_slot_def pas_refined_def) apply (blast dest: state_asids_to_policy_aux.intros) done lemma as_user_state_vrefs[wp]: "\\s. P (state_vrefs s)\ as_user t f \\rv s. P (state_vrefs s)\" apply (simp add: as_user_def set_object_def split_def) apply wp apply (clarsimp simp: state_vrefs_def vs_refs_no_global_pts_def get_tcb_def elim!: rsubst[where P=P, OF _ ext] split: option.split_asm Structures_A.kernel_object.split) done lemma as_user_tcb_states[wp]: "\\s. P (tcb_states_of_state s)\ as_user t f \\rv s. P (tcb_states_of_state s)\" apply (simp add: as_user_def set_object_def split_def tcb_states_of_state_def) apply wp apply (clarsimp simp: thread_states_def get_tcb_def elim!: rsubst[where P=P, OF _ ext] split: option.split) done lemma as_user_thread_state[wp]: "\\s. P (thread_states s)\ as_user t f \\rv s. P (thread_states s)\" apply (simp add: thread_states_def ) apply wp done lemma as_user_thread_bound_ntfn[wp]: "\\s. P (thread_bound_ntfns s)\ as_user t f \\rv s. P (thread_bound_ntfns s)\" apply (simp add: as_user_def set_object_def split_def thread_bound_ntfns_def) apply (wp get_object_wp) apply (clarsimp simp: thread_states_def get_tcb_def elim!: rsubst[where P=P, OF _ ext] split: option.split) done crunch cdt_preserved[wp]: as_user "\s. P (cdt s)" lemma tcb_domain_map_wellformed_lift: assumes 1: "\P. \\s. P (ekheap s)\ f \\rv s. P (ekheap s)\" shows "\tcb_domain_map_wellformed aag\ f \\rv. tcb_domain_map_wellformed aag\" by (rule 1) lemma as_user_pas_refined[wp]: "\pas_refined aag\ as_user t f \\rv. pas_refined aag\" apply (simp add: pas_refined_def state_objs_to_policy_def) apply (rule hoare_pre) apply wps apply wp apply simp done (* **************************************** *) text{* Random lemmas that belong elsewhere. *} (* FIXME: move *) lemma bang_0_in_set: "xs \ [] \ xs ! 0 \ set xs" apply(fastforce simp: in_set_conv_nth) done (* FIXME: move *) lemma update_one_strg: "((b \ P c v) \ (\ b \ (\v'. f c' = Some v' \ P c v'))) \ ((f(c := if b then Some v else f c')) x = Some y \ f x \ Some y \ P x y)" by auto (* FIXME: move *) lemma hoare_gen_asm2: assumes a: "P \ \\\ f \Q\" shows "\K P\ f \Q\" using a by (fastforce simp: valid_def) (* FIXME: move *) lemma hoare_vcg_all_liftE: "(\x. \P x\ f \Q x\, \Q' x\) \ \\s. \x. P x s\ f \\rv s. \x. Q x rv s\, \\rv s. \x. Q' x rv s\" unfolding validE_def apply (rule hoare_post_imp [where Q = "\v s. \x. case v of Inl e \ Q' x e s | Inr r \ Q x r s"]) apply (clarsimp split: sum.splits) apply (erule hoare_vcg_all_lift) done (* FIXME: eliminate *) lemma hoare_weak_lift_impE: "\P\ f \Q\, \Q'\ \ \\s. R \ P s\ f \\rv s. R \ Q rv s\, \\rv s. R \ Q' rv s\" by (rule wp_throw_const_impE) (* FIXME: move *) lemma hoare_use_ex_R: "(\x. \P x and Q \ f \R\, -) \ \\s. (\x. P x s) \ Q s \ f \R\, -" unfolding validE_R_def validE_def valid_def by fastforce (* FIXME: move *) lemma mapM_x_and_const_wp: assumes f: "\v. \P and K (Q v)\ f v \\rv. P\" shows "\P and K (\v \ set vs. Q v)\ mapM_x f vs \\rv. P\" apply (induct vs) apply (simp add: mapM_x_Nil) apply (simp add: mapM_x_Cons) apply (wp f | assumption | simp)+ done (* stronger *) (* FIXME: MOVE *) lemma ep_queued_st_tcb_at': "\P. \ko_at (Endpoint ep) ptr s; (t, rt) \ ep_q_refs_of ep; valid_objs s; sym_refs (state_refs_of s); \pl. P (Structures_A.BlockedOnSend ptr pl) \ P (Structures_A.BlockedOnReceive ptr) \ \ st_tcb_at P t s" apply (case_tac ep, simp_all) apply (frule(1) sym_refs_ko_atD, clarsimp, erule (1) my_BallE, clarsimp simp: st_tcb_at_def refs_of_rev elim!: obj_at_weakenE)+ done (* Sometimes we only care about one of the queues. *) (* FIXME: move *) lemma ep_rcv_queued_st_tcb_at: "\P. \ko_at (Endpoint ep) epptr s; (t, EPRecv) \ ep_q_refs_of ep; valid_objs s; sym_refs (state_refs_of s); P (Structures_A.BlockedOnReceive epptr); kheap s' t = kheap s t\ \ st_tcb_at P t s'" apply (case_tac ep, simp_all) apply (subgoal_tac "st_tcb_at P t s") apply (simp add: st_tcb_at_def obj_at_def) apply (frule(1) sym_refs_ko_atD, clarsimp, erule (1) my_BallE, clarsimp simp: st_tcb_at_def refs_of_rev elim!: obj_at_weakenE)+ done (* FIXME: move. *) lemma ntfn_queued_st_tcb_at': "\P. \ko_at (Notification ntfn) ntfnptr s; (t, rt) \ ntfn_q_refs_of (ntfn_obj ntfn); valid_objs s; sym_refs (state_refs_of s); P (Structures_A.BlockedOnNotification ntfnptr) \ \ st_tcb_at P t s" apply (case_tac "ntfn_obj ntfn", simp_all) apply (frule(1) sym_refs_ko_atD) apply (clarsimp) apply (erule_tac y="(t, NTFNSignal)" in my_BallE, clarsimp) apply (clarsimp simp: pred_tcb_at_def refs_of_rev elim!: obj_at_weakenE)+ done (* FIXME: move *) lemma case_prod_wp: "(\a b. x = (a, b) \ \P a b\ f a b \Q\) \ \P (fst x) (snd x)\ case_prod f x \Q\" by (cases x, simp) (* FIXME: move *) lemma case_sum_wp: "\ (\a. x = Inl a \ \P a\ f a \Q\); (\a. x = Inr a \ \P' a\ g a \Q\) \ \ \\s. (\a. x = Inl a \ P a s) \ (\a. x = Inr a \ P' a s)\ case_sum f g x \Q\" by (cases x, simp_all) (* MOVE *) crunch arm_asid_table_inv [wp]: store_pte "\s. P (arm_asid_table (arch_state s))" lemma st_tcb_at_to_thread_states: "st_tcb_at P t s \ \st. P st \ thread_states s t = tcb_st_to_auth st" by (fastforce simp: st_tcb_def2 thread_states_def tcb_states_of_state_def) lemma aag_Control_into_owns: "\ aag_has_auth_to aag Control p; pas_refined aag s \ \ is_subject aag p" apply (drule (1) pas_refined_Control) apply simp done lemma aag_has_Control_iff_owns: "pas_refined aag s \ (aag_has_auth_to aag Control x) = (is_subject aag x)" apply (rule iffI) apply (erule (1) aag_Control_into_owns) apply (simp add: pas_refined_refl) done lemma aag_Control_owns_strg: "pas_wellformed aag \ is_subject aag v \ aag_has_auth_to aag Control v" by (clarsimp simp: aag_wellformed_refl) (* **************************************** *) subsection {* Policy entailments *} lemma owns_ep_owns_receivers: "\ (\auth. aag_has_auth_to aag auth epptr); pas_refined aag s; invs s; ko_at (Endpoint ep) epptr s; (t, EPRecv) \ ep_q_refs_of ep\ \ is_subject aag t" apply (drule (1) ep_rcv_queued_st_tcb_at [where P = "receive_blocked_on epptr"]) apply clarsimp apply clarsimp apply clarsimp apply (rule refl) apply (drule st_tcb_at_to_thread_states) apply (clarsimp simp: receive_blocked_on_def2) apply (drule spec [where x = Grant]) apply (frule aag_wellformed_grant_Control_to_recv [OF _ _ pas_refined_wellformed]) apply (rule pas_refined_mem [OF sta_ts]) apply fastforce apply assumption+ apply (erule (1) aag_Control_into_owns) done (* MOVE *) lemma cli_caps_of_state: "\ caps_of_state s slot = Some cap; pas_refined aag s \ \ cap_links_irq aag (pasObjectAbs aag (fst slot)) cap" apply (clarsimp simp add: cap_links_irq_def pas_refined_def) apply (blast dest: state_irqs_to_policy_aux.intros) done (* MOVE *) lemma cap_auth_caps_of_state: "\ caps_of_state s p = Some cap; pas_refined aag s \ \ aag_cap_auth aag (pasObjectAbs aag (fst p)) cap" unfolding aag_cap_auth_def apply (intro conjI) apply clarsimp apply (drule (2) sta_caps) apply (drule_tac f="pasObjectAbs aag" in auth_graph_map_memI[OF _ refl refl]) apply (fastforce simp: pas_refined_def) apply clarsimp apply (drule (2) sta_untyped [THEN pas_refined_mem] ) apply simp apply (drule (1) clas_caps_of_state) apply simp apply (drule (1) cli_caps_of_state) apply simp done lemma cap_cur_auth_caps_of_state: "\ caps_of_state s p = Some cap; pas_refined aag s; is_subject aag (fst p) \ \ pas_cap_cur_auth aag cap" by (metis cap_auth_caps_of_state) lemmas new_range_subset' = aligned_range_offset_subset lemmas ptr_range_subset = new_range_subset' [folded ptr_range_def] lemma pbfs_less_wb: "pageBitsForSize x < word_bits" by (cases x, simp_all add: word_bits_def) lemma ipcframe_subset_page: "\valid_objs s; get_tcb p s = Some tcb; tcb_ipcframe tcb = cap.ArchObjectCap (arch_cap.PageCap d p' R vms xx); x \ ptr_range (p' + (tcb_ipc_buffer tcb && mask (pageBitsForSize vms))) msg_align_bits \ \ x \ ptr_range p' (pageBitsForSize vms)" apply (frule (1) valid_tcb_objs) apply (clarsimp simp add: valid_tcb_def ran_tcb_cap_cases) apply (erule set_mp[rotated]) apply (rule ptr_range_subset) apply (simp add: valid_cap_def cap_aligned_def) apply (simp add: valid_tcb_def valid_ipc_buffer_cap_def is_aligned_andI1 split:bool.splits) apply (rule order_trans [OF _ pbfs_atleast_pageBits]) apply (simp add: msg_align_bits pageBits_def) apply (rule and_mask_less') apply (simp add: pbfs_less_wb [unfolded word_bits_conv]) done lemma trm_ipc': "\ pas_refined aag s; valid_objs s; case_option False (receive_blocked_on ep) (tcb_states_of_state s p'); (tcb_states_of_state s' p') = Some Structures_A.Running; p \ auth_ipc_buffers s p' \ \ integrity_mem aag subjects p (tcb_states_of_state s) (tcb_states_of_state s') (auth_ipc_buffers s) X (underlying_memory (machine_state s) p) (underlying_memory (machine_state s') p)" apply (cases "pasObjectAbs aag p' \ subjects") apply (rule trm_write) apply (clarsimp simp: auth_ipc_buffers_member_def) apply (frule pas_refined_mem[rotated]) apply (erule sta_caps, simp) apply (erule(3) ipcframe_subset_page) apply (simp add: cap_auth_conferred_def vspace_cap_rights_to_auth_def is_page_cap_def) apply fastforce apply fastforce apply (erule (3) trm_ipc) done lemma integrity_mono: "\ integrity_subjects S aag activate X s s'; S \ T; pas_refined aag s; valid_objs s \ \ integrity_subjects T aag activate X s s'" apply (clarsimp simp: integrity_subjects_def) apply (rule conjI) apply clarsimp apply (drule_tac x=x in spec)+ apply (erule integrity_obj.cases[OF _ integrity_obj.intros], auto simp: tcb_bound_notification_reset_integrity_def indirect_send_def direct_send_def)[1] apply (blast intro: tro_asidpool_clear) apply (rule conjI) apply clarsimp apply (drule_tac x=x in spec)+ apply (erule integrity_eobj.cases, auto intro: integrity_eobj.intros)[1] apply (rule conjI) apply clarsimp apply (drule_tac x=x in spec, erule integrity_mem.cases, (blast intro: integrity_mem.intros trm_ipc')+)[1] apply (rule conjI) apply clarsimp apply (drule_tac x=x in spec, erule integrity_device.cases, (blast intro: integrity_device.intros)+)[1] apply (simp add: integrity_cdt_list_def) apply (rule conjI) apply (fastforce simp: integrity_cdt_def) apply (rule conjI) apply clarsimp apply (blast intro: weaken_filter_eq[where P="\x. pasObjectAbs aag (fst x) \ S"]) (* be more manual here to make this part of the proof much faster *) apply (rule conjI) apply (fastforce simp: integrity_interrupts_def) apply (rule conjI) apply (fastforce simp: integrity_asids_def) apply (clarsimp simp: integrity_ready_queues_def) apply blast done abbreviation "einvs \ invs and valid_list and valid_sched" end end