17 research outputs found
Dijkstra monads for all
This paper proposes a general semantic framework for verifying programs with arbitrary monadic side-effects using Dijkstra monads, which we define as monad-like structures indexed by a specification monad. We prove that any monad morphism between a computational monad and a specification monad gives rise to a Dijkstra monad, which provides great flexibility for obtaining Dijkstra monads tailored to the verification task at hand. We moreover show that a large variety of specification monads can be obtained by applying monad transformers to various base specification monads, including predicate transformers and Hoare-style pre- and postconditions. For defining correct monad transformers, we propose a language inspired by Moggi's monadic metalanguage that is parameterized by a dependent type theory. We also develop a notion of algebraic operations for Dijkstra monads, and start to investigate two ways of also accommodating effect handlers. We implement our framework in both Coq and F*, and illustrate that it supports a wide variety of verification styles for effects such as exceptions, nondeterminism, state, input-output, and general recursion
Reaching for the Star: Tale of a Monad in Coq
Monadic programming is an essential component in the toolbox of functional programmers. For the pure and total programmers, who sometimes navigate the waters of certified programming in type theory, it is the only means to concisely implement the imperative traits of certain algorithms. Monads open up a portal to the imperative world, all that from the comfort of the functional world. The trend towards certified programming within type theory begs the question of reasoning about such programs. Effectful programs being encoded as pure programs in the host type theory, we can readily manipulate these objects through their encoding. In this article, we pursue the idea, popularized by Maillard [Kenji Maillard, 2019], that every monad deserves a dedicated program logic and that, consequently, a proof over a monadic program ought to take place within a Floyd-Hoare logic built for the occasion. We illustrate this vision through a case study on the SimplExpr module of CompCert [Xavier Leroy, 2009], using a separation logic tailored to reason about the freshness of a monadic gensym
Securing Verified IO Programs Against Unverified Code in F*
We introduce SCIO*, a formally secure compilation framework for statically
verified partial programs performing input-output (IO). The source language is
an F* subset in which a verified program interacts with its IO-performing
context via a higher-order interface that includes refinement types as well as
pre- and post-conditions about past IO events. The target language is a smaller
F* subset in which the compiled program is linked with an adversarial context
that has an interface without refinement types, pre-conditions, or concrete
post-conditions. To bridge this interface gap and make compilation and linking
secure we propose a formally verified combination of higher-order contracts and
reference monitoring for recording and controlling IO operations. Compilation
uses contracts to convert the logical assumptions the program makes about the
context into dynamic checks on each context-program boundary crossing. These
boundary checks can depend on information about past IO events stored in the
state of the monitor. But these checks cannot stop the adversarial target
context before it performs dangerous IO operations. Therefore linking in SCIO*
additionally forces the context to perform all IO actions via a secure IO
library, which uses reference monitoring to dynamically enforce an access
control policy before each IO operation. We prove in F* that SCIO* soundly
enforces a global trace property for the compiled verified program linked with
the untrusted context. Moreover, we prove in F* that SCIO* satisfies by
construction Robust Relational Hyperproperty Preservation, a very strong secure
compilation criterion. Finally, we illustrate SCIO* at work on a simple web
server example.Comment: POPL'24 camera-ready versio
Extending Equational Monadic Reasoning with Monad Transformers
There is a recent interest for the verification of monadic programs using proof assistants. This line of research raises the question of the integration of monad transformers, a standard technique to combine monads. In this paper, we extend Monae, a Coq library for monadic equational reasoning, with monad transformers and we explain the benefits of this extension. Our starting point is the existing theory of modular monad transformers, which provides a uniform treatment of operations. Using this theory, we simplify the formalization of models in Monae and we propose an approach to support monadic equational reasoning in the presence of monad transformers. We also use Monae to revisit the lifting theorems of modular monad transformers by providing equational proofs and explaining how to patch a known bug using a non-standard use of Coq that combines impredicative polymorphism and parametricity
Interaction Tree Specifications: A Framework for Specifying Recursive, Effectful Computations That Supports Auto-Active Verification
This paper presents a specification framework for monadic, recursive, interactive programs that supports auto-active verification, an approach that combines user-provided guidance with automatic verification techniques. This verification tool is designed to have the flexibility of a manual approach to verification along with the usability benefits of automatic approaches. We accomplish this by augmenting Interaction Trees, a Coq datastructure for representing effectful computations, with logical quantifier events. We show that this yields a language of specifications that are easy to understand, automatable, and are powerful enough to handle properties that involve non-termination. Our framework is implemented as a library in Coq. We demonstrate the effectiveness of this framework by verifying real, low-level code
Reasoning about the garden of forking paths
Lazy evaluation is a powerful tool for functional programmers. It enables the
concise expression of on-demand computation and a form of compositionality not
available under other evaluation strategies. However, the stateful nature of
lazy evaluation makes it hard to analyze a program's computational cost, either
informally or formally. In this work, we present a novel and simple framework
for formally reasoning about lazy computation costs based on a recent model of
lazy evaluation: clairvoyant call-by-value. The key feature of our framework is
its simplicity, as expressed by our definition of the clairvoyance monad. This
monad is both simple to define (around 20 lines of Coq) and simple to reason
about. We show that this monad can be effectively used to mechanically reason
about the computational cost of lazy functional programs written in Coq.Comment: 28 pages, accepted by ICFP'2
Formalizing, Verifying and Applying ISA Security Guarantees as Universal Contracts
Progress has recently been made on specifying instruction set architectures
(ISAs) in executable formalisms rather than through prose. However, to date,
those formal specifications are limited to the functional aspects of the ISA
and do not cover its security guarantees. We present a novel, general method
for formally specifying an ISAs security guarantees to (1) balance the needs of
ISA implementations (hardware) and clients (software), (2) can be
semi-automatically verified to hold for the ISA operational semantics,
producing a high-assurance mechanically-verifiable proof, and (3) support
informal and formal reasoning about security-critical software in the presence
of adversarial code. Our method leverages universal contracts: software
contracts that express bounds on the authority of arbitrary untrusted code.
Universal contracts can be kept agnostic of software abstractions, and strike
the right balance between requiring sufficient detail for reasoning about
software and preserving implementation freedom of ISA designers and CPU
implementers. We semi-automatically verify universal contracts against Sail
implementations of ISA semantics using our Katamaran tool; a semi-automatic
separation logic verifier for Sail which produces machine-checked proofs for
successfully verified contracts. We demonstrate the generality of our method by
applying it to two ISAs that offer very different security primitives: (1)
MinimalCaps: a custom-built capability machine ISA and (2) a (somewhat
simplified) version of RISC-V with PMP. We verify a femtokernel using the
security guarantee we have formalized for RISC-V with PMP
Verifying Programs with Logic and Extended Proof Rules: Deep Embedding v.s. Shallow Embedding
Many foundational program verification tools have been developed to build
machine-checked program correctness proofs, a majority of which are based on
Hoare logic. Their program logics, their assertion languages, and their
underlying programming languages can be formalized by either a shallow
embedding or a deep embedding. Tools like Iris and early versions of Verified
Software Toolchain (VST) choose different shallow embeddings to formalize their
program logics. But the pros and cons of these different embeddings were not
yet well studied. Therefore, we want to study the impact of the program logic's
embedding on logic's proof rules in this paper. This paper considers a set of
useful extended proof rules, and four different logic embeddings: one deep
embedding and three common shallow embeddings. We prove the validity of these
extended rules under these embeddings and discuss their main challenges.
Furthermore, we propose a method to lift existing shallowly embedded logics to
deeply embedded ones to greatly simplify proofs of extended rules in specific
proof systems. We evaluate our results on two existing verification tools. We
lift the originally shallowly embedded VST to our deeply embedded VST to
support extended rules, and we implement Iris-CF and deeply embedded Iris-Imp
based on the Iris framework to evaluate our theory in real verification
projects