AdaCore Tech Cyber Security Web
AdaCore Tech Cyber Security Web
Cyber Security
Roderick Chapman and Yannick Moy
Version 1.0
May 2018
i
About the Authors
Roderick Chapman
Dr. Roderick Chapman is an independent consulting engineer with more
than 20 years of experience in the development and certification of
critical software. Following graduation from the University of York in the
U.K., Rod joined Praxis (now Altran UK), and contributed to many of the
company’s keynote projects, rising to the role of principal engineer for
software process and design. He also led the programming language and
verification research group at Praxis, leading the technical development,
training, sales and marketing of the SPARK product line. Rod is a regular
speaker at international conferences, and he is widely recognized as a
leading authority on high integrity software development, programming
language design, and software verification tools. In February 2015, Rod
was appointed Honorary Visiting Professor in the Department of
Computer Science at the University of York.
Yannick Moy
Dr. Yannick Moy is a Senior Software Engineer at AdaCore and co-
director of the ProofInUse joint laboratory with INRIA (France). At
AdaCore, he works on the software source code analyzers CodePeer and
SPARK Pro, which are tools that are focused on detecting bugs or
verifying safety/security properties. Yannick has led the development of
the SPARK 2014 technology, which he has presented in articles, at
conferences, in courses and in blogs (blog.adacore.com). Yannick
previously worked on source code analyzers at PolySpace (now The
MathWorks) and at the Université Paris-Sud.
iii
Foreword
The book is intended for readers who are involved with software at any
level (developers, project managers, procurement personnel) and who
would like to learn how currently available technology can help address
some of the most serious challenges associated with software and security.
Our goal is to provide useful guidance both to those who are using other
languages and are interested in the benefits that Ada offers, and to
existing Ada users who might be confronted with new security
requirements.
v
The authors gratefully acknowledge the assistance of Ben Brosgol
(AdaCore) for his review of and contributions to the material presented in
this document.
Roderick Chapman
Protean Code Limited
Bath, U.K.
May 2018
Yannick Moy
AdaCore
Paris, France
May 2018
info@adacore.com
www.adacore.com
vi
AdaCore Technologies for Cyber Security
Contents
About the Authors ................................................................................................ iii
Foreword .................................................................................................................. v
1. Introduction ................................................................................................. 9
2. The Challenge of Secure Software ..................................................... 13
2.1. Why is it so hard?................................................................................ 13
2.2. Standards and Guidance................................................................... 16
2.3. The Market, Lemons, and Regulators ............................................... 17
2.4. A Manifesto for Secure Software..................................................... 18
3. Languages, Tools and Technologies Overview ............................. 25
3.1. Ada ......................................................................................................... 25
3.2. SPARK .................................................................................................... 31
3.3. GNAT Pro Enterprise........................................................................... 33
3.4. GNAT Pro Assurance........................................................................... 34
3.5. Static Verification - Basic Tools......................................................... 35
3.6. Static Verification - CodePeer .......................................................... 40
3.7. Static Verification - SPARK Pro......................................................... 41
3.8. Dynamic Analysis Tools ....................................................................... 42
3.9. Integrated Development Environments (IDEs) ................................. 44
4. Security Vulnerabilities and Their Mitigation .................................. 47
4.1. Data Validation ................................................................................... 47
4.2. Native Code Injection ......................................................................... 50
4.3. Denial of Service ................................................................................. 51
4.4. Information Leak .................................................................................. 53
4.5. Improper use of API ............................................................................ 55
4.6. Weak or No Crypto............................................................................ 57
7
AdaCore Technologies for Cyber Security
8
1. Introduction
It seems that every week’s news brings a story about yet another high-
profile failure of a computer system owing to a security issue. These
problems have a significant impact on the public, businesses and
government alike, affecting the reputation and share price of major
organizations. In the most critical industry sectors, company directors face
liability and governance concerns in an increasingly litigated environment.
9
AdaCore Technologies for Cyber Security
Reader’s Guide
Chapter 2 is recommended for all readers. It covers why producing
secure software is such a challenge, and thus motivates our technical
approach.
Chapter 3 covers the Ada and SPARK languages and then goes on to
describe AdaCore’s tools, with a focus on how they can support an
evidence-based assurance case for security. Readers already familiar
with Ada can probably skip section 3.1, while those familiar with
AdaCore’s tools as well can go straight on to chapter 4.
10
Roderick Chapman and Yannick Moy
11
2. The Challenge of Secure
Software
This chapter considers why building and operating secure computer
systems appears to be so difficult, as evidenced by the frequency and
magnitude of attacks reported in the media. Having set out the “bad
news”, this chapter closes with some principles that can be applied and
justify AdaCore’s position and technical approach.
13
AdaCore Technologies for Cyber Security
Asymmetry of Capability
It gets worse. The “bad guys” (attackers, malicious actors) are smarter
than you, have more money than you, and more time than you.
Furthermore, their capabilities don’t grow in some linear, predictable
fashion. A public “leak” of a government’s arsenal of hacking tools can
put nation-state level capability within reach of anyone at all in a matter
of days, and these capabilities become commoditized very rapidly.
Asymmetry of Effort
The software developer is responsible for preventing every possible
defect that might lead to any sort of security exploit or failure of the
system. An attacker, on the other hand, has to find just one defect to
mount a successful attack.
Asymmetry of Knowledge
Computer security (and, in particular, its sub-genre cryptography) is a
strange discipline, since the total knowledge of the field is far greater
than what is published in the scientific literature. In short, various groups
(including “attackers”, and certain notable government agencies) know
things that typical developers don’t. Examples include the RSA
cryptosystem in the early 1970’s, Differential Power Analysis pre-1999,
14
Roderick Chapman and Yannick Moy
Asymmetry of Impact
In software, it is very difficult to predict the relationship between a
particular defect (or class of defects) and its potential impact on the
system’s behavior, the system’s customers/users, or the developing
organization’s business. The impact of security issues can range from
negligible to those that destroy the reputation and share-price of a
company overnight. Given that attacks exist that developers don’t know
about, trying to decide whether a particular defect is “high impact” (and
therefore worthy of being fixed) can be almost impossible.
15
AdaCore Technologies for Cyber Security
It is also obvious to note that this approach does not scale with team
size—projects need technologies and disciplines that allow all developers
to produce work of the required quality, instead of relying on a few
“hero programmers” to save the day (or the project, or the company...)
16
Roderick Chapman and Yannick Moy
There have also been some higher-level attempts to look at the problem
which merit some attention. Examples include the US National Academy of
Sciences report “Software for Dependable Systems: Sufficient Evidence?”
[5] and the US National Institute for Standards and Technology (NIST)
report “Dramatically Reducing Software Vulnerabilities” [6]. The NIST
report identifies five approaches that have the potential to make a
dramatic impact on software quality, including the use of formal methods,
which (as will be shown later) aligns closely with AdaCore’s capabilities
and technologies.
17
AdaCore Technologies for Cyber Security
this “A market for Lemons” after similar observations were made about
the market for used cars.
This section lays out some basic principles for high-integrity software
engineering that could be applied to any project, regardless of the
standards, industry, or regulatory environment that might apply.
Chapter 3 goes into more details, showing how AdaCore’s languages and
tool technologies contribute to meeting these goals.
18
Roderick Chapman and Yannick Moy
Requirements
Arguably the most important aspect of producing secure and reliable
software, and also perhaps the most difficult to achieve, is to specify a
complete, consistent, and unambiguous set of requirements that the
software must meet, and to do so without overly constraining the solution.
The requirements should specify the “what”, but not the “how”, and should
be expressed in a way that facilitates verifying whether they are met.
Software standards such as DO-178C (airborne software) and CENELEC
EN 50128 (railway control and protection systems) recognize the critical
role of the requirements specification in the software life cycle. Typically
derived from overall system requirements, software requirements are
most easily visualized as comprising several tiers:
19
AdaCore Technologies for Cyber Security
Architecture
A system’s architecture entails its high-level design as components with
well-defined interfaces and interrelationships. A good architecture
provides a solid framework with effective modularization and robustness
in the presence of future enhancements and requirements changes.
Architecture covers issues such as redundancy, the provision of fail-safe
states or modes, mitigation of security concerns by physical means (e.g.
hardware design), and the separation of critical from non-critical
components. The last of these also allows the most critical software
components to be as small as possible, which helps to control cost.
Evidence-based Assurance
The fitness-for-purpose of a system should be justified by a logical
argument which is supported by evidence from a wide range of sources.
The evidence might be based on analysis of design artefacts, observation
including all forms of testing, metrics, and both direct and indirect
evidence of process compliance.
20
Roderick Chapman and Yannick Moy
Verification-Driven Development
Given a need for evidence, a development approach should be chosen
that generates the evidence as a natural by-product. This can be
summarized as “Security should be built in, not bolted on.” This idea can
be seen as a generalization of “Test-Driven Development” to cover all the
forms of verification activity that are available.
In theory, a static verification activity should yield results that are true for
all possible states and inputs, and therefore offers a qualitatively different
level of assurance from testing alone. This tool property is referred to as
“Soundness”, meaning that the results of a static verification really are
trustworthy. The concept is best illustrated with a simple example. Imagine
submitting a program’s source code to a tool, asking the question “Are
there any defects?” (for example, reads of uninitialized variables) and
receiving a report in response. If the tool is Sound, then these are the
21
AdaCore Technologies for Cyber Security
only such defects; if the tool is Unsound then the code may have defects
that were not reported. Phrased differently: if a Sound tool reports that
the program has no defects, then this conclusion can be trusted. If an
Unsound tool reports that the program has no defects, then it is still
possible that unreported defects are present.
The Sound tool offers a more desirable result than the Unsound tool, since
it provides a higher degree of confidence and requires less testing and
re-work later.
But...as always, there is no “free lunch.” It turns out that Soundness in static
verification is rather difficult to achieve, for the reasons set out in the next
sub-section. And all tools, whether Sound or Unsound, run the risk of
generating “false alarms”: reporting a potential defect that in fact is not
a problem. An ideal tool that is both Sound (reporting all defects) and
precise (not reporting any non-defects) is not achievable; in practice a
trade-off must be maintained. For example, first applying an Unsound
but precise tool to analyze legacy code and correct the reported defects,
and then using a Sound tool to identify the remaining defects.
Unambiguous Notation
To analyze the meaning (and therefore the presence or absence of
important defects) of a program successfully, a tool needs to know exactly
what a program means. This seems obvious, but turns out to be rather
difficult to achieve with most of the popular and practical programming
languages.
22
Roderick Chapman and Yannick Moy
The SPARK language and toolset set a high-water mark in this regard.
Soundness is achieved through a combination of language subsetting,
additional language rules, and analyses. SPARK can also be thought of as
a fully Formal language owing to its unambiguous semantics.
23
3. Languages, Tools and
Technologies Overview
This chapter summarizes the Ada and SPARK languages, as well as
AdaCore’s tools and technologies, and highlights their contributions to
system security.
3.1. Ada
Ada is a modern programming language designed for large, long-lived
applications – and embedded systems in particular – where reliability,
maintainability, and efficiency are essential. It was originally developed
in the early 1980s (this version is generally known as Ada 83) by a team
led by Jean Ichbiah at CII-Honeywell-Bull in France. The language was
revised and enhanced in an upward-compatible fashion in the early
1990s, under the leadership of Tucker Taft from Intermetrics in the U.S.
The resulting language, Ada 95, was the first internationally standardized
(ISO) object-oriented language. Under the auspices of ISO, a further
(minor) revision was completed as an amendment to the standard; this
version of the language is known as Ada 2005. Additional features
(including support for contract-based programming in the form of
subprogram pre- and postconditions and type invariants) were added in
the most recent version of the language standard, Ada 2012 (see
[9,10,11] for information about Ada).
25
AdaCore Technologies for Cyber Security
AdaCore has a long history and close connection with the Ada
programming language. Company members worked on the original
Ada 83 design and review and played key roles in the Ada 95 project
as well as the subsequent revisions. The initial GNAT compiler was
essential to the growth of Ada 95; it was delivered at the time of the
language’s standardization, thus guaranteeing that users would have a
quality implementation for transitioning to Ada 95 from Ada 83 or other
languages.
Language Overview
Ada is multi-faceted. From one perspective it is a classical stack-based
general-purpose language, not tied to any specific development
methodology. It has a simple syntax, structured control statements,
flexible data composition facilities, strong type checking, traditional
features for code modularization (“subprograms”), and a mechanism for
detecting and responding to exceptional run-time conditions (“exception
handling”).
Scalar ranges
Unlike languages based on C (such as C++, Java, and C#), Ada allows
the programmer to simply and explicitly specify the range of values that
are permitted for variables of scalar types (integer, floating-point, fixed-
point, and enumeration types). The attempted assignment of an out-of-
range value causes a run-time error. The ability to specify range
constraints makes programmer intent explicit and makes it easier to
detect a major source of coding and user input errors. It also provides
useful information to static analysis tools and facilitates automated proofs
of program properties.
26
Roderick Chapman and Yannick Moy
Contract-based programming
Ada 2012 allows extending a subprogram specification or a
type/subtype declaration with a contract (a Boolean assertion).
Subprogram contracts take the form of preconditions and postconditions.
Through contracts the developer can formalize the intended behavior of
the application, and can verify this behavior by testing, static analysis or
formal proof.
package Table_Pkg is
type Table is private; -- Encapsulated type
27
AdaCore Technologies for Cyber Security
Ada 2012 goes further still, allowing type invariants and subtype
predicates to specify precisely what is and isn’t valid for any particular
(sub)type, including composite types such as records and arrays. For
example, one can easily specify that field Max_A in the Launching_Pad
structure below is the maximal value of angle allowed given the distance
D to the center of the launching pad and the height H of the rocket, with
the guarantee that automatic run-time checks will be inserted by the
compiler to verify this predicate as well as constraints on the individual
fields:
Generic templates
A key to reusable components is a mechanism for parameterizing modules
with respect to data types and other program entities, for example a
stack package for an arbitrary element type. Ada meets this requirement
through a facility known as “generics”; since the parameterization is done
at compile time, run-time performance is not penalized.
28
Roderick Chapman and Yannick Moy
Concurrent programming
Ada supplies a structured, high-level facility for concurrency. The unit of
concurrency is a program entity known as a “task.” Tasks can communicate
implicitly via shared data or explicitly via a synchronous control
mechanism known as the rendezvous. A shared data item can be defined
abstractly as a “protected object” (a feature introduced in Ada 95), with
operations executed under mutual exclusion when invoked from multiple
tasks. Asynchronous task interactions are also supported, specifically
timeouts and task termination. Such asynchronous behavior is deferred
during certain operations, to prevent the possibility of leaving shared
data in an inconsistent state. Mechanisms designed to help take
advantage of multi-core architectures were introduced in Ada 2012.
29
AdaCore Technologies for Cyber Security
Systems programming
Both in the “core” language and the Systems Programming Annex, Ada
supplies the necessary features for hardware-specific processing. For
example, the programmer can specify the bit layout for fields in a
record, define alignment and size properties, place data at specific
machine addresses, and express specialized code sequences in assembly
language. Interrupt handlers can also be written in Ada, using the
protected type facility.
Real-time programming
Ada’s tasking facility and the Real-Time Systems Annex support common
idioms such as periodic or event-driven tasks, with features that can help
avoid unbounded priority inversions. A protected object locking policy is
defined that uses priority ceilings; this has an especially efficient
implementation in Ada (mutexes are not required) since protected
operations are not allowed to block. Ada 95 defined a task dispatching
policy that basically requires tasks to run until blocked or preempted, and
Ada 2005 introduced several others including Earliest Deadline First.
High-integrity systems
With its emphasis on sound software engineering principles Ada supports
the development of high-integrity applications, including those that need
to be certified against safety standards such DO-178C for avionics,
CENELEC EN 50128 for rail systems and security standards such as the
Common Criteria. For example, strong typing means that data intended
for one purpose will not be accessed via inappropriate operations; errors
such as treating pointers as integers (or vice versa) are prevented. And
Ada’s array bounds checking prevents buffer overflow vulnerabilities that
are common in C and C++.
30
Roderick Chapman and Yannick Moy
The evolution of Ada has seen the continued increase in support for
safety-critical and high-security applications. Ada 2005 standardized the
Ravenscar Profile, a collection of concurrency features that are powerful
enough for real-time programming but simple enough to make
certification practical. Ada 2012 has introduced contract-based
programming facilities, allowing the programmer to specify preconditions
and/or postconditions for subprograms, and invariants for encapsulated
(private) types. These can serve both for run-time checking and as input to
static analysis tools.
3.2. SPARK
SPARK1 is a software development technology (programming language
and verification toolset) specifically designed for engineering ultra-low
defect level applications, for example where safety and/or security are
key requirements. SPARK Pro is the commercial-grade offering of the
SPARK technology developed by AdaCore and Altran. The main
component in the toolset is GNATprove, which performs formal
verification on SPARK code.
SPARK has an extensive industrial track record. Since its inception in the
late 1980s it has been used worldwide in a range of industrial
applications such as civil and military avionics, air traffic management /
control, railway signaling, cryptographic software, and cross-domain
solutions. SPARK 2014 is the most recent version of the technology (see
[13]).
1 Note that our SPARK is totally unrelated to the Apache SPARK analytics
framework, or the SPARC CPU Instruction Set Architecture.
31
AdaCore Technologies for Cyber Security
Flexibility
SPARK 2014 offers the flexibility of configuring the language on a per-
project basis. Restrictions can be fine-tuned based on the relevant coding
standards or run-time environments.
SPARK 2014 code can easily be combined with full Ada code or with C,
so that new systems can be built on and reuse legacy codebases.
Ease of Adoption
The SPARK 2014 technology is easy to learn and can be smoothly
integrated into an organization’s existing development and verification
methodology and infrastructure.
SPARK supports “hybrid verification” that can mix testing with formal
proofs. For example an existing project in Ada and C can adopt SPARK
to implement new functionality for critical components. The SPARK units
can be analyzed statically to achieve the desired level of verification,
with testing performed at the interfaces between the SPARK units and the
modules in the other languages.
32
Roderick Chapman and Yannick Moy
Based on the GNU GCC technology, GNAT Pro Enterprise supports all
versions of the Ada language standard, from Ada 83 to Ada 2012, and
also handles multiple versions of C (C89, C99, and C11). It includes an
Integrated Development Environment (GNAT Programming Studio and/or
GNATbench), a comprehensive toolsuite including a visual debugger, and
a set of libraries and bindings.
GNAT Pro Enterprise offers several features that make it ideal for the
development of secure systems. These include:
33
AdaCore Technologies for Cyber Security
Beyond this bundled support, AdaCore also provides Ada language and
tool training as well as on-site consulting on topics such as how to best
deploy the technology, and assistance on start-up issues. On-demand tool
development or ports to new platforms are also available.
34
Roderick Chapman and Yannick Moy
Sustained Branches
Unique to GNAT Pro Assurance is a service known as a “sustained
branch”: customized support and maintenance for a specific version of the
product. A project on a sustained branch can monitor relevant known
problems, analyze their impact, and if needed update to a newer version
of the product on the same development branch (i.e., not incorporating
changes introduced in later versions of the product).
GNATcheck
GNATcheck is a coding standard verification tool that is extensible and
rule-based. It allows developers to completely define a coding standard
as a set of rules, for example a subset of permitted language features. It
verifies a program’s conformance with the resulting rules and thereby
facilitates demonstration of a system’s compliance with certification
standards.
35
AdaCore Technologies for Cyber Security
GNATstack
GNATstack is a software analysis tool that enables Ada/C software
development teams to accurately predict the maximum size of the
memory stack required for program execution.
36
Roderick Chapman and Yannick Moy
This is a static analysis tool in the sense that its computation is based on
information known at compile time. When the tool indicates that the result
is accurate, the computed bound can never be exceeded.
On the other hand, there may be cases in which the results will not be
accurate (the tool will report such situations) because of some missing
information (such as the maximum depth of subprogram recursion, indirect
calls, etc.). The user can assist the tool by specifying missing call graph
and stack usage information.
GNATstack’s main output is the worst-case stack usage for every entry
point, together with the paths that result in these stack sizes. The list of
entry points can be automatically computed (all the tasks, including the
environment task) or can be specified by the user (a list of entry points or
all the subprograms matching a given regular expression).
GNATstack can also detect and display a list of potential problems when
computing stack requirements:
• Indirect (including dispatching) calls. The tool will indicate the number
of indirect calls made from any subprogram.
• External calls. The tool displays all the subprograms that are
reachable from any entry point for which there is no stack or call
graph information.
• Unbounded frames. The tool displays all the subprograms that are
reachable from any entry point with an unbounded stack requirement.
37
AdaCore Technologies for Cyber Security
procedure P (N : Integer) is
S : String (1 .. N);
begin
...
end P;
• Cycles. The tool can detect all the cycles (i.e., potential recursion)
in the call graph.
GNATstack allows the user to supply a text file with the missing
information, such as the potential targets for indirect calls, the stack
requirements for externals calls, and the maximal size for unbounded
frames.
Timing Verification
Suitably subsetted, Ada (and SPARK) are also amenable to the static
analysis of timing behavior. This kind of analysis is relevant for real-time
systems, where worst-case execution time (WCET) must be known in order
to guarantee that timing deadlines will always be met. Timing analysis is
also of interest for secure systems, where the issue might be to show that
programs do not leak information via so-called side-channels based on
the observation of differences in execution time.
AdaCore does not produce its own WCET tool, but there are several such
tools on the market from partner companies, such as RapiTime from
Rapita Systems Ltd.
38
Roderick Chapman and Yannick Moy
• Code instrumentation
39
AdaCore Technologies for Cyber Security
CodePeer can analyze programs written in full Ada (including all the
features of Ada 2012) and does not rely on a particular language subset
having been used. It is therefore suitable for analysis and assurance of
existing code bases, and maintaining discipline for new and modified
code.
40
Roderick Chapman and Yannick Moy
41
AdaCore Technologies for Cyber Security
For the most critical embedded systems, SPARK supports the so-called
“Bare-Metal” development style, where SPARK code is running directly on
a CPU with little or no COTS libraries or operating system at all. SPARK is
also designed to be compatible with GNAT Pro’s Zero FootPrint (ZFP) run-
time library. In a Bare-Metal/ZFP development, every byte of object
code can be traced to the application’s source code, and accounted for.
This can be particularly useful for systems that must withstand evaluation
by a national technical authority or regulator.
SPARK code can also run on top of a full Ada run-time library and a
commercial desktop operating system or anything in-between, but the
choice is left to the system designer, not imposed by the language.
42
Roderick Chapman and Yannick Moy
• The complete harnessing code for executing all the unit tests under
consideration. This code is generated completely automatically.
GNATemulator
GNATemulator is an efficient and flexible tool that provides integrated,
lightweight target emulation.
There are two basic types of emulators. The first can serve as a surrogate
for the final hardware during development for a wide range of
verification activities, particularly those that require time accuracy.
However, they tend to be extremely costly, and are often very slow. The
second, which includes GNATemulator, does not attempt to be a complete
time-accurate target board simulator, and thus it cannot be used for all
aspects of testing. But it does provide a very efficient and cost-effective
way to execute the target code very early in the development and
verification processes. GNATemulator thus offers a practical compromise
between a native environment that lacks target emulation capability, and
a cross configuration where the final target hardware might not be
available soon enough or in sufficient quantity.
GNATcoverage
GNATcoverage is a dynamic analysis tool that analyzes and reports
program coverage. GNATcoverage can perform coverage analysis at
both the object code level (instruction and branch coverage), and the
43
AdaCore Technologies for Cyber Security
Tools
GPS’s extensive navigation and analysis tools can generate a variety of
useful information including call graphs, source dependencies, project
organization, and complexity metrics, giving the developer a thorough
understanding of a program at multiple levels. It allows interfacing with
third-party Version Control Systems, easing both development and
maintenance.
44
Roderick Chapman and Yannick Moy
Remote Programming
Integrated into GPS, Remote Programming provides a secure and
efficient way for programmers to access any number of remote servers on
a wide variety of platforms while taking advantage of the power and
familiarity of their local PC workstations.
GNATdashboard
GNATdashboard serves as a one-stop control panel for monitoring and
improving the quality of Ada software. It integrates and aggregates the
results of AdaCore’s various static and dynamic analysis tools
(GNATmetric, GNATcheck, GNATcoverage, CodePeer, SPARK Pro, among
others) within a common interface, helping quality assurance managers
and project leaders understand or reduce their software’s technical debt,
and eliminating the need for manual input.
45
4. Security Vulnerabilities
and Their Mitigation
This chapter considers a number of specific and high-profile software
vulnerabilities, inspired by the CWE/SANS “Top 25 Most Dangerous
Software Errors” [17], and discusses how each can be prevented or
mitigated using Ada, SPARK, and AdaCore’s tools.
Some vulnerabilities are universal in that all software should be free of all
occurrences—buffer overflow would be a good example, since all
programs should be free of all buffer overflows, regardless of the
particular application’s requirements or operational domain.
Many vulnerabilities are in some way application specific in that they may
or may not be a problem, depending on the application’s particular
security requirements and operational environment.
Vulnerability
Missing or incorrect validation of input data remains one of the most
common security vulnerabilities in software. This is an application-specific
vulnerability, since exactly what does or doesn’t constitute “valid” input
data is highly dependent on an application and its security requirements.
47
AdaCore Technologies for Cyber Security
Dynamic Mitigation
At the most basic level, Ada has always offered run-time range checking
for scalar values. If a check fails at run time, then an exception is raised
rather than allowing the execution of the program to become undefined.
This offers protection against common defects such as integer range
violations, buffer overflows, arithmetic overflow and division by zero. For
example, any attempt to store an integer value outside the range (-180 ..
180) for an angle, or a real value outside the range (0.0 .. 10000.0) for
a length in the following example will raise an exception at run time.
Similarly, a Data value whose Kind is Angle_Data cannot be mistakenly
interpreted as a value whose Kind is Length_Data (i.e., an Angle bit
pattern cannot be interpreted as a Length) when using the discriminated
unions of Ada; such an error would raise an exception.
Ada 95 added a special attribute X'Valid for any scalar object X. This
returns True if and only if the raw bit-pattern present in memory is a valid
value for the type of the object and satisfies any subtype constraint or
predicate (if present). This is more powerful than a simple “range check”,
because it applies to types with complex representations such as floating-
point or enumeration types with non-contiguous values. Further, the
evaluation of X'Valid can never itself become undefined or raise an
exception, so it provides a way to “peek” at incoming data to see if it’s
48
Roderick Chapman and Yannick Moy
OK before proceeding. It also works with the ZFP run time and SPARK,
where exceptions are excluded anyway.
Static Mitigation
The GNAT Pro compiler can detect some violations of data constraints
that do not depend on the flow of control and analysis of calls. In such
cases, it issues a warning that an exception will be raised at run time if
that code is executed. Similarly, it can detect some simple cases of
reading an uninitialized variable.
49
AdaCore Technologies for Cyber Security
SPARK Pro goes further in a number of ways. Firstly, SPARK Pro offers a
completely static verification for the absence of all undefined behavior,
run-time errors and exceptions. In SPARK it’s possible to prove that none
of Ada’s predefined run-time checks will ever fail for any program
executions.
In the most general sense, subprograms in Ada and SPARK can also
include precondition contracts that can specify arbitrary validity
requirements on their parameters, which can be as permissive or as strict
as is required by the designer. These can be checked at run time, or by
static analysis, or both.
Vulnerability
This section specifically deals with the problem of malicious injection of
Ada or machine code. This is a universal vulnerability. Injection of code in
other languages (e.g., scripting languages or SQL) can be application
specific, so is considered elsewhere. Two cases are covered here—
injection of Ada code itself, and injection of compiled machine code.
50
Roderick Chapman and Yannick Moy
Vulnerability
“Denial-of-Service” has become a broad term that refers to any form of
attack that prevents a computer system from fulfilling its intended role
and service. This is an application-specific vulnerability, since some
51
AdaCore Technologies for Cyber Security
systems can “fail secure” while others might have onerous requirements for
continuity of service and availability.
Dynamic Mitigation
For some systems, termination in a known “secure state” might be
acceptable. This kind of “fail secure” behavior is supported by Ada
through run-time exception handling. A top-level “catch all” handler can
be inserted into the main program and each task type or object; the
handler can bring the system to a safe and/or secure state before
allowing the system to terminate.
A second option is similar, but the system can implement some sort of
“graceful degradation” and switch to a simpler mode of operation. Other
options include reverting to a backup system, or executing a hardware-
based “reset” to bring the system to a known state.
Static Mitigation
Where continuity of service is important, for example in communications
and real-time control applications, both CodePeer and SPARK Pro offer
strong protection. If programs can be statically shown to be free from all
run-time errors, then they are effectively crash proof in the face of
arbitrary input data.
52
Roderick Chapman and Yannick Moy
Vulnerability
These vulnerabilities form a general class of problems where information
is seen to go where it shouldn’t. Three sub-classes of this problem arise:
53
AdaCore Technologies for Cyber Security
Mitigation—Programming Defects
This is a universal vulnerability. Simple programming defects can cause
information to flow in unexpected ways. For example:
Mitigation—Algorithmic Defects
If a programmer simply implements “the wrong code”, then unintended
information flow can result. For example, if a function is supposed to be
computed from two input variables X and Y, but the programmer
mistakenly computes the result from X, Y and Z, then an observer might be
able to deduce something about the value of Z, which might be a security
vulnerability if Z is some sensitive value like a cryptographic key.
Contracts can also be used to specify, for example, that data of different
classification (e.g. “Unclassified” and “Top-Secret”) shall not be mixed in
a single computation. Again, SPARK Pro offers strong verification for such
properties.
54
Roderick Chapman and Yannick Moy
Mitigation—Side Channels
So-called “Side” or “Covert” channels exploit devious and unusual
observations of a program’s execution to deduce its internal state. These
include:
55
AdaCore Technologies for Cyber Security
Related CWEs
CWE Short description Notes
440 Expected Behaviour Violation
559 Often Misused: Arguments and
Parameters
628 Function Call with Incorrectly
Specified Arguments
648 Incorrect Use of Privileged APIs
749 Exposed Dangerous Method or
Function
Vulnerability
The design of reusable, general, and error-tolerant APIs remains one of
the core skills of a software designer. (See Joshua Bloch’s lecture [18] for
an overview of this topic.)
A core issue is the expressive power, precision and abstraction with which
a programming language allows an API specification to be defined.
Many APIs need to express usage rules—what a user should and
shouldn’t do to use the API properly—and if these rules are specified
formally then they can be checked either at run time or using static
analysis.
Mitigations
Once again, Ada’s contracts offer strong support. Preconditions express
exactly the conditions under which a particular operation may be
invoked, and can even be used to express ordering constraints on
operations (e.g. “operation X must be invoked before either of operations
Y or Z.”) Similarly, postcondition contracts can express exactly what
operations promise to do (and not do.)
56
Roderick Chapman and Yannick Moy
tools. This is the case for example for the standard numerical library
shipped with GNAT Pro. Some freely available libraries have also
started to appear in SPARK, such as standard cryptographic algorithms
[19].
Vulnerability
These are clearly application specific. The appropriate use of
cryptographic algorithms depends on an application’s precise needs for
confidentiality, authentication and integrity of data, plus the perceived
capability and threat owing to attackers.
Mitigations
Ada can help to some extent through its system of strong types. A good
design approach would be to declare distinct and incompatible types for
unencrypted and encrypted data, so that they cannot be confused or
used in the wrong context. For example:
57
AdaCore Technologies for Cyber Security
Even though, under the hood, these types might both represent an
unstructured sequence of bytes, they are distinct and incompatible from
the point of view of the client. For example, a procedure that outputs an
encrypted buffer to a communications channel might be declared:
Note that the Key type is declared limited private so that objects of that
type cannot be copied by assignment—another built-in feature of Ada
that is ideal for such sensitive types.
58
Roderick Chapman and Yannick Moy
Vulnerability
This vulnerability concerns the need to erase (or “sanitize”) sensitive data,
such as cryptographic keys, after they have been used, to prevent
unintentional leak or exposure of that some time later.
Mitigations
Ada provides some specific support in this area. Its limited types are ideal
for sensitive data since they cannot be copied by assignment, and are
always passed by reference at run time. Ada 95 also introduced a
special pragma Inspection_Point which serves to forbid “dead store
elimination” in the compiler for a particular object at a particular place,
thus ensuring that a final “sanitizing assignment” is not removed.
59
AdaCore Technologies for Cyber Security
Vulnerability
This large family of vulnerabilities is highly application specific. What is
or is not “authorized” for a user of a system depends on the system, its
environment, and the threat model that is expected.
Mitigations
In the broadest terms, systems should be designed with the least privilege
principle in mind, restricting the most important or risky operations to the
fewest users and operational scenarios.
Given a strong design along those lines, these concepts can be encoded in
Ada using types and contracts. A simple model might map a user’s ID onto
some ordered value of authorization:
Sensitive operations can then use a precondition to restrict access, such as:
60
Roderick Chapman and Yannick Moy
61
5. Industrial Scenario
Examples
5.1. Overview
This chapter presents a number of security-related scenarios that may
arise in real-world projects. Each opens with a description of the context
and the security issue, and then shows how either Ada or SPARK, in
conjunction with the relevant AdaCore tool(s), can contribute. Each
scenario is illustrated with one or more examples, drawn from experience
with customers and industrial projects.
Even when GNAT Pro is not the main compiler on a project, it can
still be used as a basic static analysis tool. GNAT Pro flags
around 50 different classes of warnings which represent over
130 warning messages. Experience shows that a careful selection
of warnings combined with a fix-all-warnings policy can
significantly increase the quality of a code base. Warnings that
cannot be fixed can be justified with pragma Warnings Off.
Warnings can be treated as errors (thus stopping compilation) by
63
AdaCore Technologies for Cyber Security
Since 2017, AdaCore has been running CodePeer on the GNAT Pro front
end, with a fix-all-messages policy. These runs have resulted in the
detection of a number of errors in the code, as well as code quality issues
(e.g. dead code) which are opportunities for refactoring. CodePeer is run
at level 1 for fast execution (less than 10 minutes on a developer
machine) while minimizing false alarms. Remaining false alarms are
justified with pragma Annotate in the code. CodePeer runs have been
integrated in the continuous building environment and nightly regression
testing.
64
Roderick Chapman and Yannick Moy
Because AWS is security sensitive, special care is taken in its code to state
explicitly the constraints that should be respected for the program to
operate without errors, using Ada contracts on types and subprograms.
For example, AWS code deals with time-zone string representation in
many places. The code uses a predicate on this type to enforce that this
representation remains valid:
65
AdaCore Technologies for Cyber Security
In the same vein AWS uses a Hex_String type which contains only
numbers and letters from 'a' to 'f'.
function Build
(Content_Type : String;
UString_Message : Unbounded_String;
Status_Code : Messages.Status_Code := …;
Cache_Control : Messages.Cache_Option := …;
Encoding : Messages.Content_Encoding := …)
return Data
with Post => not Is_Empty (Build'Result)
and then Response.Status_Code (Build'Result) = Status_Code;
66
Roderick Chapman and Yannick Moy
The Muen system, including all the code, is freely available under
version 3 of the GNU Public License (GPL).
67
AdaCore Technologies for Cyber Security
Example of Scenario 4
The MULTOS CA [8] formed the root certificate authority and key
generation facility for the MULTOS smartcard operating system. The CA
facility stored the private signing keys that were used to digitally sign
certificates for MULTOS applications, and so were subject to an
extraordinary level of physical, procedural, and computer-based security.
68
Roderick Chapman and Yannick Moy
69
AdaCore Technologies for Cyber Security
Once C libraries are “wrapped” in this fashion, they can be called from
new Ada or SPARK code as expected. (It also works in the other direction:
Ada and SPARK can be called from C.) The contracts on the library
binding will be verified, either dynamically at run time, statically using
CodePeer or SPARK Pro, or both.
Some effort was spent to document the assumptions that the SPARK and C
code make about each other’s behavior, and how these assumptions can
be expressed as contracts and verified in practice. Further details of this
project appear in [26], which is available from the authors.
70
6. Summing Up
Developing software that operates predictably and “does the right thing”
in an overtly malicious environment is a high bar for software designers to
overcome, but it can be done with a combination of engineering
discipline, processes, languages and tools. While security remains a multi-
faceted problem, the Ada and SPARK languages and AdaCore’s tools
provide some effective means to build software that truly matters.
From its earliest days, Ada has always emphasized the needs of high-
integrity systems and, in particular, the verifiability of code. With the
rising need for security in software, the strengths of Ada’s design are
gaining increased recognition and appreciation. Although other
languages are trying to add support for high-integrity and secure
programming, these are properties that need to be considered from the
earliest stages of the language design, they cannot be grafted on
afterwards. If and when those languages eventually arrive at that sweet
spot, they will find Lady Ada already there waiting to greet them.
In brief, Ada and SPARK and their associated tools stand out among
current language technologies in addressing the two issues underling
secure software:
71
A. CWE Mapping
Overview
This appendix focuses on the MITRE Corporation’s Common Weakness
Enumeration (CWE) and how the use of Ada and AdaCore technologies
can address particular CWEs.
Several terms are used here with specific meanings. A language or tool is
said to prevent a given CWE if:
73
AdaCore Technologies for Cyber Security
74
Roderick Chapman and Yannick Moy
These tables only list “Base” CWEs, not “Class” or “Variant” CWEs.
75
AdaCore Technologies for Cyber Security
76
Roderick Chapman and Yannick Moy
Note to GNAT Pro users: If a project is not using the Restrictions pragma,
then the list of Restrictions that could be applied can be generated using
the GNAT Pro Binder tool’s “-r” switch. In GPS, this switch can be enabled
from the Project Properties dialog box, by selecting the Build / Switches /
Binder menu entry and then checking the “List possible restrictions”
checkbox.
77
AdaCore Technologies for Cyber Security
78
B. Handling SQL Injection
in Ada and SPARK
This appendix builds a worked example of how the common “SQL
Injection” defect can be handled using Ada and SPARK.
These forms of “code injection” attacks have been at or near the top of
the most-reported cyber security vulnerabilities for many years.
Some static analysis tools claim to find and report SQL Injection problems,
using some form of “taint analysis”. This is where the flow of information
from an input to an SQL query is tracked through a program, so that
potentially suspicious (or “tainted”) queries can be reported. This
approach is essentially heuristic—a tool is trying to assess if a particular
user input might be tainted. This yields both false positives (spurious
alarms) and false negatives (missing alarms).
The crux is that a general-purpose tool cannot know what does or doesn’t
constitute a valid and secure SQL query without detailed knowledge of
the target application’s security policy and requirements. This detail is
inherently domain- and application specific, so there’s no way an “out of
the box” tool can have such a built-in oracle.
This example shows how Ada’s contracts can be used to solve this
problem.
79
AdaCore Technologies for Cyber Security
package DB
with SPARK_Mode => On,
Abstract_State => State,
Initializes => State
is
procedure Execute (SQL_Query : in String;
Result : out Integer)
with Global => (Input => State);
end DB;
80
Roderick Chapman and Yannick Moy
package DB
with SPARK_Mode => On,
Abstract_State => State,
Initializes => State
is
function Is_Valid (SQL_Query : in String) return Boolean;
If a main program tries to call Execute without checking Is_Valid first and
chooses not to handle the resulting exception, then the result is
predictable:
81
AdaCore Technologies for Cyber Security
hand Is_Valid could return True all the time—this would cause no
violations but would be rather obviously unsound if a malicious query
really did arrive. On the other hand, it could always return False—never
allowing any SQL queries at all. This would be “secure” but offer a rather
high false-positive rate, since all perfectly legal queries would be
rejected.
An important lesson for system designers is that technologies like Ada and
SPARK can offer useful mechanisms in building secure systems, but they do
not supply policy. That can only come from a knowledge of the system’s
application domain and requirements.
An example of Is_Valid
For simplicity this example assumes that the system’s security policy exists
and says that an SQL query is valid if:
would be rejected.
82
Roderick Chapman and Yannick Moy
The SPARK language and tools go further, offering fully static verification
of the same properties.
as expected.
In practice however, a safe application would not build SQL queries using
simple string operations in the first place. Instead, it would more likely use
type-safe APIs like those provided by the library GNATCOLL.SQL, or
83
AdaCore Technologies for Cyber Security
84
References
[1] Ross Anderson. Security Engineering, 2nd Edition. Wiley, 2008.
Also available at http://www.cl.cam.ac.uk/~rja14/book.html
85
AdaCore Technologies for Cyber Security
[10] John Barnes and Ben Brosgol, Safe and Secure Software, an
invitation to Ada 2012, AdaCore, 2015.
Available at http://www.adacore.com/knowledge/technical-
papers/safe-and-secure-software-an-invitation-to-ada-2012/
[14] Paul E. Black, Michael Kass, Michael Koo, Elizabeth Fong, Source
Code Security Analysis Tool Functional Specification, NIST, 2011.
[18] Joshua Bloch. How to Design a Good API and Why it Matters.
Various on-line sources, including video here:
https://www.youtube.com/watch?v=aAb7hSCtvGw.
86
Roderick Chapman and Yannick Moy
87
Index
Ada language
Assertion_Error exception, 28
Buffer overflow prevention, 30
Concurrent programming (tasks), 29
Contract-based programming, 27, 31
Generic templates, 28
History and overview, 25
Limited types, 59
Object-Oriented Programming (OOP), 29
Postconditions, 27
pragma Inspection_Point, 59
pragma Restrictions, 30
Preconditions, 27
Programming in the large, 28
Real-Time Systems Annex, 30
Scalar ranges, 26
Systems Programming Annex, 30
Usage, 25
AdaCore
Ada history, 26
ASIS-for-GNAT. See ASIS-for-GNAT
CodePeer. See CodePeer
GNAT Pro Assurance. See GNAT Pro Assurance
GNAT Pro Enterprise. See GNAT Pro Enterprise
GNAT Programming Studio. See GNAT Programming Studio (GPS)
GNAT2XML. See GNAT2XML
GNATbench. See GNATbench
GNATcheck. See GNATcheck
GNATcoverage. See GNATcoverage
GNATdashboard. See GNATdashboard
GNATemulator. See GNAtemulator
GNATmetric. See GNATmetric
GNATprove. See GNATprove
GNATstack. See GNATstack
GNATtest. See GNATtest
SPARK Pro. See SPARK Pro
Support and expertise, 34
Anderson, Ross, 9
API Usage, 55
Architecture, 20
Physical, 20
Simplicity, 20
ASIS (Ada Semantic Interface Specification), 39
ASIS-for-GNAT, 39
Assurance
89
AdaCore Technologies for Cyber Security
Evidence-based, 20
Asymmetry
Capability, 14
Effort, 14
Impact, 15
Knowledge, 14
AUnit, 42
Authentication, 60
Authorization, 60
Babbage, Charles, 25
Buffer overflow, 30, 41
C language
Buffer overflow, 30
Supported by GNAT Pro, 33
C++ language
Buffer overflow, 30
Case studies
Ada Web Server, 65
cryptographic algorithms, 68
GNAT Pro frontend, 64
Muen, 67
MULTOS CA, 68
SQL Injection, 79
Tokeneer project, 68
CENELEC EN 50128, 19, 30
Code Injection, 50
Ada, 50
Machine code, 51
SQL, 79
CodePeer, 40
Common Weakness Enumeration (CWE) errors detected, 41
Early error detection, 41
Coding standard
Enforcement by GNATcheck, 35
Common Criteria, 30
Common Weakness Enumeration (CWE) errors detected by CodePeer, 41
Computer Emergency Readiness Team (CERT), 9
Cryptography, 14
Weak or absent, 57
CWEs, 47
Ada language Restrictions mapping, 77
Application specific, 73
Compliance, 74
Dynamic mitigation, 74
Mitigated by Ada, 75
90
Roderick Chapman and Yannick Moy
Mitigated by CodePeer, 75
Mitigated by SPARK, 75
Mitigation, 73
Prevented by Ada, 74
Prevention, 73
Static mitigation, 74
Universal, 73
Cyber Security Body of Knowledge (CyBOK), 9
Garbage collection, 29
GNAT Pro Assurance, 34
Configurable Run-Time Library, 33
Sustained branch. See Sustained branch
Traceability analysis service. See Traceability (Source to Object)
Warnings, 63
GNAT Pro Enterprise, 33
GNAT Programming Studio (GPS), 33, 44
GNAT2XML, 40
GNATbench, 33, 45
GNATcheck, 35
Coding standard enforcement, 35
GNATcoverage, 43
GNATdashboard, 45
GNATemulator, 43
GNATmetric, 35
GNATprove, 31
91
AdaCore Technologies for Cyber Security
GNATstack, 36
GNATtest, 42
GNU GCC technology, 33
High-level requirements, 19
Hybrid verification, 32
Ichbiah, Jean, 25
Incorrect calculation of buffer size, 41
Information Leak, 53
Side channel, 55
Input Data
Validation, 34
Integer overflow or wraparound, 41
Integrated Development Environments (IDEs), 44
Java language, 29
Libadalang, 39
Limits
Talent, 15
Testing, 15
Liskov Substitution Principle (LSP), 43
Lovelace, Augusta Ada, 25
Low-level requirements, 19
Market, 17
Failure, 17
Lemons, 18
Memory
Leak, 38
Usage verification, 38
Modified Condition/Decision Coverage (MC/DC), 44
Muen hypervisor, 67
Patching, 16
QEMU, 43
Safety-critical systems, 14
Satan's computer, 14
92
Roderick Chapman and Yannick Moy
Sensitive Data, 59
Erasing, 59
SPARK, 31
Absence of run-time exceptions, 42
Data and control flow analysis, 41
Information flow analysis, 41
Static verification support, 41
Usage, 31
SPARK Pro, 31
SQL Injection, 79
Dynamic mitigation using Ada, 79
Static prevention using SPARK, 83
Standards, 16
abundance of, 17
Statement coverage, 44
Static Analysis. See Static Verification
Static Verification, 21
Soundness, 21, 32
Sustained branch, 35
Taft, Tucker, 25
Test-Driven Development, 21
Timing Verification, 38
Traceability (Source to Object), 35
Valgrind, 44
Verification
Dynamic, 21
Static, 21
Verification-Driven Development, 21
Vulnerabilities, 47
Application specific, 47
Universal, 47
WCET Analysis, 38
Weak Crypto, 57
Workbench (WindRiver development environment), 45
93