Gneiss A nice component framework in SPARK Johannes Kliemann FOSDEM, Brussels, 2020-02-02
Component-based Architectures Trusted Components ■ Can’t reimplement everything ■ Solution: software reuse Protocol validator ▪ Untrusted software (gray) (e.g. TLS) ▪ Policy object (green) ▪ Client software (orange) ■ Policy and proxy components Network Web ▪ Formally verified Stack browser ▪ Limited complexity 2020-02-02 2
Ensuring Correctness Prerequisites ■ Reusability ■ Correctness by proof ▪ Proofs require effort ▪ Absence of runtime errors ▪ Abstraction from actual platform ▪ Functional correctness ■ Provability ■ Tools ▪ Formal specification ▪ Formalization language ▪ Manageable complexity ▪ Mapping between implementation and proof ▪ Deterministic behaviour 2020-02-02 3
Correctness by Proof and Tools SPARK ■ Programming Language function Abs (I : Integer) return Integer ▪ Based on Ada with ▪ Compilable with GCC and LLVM Pre => I > Integer’First, Post => Abs’Result >= 0; ▪ Customizable runtime ▪ Contracts (preconditions, procedure Inc postconditions, invariants) (I : in out Integer) ■ Verification Toolset with Pre => I < Integer’Last, ▪ Absence of runtime errors Post => I = I’Old + 1, ▪ Functional correctness Global => null; 2020-02-02 4
Provability and Reusability Gneiss ■ Reusability ■ Provability ▪ Platform abstraction ▪ Platform formalization ▪ Interface mappable to multiple ▪ Assumptions coarse enough to different semantics be valid on multiple platforms ▪ Only dependencies satisfiable by ▪ Assumptions strong enough to all platforms ease proving 2020-02-02 5
Example: Block Client 2020-02-02 6
Block Devices Client Interface ■ Block device ▪ Storage device of equally sized blocks ■ Create packet descriptor ▪ Block size is typically 512 or ■ Allocate memory for request 4096 bytes ■ (write data) ■ Packet descriptor ■ Send request to block device ▪ Starting block number ■ Receive answer from block device ▪ Amount of blocks ■ (read data) ▪ Read/Write/Sync/Trim ▪ Memory location 2020-02-02 7
Gneiss Block Client Formalizing properties ■ Formalize properties of platform packet = Packet_descriptor( API WRITE, start, count); ▪ Packet object is needed try { ▪ Packet object can always be packet.alloc_packet( initialized block_size * count); ▪ Request memory must be if(ready_to_submit()){ allocated separately submit(packet); } ▪ Memory allocation might fail catch (Alloc_Error) { } ▪ Submitting must be checked ▪ Submitting works always if ready 2020-02-02 8
Gneiss Block Client Formalizing properties type Packet is record Start : Natural; ■ Define packet type Length : Positive; ▪ No exceptions, allocation Op : Operation; success is a property Allocated : Boolean; end record; ■ Define precondition from function Ready return Boolean; formalized properties procedure Submit (P : Packet) ▪ Packet must be allocated with ▪ And the platform must be ready Pre => P.Allocated and then Ready; 2020-02-02 9
Gneiss Block Client Formalizing properties ■ Packet properties can be changed by the programmer P := Packet’(Start => 0, ▪ Allocation status can be set Length => 1, without actually successfully Op => READ, allocating Allocated => True); ▪ Packet can be submitted multiple if P.Allocated and then Ready times then Submit (P); ■ Submit does not change the Submit (P); platform state end if; ▪ Calling Submit should invalidate Ready 2020-02-02 10
Gneiss Block Client Formalizing properties type Packet is limited private; type Packet_State is ■ Use state enum instead of (Empty, Allocated); boolean function Create ■ Encapsulate Packet type (Start : Natural; Length : Positive; ▪ Can only be changed by platform Op : Operation) calls return Packet ▪ Can only be created in state with Empty Post => State (Create’Result) = Empty; ▪ Cannot be copied ( limited ) function State (P : Packet) return Packet_State; 2020-02-02 11
Gneiss Block Client Formalizing properties function Ready return Boolean with ■ Submit changes packet state Global => (Input => Platform); ■ Submit changes platform state procedure Submit ▪ Ready depends on platform (P : in out Packet) with state Pre => State (P) = Allocated ▪ Once Submit is called, Ready and then Ready, must be checked again Post => State (P) = Empty, Global => (In_Out => Platform); 2020-02-02 12
Gneiss Block Client A Second Platform ■ write might fail ▪ ENOSYS (not implemented) struct block_packet packet = {0, 1, WRITE, 0}; ▪ EINVAL (wrong argument) int result; ▪ EFBIG (offset out of file) packet.ptr = malloc ▪ EBADF (bad file descriptor) (block_size * packet.len); ▪ EAGAIN (out of resources) if(packet.ptr){ result = write(fd, &packet); ■ No way to make sure it } succeeds, submit must be able to fail, too 2020-02-02 13
Gneiss Block Client A Second Platform procedure Submit (P : in out Packet) ■ Submit must be able to fail with ▪ It might change the packet state Pre => or leave it as is State (P) = Allocated, Post => ▪ An unsuccessfully submitted State (P) in packet can be submitted again Empty | Allocated, Global => (In_Out => Platform); 2020-02-02 14
Gneiss Block Client Adapting the first platform procedure Submit ■ Both platforms have different (P : in out Packet) semantics is ■ The second platform cannot be begin expressed with the first one if Ready then Submit_Native (P); ■ But the first one can be expressed end if; with the second one end Submit; 2020-02-02 15
Gneiss Summary ■ Multiple platforms ▪ Genode ■ Asynchronous, event based ▪ Linux ■ Supports capabilities ▪ Muen ■ Callbacks via generics ■ Interfaces ■ Limited dynamic resource allocation ▪ Log client/server ▪ Platform dependent ▪ Block client/server ■ No memory pressure ▪ Timer client ■ No aliasing ▪ Message client/server ▪ Shared memory 2020-02-02 16
Questions? Johannes Kliemann kliemann@componolit.com @Componolit · componolit.com · github.com/Componolit 2020-02-02 17
Recommend
More recommend