Digital Security by Design: Formal Verification with Broad-Spectrum ANSI-C Reference Specifications - Tom Melham, Andreas Tiemeyer, Daniel Kroening, University of Oxford & John O’Leary, Intel Corporation
KTN ran a collaborators' workshop on 26 September 2019 in London to explain more about the Digital Security by Design Challenge announced by the government.
The Digital Security by Design challenge has been recently announced by the Department for Business, Energy & Industrial Strategy (BEIS). This challenge, amounting to £70 million of government funding over 5 years, was delivered by UK Research and Innovation (UKRI) through the Industrial Strategy Challenge Fund (ISCF).
This Collaborators' Workshop provides an opportunity to hear more details of the challenge and forthcoming competitions.
A Scoping Workshop for this challenge was held on 30th May: http://ow.ly/oz6230pHlGl
Find out more about the Defence and Security Interest Group at https://ktn-uk.co.uk/interests/defence-security
Join the Defence and Security Interest Group at https://www.linkedin.com/groups/8584397 or Follow KTN_UK Defence group on Twitter https://twitter.com/KTNUK_Defence
Similar Characteristics of Internal Software Quality Attributes for Object-Or...
Similar to Digital Security by Design: Formal Verification with Broad-Spectrum ANSI-C Reference Specifications - Tom Melham, Andreas Tiemeyer, Daniel Kroening, University of Oxford & John O’Leary, Intel Corporation
Similar to Digital Security by Design: Formal Verification with Broad-Spectrum ANSI-C Reference Specifications - Tom Melham, Andreas Tiemeyer, Daniel Kroening, University of Oxford & John O’Leary, Intel Corporation (20)
Digital Security by Design: Formal Verification with Broad-Spectrum ANSI-C Reference Specifications - Tom Melham, Andreas Tiemeyer, Daniel Kroening, University of Oxford & John O’Leary, Intel Corporation
2. Verification of Tree-Based Hierarchical
Read-Copy Update in the Linux Kernel
Lihao Liang
University of Oxford
Paul E. McKenney
IBM Linux Technology Center
Daniel Kroening and Tom Melham
University of Oxford
Abstract—Read-Copy Update (RCU) is a scalable, high-
performance Linux-kernel synchronization mechanism that runs
low-overhead readers concurrently with updaters. Production-
quality RCU implementations are decidedly non-trivial and their
stringent validation is mandatory. This suggests use of formal
verification. Previous formal verification efforts for RCU either
focus on simple implementations or use modeling languages. In
this paper, we construct a model directly from the source code
of Tree RCU in the Linux kernel, and use the CBMC program
analyzer to verify its safety and liveness properties. To the best
of our knowledge, this is the first verification of a significant part
of RCU’s source code—an important step towards integration of
formal verification into the Linux kernel’s regression test suite.
I. INTRODUCTION
The Linux operating system kernel [1] is widely used,
for example in servers, safety-critical embedded systems,
household appliances, and mobile devices. Over the past 25
years, many technologies have been added to the Linux kernel,
one example being Read-Copy Update (RCU) [2].
RCU is a synchronization mechanism used to replace reader-
writer locks in read-mostly scenarios, allowing low-overhead
readers to run concurrently with updaters. Production-quality
implementations for multi-core systems must provide excellent
scalability, high throughput, low latency, modest memory
footprint, excellent energy efficiency, and reliable response
to CPU hotplug operations. They must therefore avoid cache
misses, lock contention, frequent updates to shared variables,
and excessive use of atomic read-modify-write and memory-
barrier instructions. Finally, implementations must cope with
the extremely diverse workloads and platforms of Linux [3].
RCU is now widely used in the Linux-kernel networking,
device-driver, and file-storage subsystems [3], [4]. There are
at least 75 million Linux servers [5] and 1.4 billion Android
devices [6], so a “million-year” bug can occur several times
per day across the installed base. Stringent validation of RCU’s
complex implementation is thus critically important.
Formal verification has already been applied to some aspects
of RCU design, including Tiny RCU [7], userspace RCU [8],
sysidle [7], and interactions between dyntick-idle and non-
maskable interrupts (NMIs) [9]. But these efforts either validate
trivial single-CPU RCU implementations in C or use special-
of special-purpose modeling languages is difficult and error-
prone translation from source code. Other research has done
manual proof of simple RCU implementations [11], [12], but
this requires significant effort beyond translation. Linux kernel
releases are only about 60 days apart, and RCU changes with
each release. So any manual work must be replicated about
six times a year.
If formal verification is to be part of Linux-kernel RCU’s
regression suite, it must be scalable and automated. This
paper describes how to build a model directly from the Linux
kernel source code, and use the C Bounded Model Checker
(CBMC) [13] to verify RCU’s safety and liveness properties.
II. BACKGROUND
RCU is used in read-mostly situations. Readers run concur-
rently with updaters, so RCU maintains multiple versions of
objects and ensures they are not freed until all pre-existing
readers complete, after a grace period elapses. The idea is
to split updates into removal and reclamation phases [2]. The
removal phase makes objects inaccessible to readers, waits
during the grace period, and then reclaims them. Grace periods
need wait only for readers whose runtime overlaps the removal
phase. Readers starting after the removal phase ends cannot
hold references to any removed objects and thus cannot be
disrupted by objects being freed during the reclamation phase.
Modern CPUs guarantee that writes to single aligned pointers
are atomic, so readers see either the old or new version of
a data structure. This enables atomic insertions, deletions,
and replacements in a linked structure. Readers can then
avoid expensive atomic operations, memory barriers, and cache
misses. In the most aggressive configurations of Linux-kernel
RCU, readers use the same sequence of instructions that would
be used in a single-threaded implementation, providing RCU
readers with excellent performance and scalability.
A. Core RCU API Usage
The core API has five primitives [3], which we now introduce.
A read-side critical section begins with rcu read lock()
and ends with rcu read unlock(). When nested, they are
flattened into one critical section. Within a critical section, it
A Tool for Checking ANSI-C Programs
Edmund Clarke, Daniel Kroening, and Flavio Lerda
Carnegie Mellon University
Abstract. We present a tool for the formal verification of ANSI-C pro-
grams using Bounded Model Checking (BMC). The emphasis is on us-
ability: the tool supports almost all ANSI-C language features, including
pointer constructs, dynamic memory allocation, recursion, and the float
and double data types. From the perspective of the user, the verification
is highly automated: the only input required is the BMC bound. The
tool is integrated into a graphical user interface. This is essential for pre-
senting long counterexample traces: the tool allows stepping through the
trace in the same way a debugger allows stepping through a program.
1 Introduction
We present a tool that uses Bounded Model Checking to reason about low-level
ANSI-C programs. There are two applications of the tool: 1) the tool checks
safety properties such as the correctness of pointer constructs, and 2) the tool
can compare an ANSI-C program with another design, such as a circuit given in
Verilog.
Many safety-critical software systems are legacy designs, i.e., written in a low
level language such as ANSI-C or even assembly language, or at least contain
components that are written in this manner. Furthermore, very often perfor-
mance requirements enforce the use of these languages. These systems are a big-
ger security and safety problem than programs written in high level languages.
The high level languages are usually easier to verify, as they enforce type-safety,
for example. The verification of low level ANSI-C code is challenging due to the
extensive use of arithmetic, pointers, pointer arithmetic, and bit-wise operators.
We describe a tool that formally verifies ANSI-C programs. The properties
checked include pointer safety, array bounds, and user-provided assertions. The
tool implements a technique called Bounded Model Checking (BMC) [1]. In
BMC, the transition relation for a complex state machine and its specification
are jointly unwound to obtain a Boolean formula that is satisfiable if there exists
an error trace. The formula is then checked by using a SAT procedure. If the
formula is satisfiable, a counterexample is extracted from the output of the SAT
procedure. The tool checks that sufficient unwinding is done to ensure that no
longer counterexample can exist by means of unwinding assertions.
The tool comes with a graphical user interface (GUI) that hides the imple-
mentation details from the user. It resembles tools already well-known to soft-
ware engineers. If a counterexample is found, the GUI allows stepping through
the trace like a debugger. We hope to make formal verification tools accessible
to non-expert users this way.
K. Jensen and A. Podelski (Eds.): TACAS 2004, LNCS 2988, pp. 168–176, 2004.
c⃝ Springer-Verlag Berlin Heidelberg 2004
Formal Co-Validation of Low-Level
Hardware/Software Interfaces
Alex Horn⇤, Michael Tautschnig⇤, Celina Val†, Lihao Liang⇤,
Tom Melham⇤, Jim Grundy‡, Daniel Kroening⇤
⇤University of Oxford †University of British Columbia ‡Intel Corporation
Abstract—Today’s microelectronics industry is increasingly
confronted with the challenge of developing and validating
software that closely interacts with hardware. These interactions
make it difficult to design and validate the hardware and
software separately; instead, a verifiable co-design is required
that takes them into account. This paper demonstrates a new
approach to co-validation of hardware/software interfaces by
formal, symbolic co-execution of an executable hardware model
combined with the software that interacts with it. We illustrate
and evaluate our technique on three realistic benchmarks in
which software I/O is subject to hardware-specific protocol rules:
a real-time clock, a temperature sensor on an I2
C bus, and an
Ethernet MAC. We provide experimental results that show our
approach is both feasible as a bug-finding technique and scales
to handle a significant degree of concurrency in the combined
hardware/software model.
I. INTRODUCTION
A growing problem for today’s microelectronics industry is
co-design of hardware alongside embedded, low-level software
that closely interacts with it. In particular, semiconductor
designs are witnessing an increased use of on-chip micro-
controllers running firmware to implement functionality that
would formerly have been implemented in hardware. This trend
is driven by factors that include the following:
• Extracting the control of complex devices and implement-
ing it in firmware can cut development schedules while
adding flexibility and survivability.
• By making on-chip devices more capable, work can
be shifted away from the CPU, where performance is
increasingly hard-won. The richer control required for
more capable devices further drives the trend.
The sorts of devices that are typically integrated on-chip are
controllers for power management, hardware with sequestered
functionality for remote management or secure content, and
increasingly capable graphics processors.
Co-design and validation of such devices together with
their firmware, with the predictability needed to schedule
fabrication and hit market windows, has become an acute
challenge. Similar challenges arise in developing firmware for
systems on chip (SoCs) and general embedded systems [1].
Firmware is just hardware-specific software. One might
therefore expect that the problem can be addressed by some
combination of today’s separate techniques for design and
verification of hardware and software. But the results of
Supported by ERC project 280053 and EPSRC project EP/H017585/1.
this approach are disappointing. The problem is the complex
nature of the interactions at the hardware/software interfaces.
All large systems are structured into subsystems, but the
interfaces between hardware and software subsystems are more
problematic than those in a homogeneous system.
• In a homogeneous design, the documentation of interfaces
(say by header files) is both understandable by developers
and processable by tools. A compiler, for example, can
guarantee some consistency in how two modules view a
shared interface. But hardware and software are typically
described in different languages, processed by separate
tool chains. And the hardware and software design teams
have their own descriptions of the interfaces they share,
with little to ensure the two are consistent.
• The mechanisms for invoking functionality and sharing
data among modules in a homogeneous system, particu-
larly in software, are relatively few. In contrast, the means
of passing information between hardware and software
are varied and built up from nonstandard primitives that
may include interrupts, memory-mapped I/O, and special-
purpose registers. The situation is analogous to software
before procedure-calling conventions were standardized.
• The hardware/software interface also marks a boundary
between different threads of concurrent execution. Without
the shared understanding of synchronization that follows
from a common language and library, concurrency at the
hardware/software interface needs special treatment.
• Finally, a hardware/software interface almost always marks
a boundary between different teams, working in different
parts of a company and having different educational
backgrounds and skills. The scope for misunderstanding
is greater than usual.
The challenges faced by those implementing the two sides
of a hardware/software interface are high—but so is the need
to get it right. Building a system with a new interface and then
testing it to find and remove bugs is a perilous practice. When
designers move the control from a complex hardware device
into firmware, the stripped-down hardware can be difficult to
test without a means to run the firmware. Testing the hardware
and firmware together is difficult before silicon is fabricated:
simulators are slow, emulators expensive, and FPGAs limited
in capacity. Delaying extensive testing until silicon is available
is unacceptable as it serializes the development of hardware
and software to the point where it can be difficult to meet the
Low-Level Code and HW/SW Verification
2010 2011 2012 2013 2014 2015 2016 2017
Intel: Effective Validation of Firmware
HW/SW Co-Verification via Directed
Trace Partitioning
2018 2019
Methodology and Abstraction for
System-Level HW/SW Co-Verification
CBMC