Output-sensitive Information flow analysis
Cristian Ene, Laurent Mounier, Marie-Laure Potet
To cite this version:
Cristian Ene, Laurent Mounier, Marie-Laure Potet. Output-sensitive Information flow analysis.
39th International Conference on Formal Techniques for Distributed Objects, Components, and Systems (FORTE), Jun 2019, Copenhagen, Denmark. pp.93-110, 10.1007/978-3-030-21759-4_6. hal02303984
HAL Id: hal-02303984
https://hal.archives-ouvertes.fr/hal-02303984
Submitted on 2 Oct 2019
HAL is a multi-disciplinary open access
archive for the deposit and dissemination of scientific research documents, whether they are published or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.
L’archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d’enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.
Distributed under a Creative Commons Attribution| 4.0 International License
Output-sensitive Information flow analysis⋆
Cristian Ene[0000−0001−6322−0383] , Laurent Mounier[0000−0001−9925−098X] , and
Marie-Laure Potet[0000−0002−7070−6290]
Univ. Grenoble Alpes, CNRS, Grenoble INP, VERIMAG, 38000 Grenoble, France
[email protected]
Abstract. Constant-time programming is a countermeasure to prevent
cache based attacks where programs should not perform memory accesses
that depend on secrets. In some cases this policy can be safely relaxed
if one can prove that the program does not leak more information than
the public outputs of the computation.
We propose a novel approach for verifying constant-time programming
based on a new information flow property, called output-sensitive noninterference. Noninterference states that a public observer cannot learn
anything about the private data. Since real systems need to intentionally
declassify some information, this property is too strong in practice. In
order to take into account public outputs we proceed as follows: instead
of using complex explicit declassification policies, we partition variables
in three sets: input, output and leakage variables. Then, we propose a
typing system to statically check that leakage variables do not leak more
information about the secret inputs than the public normal output. The
novelty of our approach is that we track the dependence of leakage variables with respect not only to the initial values of input variables (as
in classical approaches for noninterference), but taking also into account
the final values of output variables. We adapted this approach to LLVM
IR and we developed a prototype to verify LLVM implementations.
Keywords: Information flow · Output-sensitive non-interference · Type
system.
1
Introduction
An important task of cryptographic research is to verify cryptographic implementations for security flaws, in particular to avoid so-called timing attacks.
Such attacks consist in measuring the execution time of an implementation on
its execution platform. For instance, Brumley and Boneh [12] showed that it was
possible to mount remote timing attacks by against OpenSSL’s implementation
of the RSA decryption operation and to recover the key. Albrecht and Paterson
[3] showed that the two levels of protection offered against the Lucky 13 attack
from [2] in the first release of the new implementation of TLS were imperfect. A
⋆
This work is supported by the French National Research Agency in the framework
of the “Investissements d’ avenir” program (ANR-15-IDEX-02)
2
Cristian Ene, Laurent Mounier, and Marie-Laure Potet
related class of attacks are cache-based attacks in which a malicious party is able
to obtain memory-access addressses of the target program which may depend
on secret data through observing cache accesses. Such attacks allow to recover
the complete AES keys [17].
A possible countermeasure is to follow a very strict programming discipline
called constant-time programming. Its principle is to avoid branchings controlled by secret data and memory load/store operations indexed by secret data.
Recent secure C libraries such as NaCl [10] or mbedTLS1 follow this programming discipline. Until recently, there was no rigorous proof that constant-time
algorithms are protected to cache-based attacks. Moreover, many cryptographic
implementations such as PolarSSL AES, DES, and RC4 make array accesses
that depend on secret keys and are not constant time. Recent works [6, 4, 11] fill
this gap and develop the first formal analyzes that allow to verify if programs
are correct with respect to the constant-time paradigm.
An interesting extension was brought by Almeida et al. [4] who enriched
the constant-time paradigm “distinguishing not only between public and private
input values, but also between private and publicly observable output values”.
This distinction raises interesting technical and theoretical challenges. Indeed,
constant-time implementations in cryptographic libraries like OpenSSL include
optimizations for which paths and addresses can depend not only on public input
values, but also on publicly observable output values. Hence, considering only
input values as non-secret information would thus incorrectly characterize those
implementations as non-constant-time. [4] also develops a verification technique
based on symbolic execution. Howvere, the soundness of their approach depends
in practice on the soundness of the underlying symbolic execution engine, which
is very difficult to guarantee for real-world programs with loops. Moreover, their
product construction can be very expensive in the worst case.
In this paper we deal with statically checking programs for output-sensitive
constant-time correctness: programs can still do branchings or memory accesses controlled by secret data if the information that is leaked is subsumed by
the normal output of the program. To give more intuition about the property
that we want to deal with, let us consider the following example, where ct eq is
a constant time function that allows to compare the arguments:
good = 1;
for (i=0; i<B_Size; i++){good = good & ct_eq(secret[i],in_p[i]);}
if (!good) { for(i=0; i<B_Size; i++) secret[i] = 0; }
return good;
Let suppose that the array variable secret is secret, and all the other variables are public. Intuitively this a sort of one-time check password verifying that
in p = secret and otherwise overwrites the array secret with zero. Obviously,
this function is not constant-time as the variable good depends on secret, and
hence branching on good violates the principles of constant-time programming.
1
mbed TLS (formerly known as PolarSSL). https://tls.mbed.org/
Output-sensitive Information flow analysis
3
It is easy to transform this program into an equivalent one which is constant
time. For example one could replace
if (!good) { for(i=0; i<B_Size; i++) secret[i] = 0; }
by
for (i=0; i<B_Size; i++) {secret[i] = secret[i] & ct_eq(good,1);}
But branching on good is a benign optimization, since anyway, the value of good
is the normal output of the program. Hence, even if the function is not constanttime, it should be considered output-sensitive constant time with respect
to its specification. Such optimization opportunities arise whenever the interface
of the target application specifies what are the publicly observable outputs, and
this information is sufficient to classify the extra leakage as benign [4].
The objective of this work is to propose a static method to check if a program
is output-sensitive constant time secure. We emphasize that our goal is not to
verify that the legal output leaks “too much”, but rather to ensure that the
unintended (side-channel) output does not leak more than this legal output.
First, we propose a novel approach for verifying constant-time security based
on a new information flow property, called output-sensitive noninterference.
Information-flow security prevents confidential information to be leaked to public channels. Noninterference states that a public observer cannot learn anything
about the private data. Since real systems need to intentionally declassify some
information, this property is too strong. An alternative is relaxed noninterference which allows to specify explicit downgrading policies. In order to take into
account public outputs while staying independent of how programs intentionally declassify information, we develop an alternative solution: instead of using
complex explicit policies for functions, we partition variables in three sets: input, output and leakage variables. Hence we distinguish between the legal public
output and the information that can leak through side-channels, expressed by
adding fresh additional leakage variables. Then we propose a typing system that
can statically check that leakage variables do not leak more secret information
than the public normal output. The novelty of our approach is that we track the
dependence of leakage variables with respect to both the initial value of input
variables (as classically the case for noninterference) and final values of output
variables. Then, we show how to verify that a program written in a high-level
language is output-sensitive constant time secure by using this typing system.
Since timed and cache-based attacks target the executions of programs, it
is important to carry out this verification in a language close to the machineexecuted assembly code. Hence, we adapt our approach to a generic unstructured
assembly language inspired from LLVM and we show how we can verify programs
coded in LLVM. Finally, we developed a prototype tool implementing our type
system and we show how it can be used to verify LLVM implementations.
To summarize, this work makes the following contributions described above:
- in section 2 we reformulate output-sensitive constant-time as a new interesting
noninterference property and we provide a sound type system that guarantees
4
Cristian Ene, Laurent Mounier, and Marie-Laure Potet
(x := e, σ) −→ σ[x 7→ σ(e)]
(skip, σ) −→ σ
(c1 , σ) −→ σ ′
(c1 , σ) −→ (c′1 , σ ′ )
(c1 ; c2 , σ) −→ (c2 , σ ′ )
(c1 ; c2 , σ) −→ (c′1 ; c2 , σ ′ )
σ(e) = 1 ? i = 1 : i = 2
(If e then c1 else c2 fi , σ) −→ (ci , σ)
σ(e) 6= 1
(While e Do c oD , σ) −→ σ
σ(e) = 1
(While e Do c oD , σ) −→ (c; While e Do c oD , σ)
Fig. 1. Operational semantics of the While language
that well-typed programs are output-sensitive noninterferent;
- in section 3 we show that this general approach can be used to verify that
programs written in a high-level language are output-sensitive constant time;
- in section 4 we adapt our approach to the LLVM-IR language and we develop
a prototype tool that can be used to verify LLVM implementations.
An extended version of this paper, inluding all proofs and complete type
systems is available on-line2 .
2
Output-sensitive non-interference
2.1
The While language and Output-sensitive noninterference
In order to reason about the security of the code, we first develop our framework
in While, a simple high-level structured programming language. In section 3
we shall enrich this simple language with arrays and in section 4 we adapt our
approach to a generic unstructured assembly language. The syntax of While
programs is listed below:
c ::= x := e | skip | c1 ; c2 | If e then c1 else c2 fi | While e Do c oD
Meta-variables x, e and c range over the sets of program variables V ar, expressions and programs, respectively. We leave the syntax of expressions unspecified,
but we assume they are deterministic and side-effect free. The semantics is shown
in Figure 1. The reflexive and transitive closure of −→ is denoted by =⇒. A state
σ maps variables to values, and we write σ(e) to denote the value of expression
e in state σ. A configuration (c, σ) is a program c to be executed along with the
current state σ. Intuitively, if we want to model the security of some program c
with respect to side-channel attacks, we can assume that there are three special
2
https://www-verimag.imag.fr/∼Cristian.Ene/OSNI/main.pdf
Output-sensitive Information flow analysis
5
subsets of variables: XI the public input variables, XO the public output variables and XL the variables that leak information to some malicious adversary.
Then, output sensitive nonintereference asks that every two complete executions
starting with XI -equivalent states and ending with XO -equivalent final states
must be indistinguishable with respect to the leakage variables XL .
Definition 1. (adapted from [4]) Let XI , XO , XL ⊆ V ar be three sets of variables, intended to represent the input, the output and the leakage of a program.
A program c is (XI , XO , XL )-secure when all its executions starting with XI equivalent stores and leading to XO -equivalent final stores, give XL -equivalent
final stores. Formally, for all σ, σ ′ , ρ, ρ′ , if hc, σi =⇒ σ ′ and hc, ρi =⇒ ρ′ and
σ =XI ρ and σ ′ =XO ρ′ , then σ ′ =XL ρ′ .
2.2
Typing rules
This section introduces a type-based information flow analysis that allows to
check whether a While program is output-sensitive noninterferent, i.e. the program does not leak more information about the secret inputs than the public
normal output.
As usual, we consider a flow lattice of security levels L. An element x of L
is an atom if x 6= ⊥ and there exists no element y ∈ L such that ⊥ ⊏ y ⊏ x. A
lattice is called atomistic if every element is the join of atoms below it.
Assumption 2.21 Let (L, ⊓, ⊔, ⊥, ⊤) be an atomistic continuous bounded lattice. As usual, we denote t1 ⊑ t2 iff t2 = t1 ⊔ t2 . We assume that there exists a
distinguished subset TO ⊆ L of atoms.
Hence, from the above assumption, for any τo ∈ TO and for any t1 , t2 ∈ L:
1. τo ⊑ t1 ⊔ t2 implies τo ⊑ t1 or τo ⊑ t2 ,
2. τo ⊑ t1 implies that there exists t ∈ L such that t1 = t ⊔ τo and τ0 6⊑ t.
A type environment Γ : V ar 7→ L describes the security levels of variables
and the dependency with respect to the current values of variables in XO . In
order to catch dependencies with respect to current values of output variables,
we associate to each output variable o ∈ XO a fixed and unique symbolic type
α(o) ∈ TO . For example if some variable x ∈ V ar has the type Γ (x) = Low⊔α(o),
it means that the value of x depends only on public input and the current value
of the output variable o ∈ XO .
Hence, we^assume that there is a fixed injective
^ mapping α : X0 7→ T0
α(o) ∈ TO . We extend
o1 6= o2 ⇒ α(o1 ) 6= α(o2 ) ∧
such that
o1 ,o2 ∈XO
o∈XO
mappings Γ and α to sets of variables in the usual way: given A ⊆ V ar and
def G
def G
α(x).
Γ (x) , α(B) =
B ⊆ XO we note Γ (A) =
x∈A
x∈B
Our type system aims to satisfy the following output sensitive non-interference
condition: if the final values of output variables in XO remain the same, only
changes to initial inputs with types ⊑ t should be visible to leakage outputs with
type ⊑ t ⊔ α(XO ). More precisely, given a derivation ⊢α Γ {c}Γ ′ , the final value
6
Cristian Ene, Laurent Mounier, and Marie-Laure Potet
of a variable x with final type Γ ′ (x) = t ⊔ α(A) for some t ∈ L and A ⊆ XO ,
should depend at most on the initial values of those variables y with initial types
Γ (y) ⊑ t and on the final values of variables in A. We call “real dependencies”
the dependencies with respect to initial values of variables and “symbolic dependencies” the dependencies with respect to the current values of output variables.
Following [19] we formalize the non-interference condition satisfied by the typing
system using reflexive and symmetric relations.
We write =A0 for relation which relates mappings which are equal on all
values in A0 i.e. for two mappings f1 , f2 : A 7→ B and A0 ⊆ A, f1 =A0 f2 iff
∀a ∈ A0 , f1 (a) = f2 (a). For any mappings f1 : A1 7→ B and f2 : A2 7→ B, we
write f1 [f2 ] the operation which updates f1 according to f2 , namely (f1 [f2 ])(x) =
if x ∈ A2 then f2 (x) else f1 (x). Given Γ : V ar 7→ L , X ⊆ V ar and t ∈ L, we
write =Γ,X,t for the reflexive and symmetric relation which relates states that
are equal on all variables having type v ⊑ t in environment Γ , provided that
they are equal on all variables in X: σ =Γ,X,t σ ′ iff σ =X σ ′ ⇒ ∀x, (Γ (x) ⊑ t ⇒
σ(x) = σ ′ (x)) . When X = ∅, we omit it, hence we write =Γ,t instead of =Γ,∅,t .
Definition 2. [20] Let R and S be reflexive and symmetric relations on states.
We say that program c maps R into S, written c : R =⇒ S, iff ∀σ, ρ, if hc, σi =⇒
σ ′ and hc, ρi =⇒ ρ′ then σRρ ⇒ σ ′ Sρ′ .
The type system we propose enjoys the following useful property:
if ⊢α Γ {c}Γ ′ then c: =Γ,Γ (XI ) =⇒ =Γ ′ ,XO ,α(XO )⊔Γ (XI )
This property is an immediate consequence of Theorem 2.
Hence, in order to prove that the above program c is output sensitive noninterferent according to Definition 1, it is enough to check that for all xl ∈ XL ,
Γ ′ (xl ) ⊑ α(XO ) ⊔ Γ (XI ). Two executions of the program c starting from initial
states that coincide on input variables XI , and ending in final states that coincide
on output variables XO , will coincide also on the leaking variables XL .
We now formally introduce our typing system. Due to assignments, values and
types of variables change dynamically. For example let us assume that at some
point during the execution, the value of x depends on the initial value of some
variable y and the current value of some output variable o (which itself depends
on the initial value of some variable h), formally captured by an environment Γ
where Γ (o) = Γ0 (h) and Γ (x) = Γ0 (y) ⊔ α(o), where Γ0 represents the initial
environment. If the next to be executed instruction is some assignment to o, then
the current value of o will change, so we have to mirror this in the new type of x:
even if the value of x does not change, its new type will be Γ ′ (x) = Γ0 (y) ⊔ Γ0 (h)
(assuming that α(o) 6⊑ Γ0 (y)). Hence Γ ′ (x) is obtained by replacing in Γ (x) the
symbolic dependency α(o) with the real dependency Γ (o).
Definition 3. If t0 ∈ TO is an atom and t′ , t ∈ L are arbitrary types, then we denote by t[t′ /t0 ] the type obtained by replacing (if any) the occurrence of t0 by t′ in
the decomposition in atoms of t. Now we extend this definition to environments:
def
let x ∈ XO and p ∈ L. Then Γ1 = Γ ⊳α x represents the environment where the
symbolic dependency on the last value of x of all variables is replaced by the real
def
def
type of x: Γ1 (y) = (Γ (y))[Γ (x)/α(x)]. Similarly, (p, Γ ) ⊳α x = p[Γ (x)/α(x)].
Output-sensitive Information flow analysis
As1
x 6∈ XO
p ⊢α Γ {x := e}Γ [x 7→ p ⊔ Γ [α](f v(e))]
Skip
Seq
p ⊢α Γ {skip}Γ
p ⊢α Γ {c1 }Γ1
As3
p ⊢α Γ1 {c2 }Γ2
p ⊢α Γ {c1 ; c2 }Γ2
As2
x ∈ XO \ f v(e)
7
Γ1 = Γ ⊳α x
p ⊢α Γ {x := e}Γ1 [x 7→ p ⊔ Γ1 [α](f v(e))]
x ∈ XO ∩ f v(e)
Γ1 = Γ ⊳α x
p ⊢α Γ {x := e}Γ1 [x 7→ p ⊔ Γ (x) ⊔ Γ1 [α](f v(e) \ x)]
Sub
Γ ⊑ Γ′
p0 ⊑ p1
p1 ⊢α Γ ′ {c}Γ1′
Γ1′ ⊑ Γ1
p0 ⊢α Γ {c}Γ1
p′ = (Γ [α](f v(e)), Γ ) ⊳α (aff O (c1 ) ∪ aff O (c2 ))
If
Γ ′ = Γ1 ⊳α aff O (c2 ) ⊔ Γ2 ⊳α aff O (c1 )
p ⊔ p′ ⊢α Γ {ci }Γi
p ⊢α Γ {If e then c1 else c2 fi }Γ ′
pe = (Γ [α](f v(e)), Γ ) ⊳α aff O (c)
Wh
p ⊔ pe ⊢α Γ {c}Γ ′
Γ ′ ⊔ (Γ ⊳α aff O (c)) ⊑ Γ
p ⊢α Γ {While e Do c oD }Γ
Fig. 2. Flow-sensitive typing rules for commands with output
We want now to extend the above definition from a single output variable x to
subsets X ⊆ XO . Our typing system will ensure that each generated environment
Γ will not contain circular symbolic dependencies between output variables,
i.e., there are no output variable o1 , o2 ∈ XO such that α(o1 ) ⊑ Γ (o2 ) and
α(o2 ) ⊑ Γ (o1 ). We can associate a graph G(Γ ) = (XO , E) to an environment
Γ , such that (o1 , o2 ) ∈ E iff α(o1 ) ⊑ Γ (o2 ). We say that Γ is well formed,
denoted AC(Γ ), if G(Γ ) is an acyclic graph. For acyclic graphs G(Γ ) we extend
Definition 3 to subsets X ⊆ XO , by first fixing an ordering X = {x1 , x2 , . . . xn }
of variables in V compatible with the graph (i.e. j ≤ k implies that there is no
def
path from xk to xj ), and then (p, Γ ) ⊳α X = (((p, Γ ) ⊳α x1 ) ⊳α x2 ) . . . ⊳α xn .
Let aff (c) be the set of assigned variables in a program c and let us denote
def
def
aff I (c) = aff (c) ∩ (V ar \ XO ) and aff O (c) = aff (c) ∩ XO . We define the
^
def
Γ1 (x) ⊑ Γ2 (x). For a command
ordering over environments: Γ1 ⊑ Γ2 =
x∈V ar
c, judgements have the form p ⊢α Γ {c}Γ ′ where p ∈ L and Γ and Γ ′ are type
environments well-formed. The inference rules are shown in Figure 2. The idea
is that if Γ describes the security levels of variables which hold before execution
of c, then Γ ′ will describe the security levels of those variables after execution of
c. The type p represents the usual program counter level and serves to eliminate
indirect information flows; the derivation rules ensure that all variables that can
be changed by c will end up (in Γ ′ ) with types greater than or equal to p. As
usual, whenever p = ⊥ we drop it and write ⊢α Γ {c}Γ ′ instead of ⊥ ⊢α Γ {c}Γ ′ .
Throughout this paper the type of an expression e is defined simply by taking the
lub of the types of its free variables Γ [α](f v(e)), for example the type of x+y +o
8
Cristian Ene, Laurent Mounier, and Marie-Laure Potet
p = ⊥,
Γ0 = [y → Y, z → Z, o1 → O1 , o2 → O2 ]
(1) o1 := x + 1
Γ1 = [y → Y, z → Z, o1 → X, o2 → O2 ]
(2) y := o1 + z
Γ2 = [y → O1 ⊔ Z, z → Z, o1 → X, o2 → O2 ]
(3) o1 := u
Γ3 = [y → X ⊔ Z, z → Z, o1 → U, o2 → O2 ]
(4) z := o1 + o3
Γ4 = [y → X ⊔ Z, z → O1 ⊔ O3 , o1 → U, o2 → O2 ]
(5) If (o2 = o3 + x)
p = O3 ⊔ O2 ⊔ X
(6) then o1 := o2
Γ6 = [y → X ⊔ Z, z → U ⊔ O3 , o1 → O3 ⊔ O2 ⊔ X ⊔ O2 , o2 → O2 ]
(7) else o2 := o1
Γ7 = [y → X ⊔ Z, z → O1 ⊔ O3 , o1 → U, o2 → O3 ⊔ O2 ⊔ X ⊔ O1 ]
(8) fi
Γ8 = (Γ6 ⊳α o2 ) ⊔ (Γ7 ⊳α o1 ) = [y → X ⊔ Z, z → U ⊔ O3 ,
o1 → O3 ⊔ O2 ⊔ X ⊔ U, o2 → O3 ⊔ O2 ⊔ X ⊔ U]
Fig. 3. Example of application for our typing system
where o is the only output variable is Γ (x) ⊔ Γ (y) ⊔ α(o). This is consistent
with the typings used in many systems, though more sophisticated typing rules
for expressions would be possible in principle. Notice that considering the type
of an expression to be Γ [α](f v(e)) instead of Γ (f v(e)) allows to capture the
dependencies with respect to the current values of output variables. In order to
give some intuition about the rules, we present a simple example in Figure 3.
Example 1. Let {x, y, z, u} ⊆ V ar \XO and {o1 , o2 , o3 } ⊆ XO be some variables,
and let us assume that ∀i ∈ {1, 2, 3}, α(oi ) = Oi . We assume that the initial
environment is Γ0 = [x → X, y → Y, z → Z, u → U, o1 → O1 , o2 → O2 , o3 →
O3 ]. Since the types of variables x, u and o3 do not change, we omit them in the
following. We highlighted the changes with respect to the previous environment.
After the first assignment, the type of o1 becomes X, meaning that the current
value of o1 depends on the initial value of x. After the assignment y := o1 + z,
the type of y becomes O1 ⊔ Z, meaning that the current value of y depends on
the initial value of z and the current value of o1 . After the assignment o1 = u,
the type of y becomes X ⊔ Z as o1 changed and we have to mirror this in the
dependencies of y, and the type of o1 becomes X. When we enter in the If , the
program counter level changes to p = O3 ⊔ O2 ⊔ X as the expression o2 = o3 + x
depends on the values of variables o2 , o3 , x, but o2 and o3 are output variables
and o2 will be assigned by the If command, hence we replace the “symbolic”
dependency α(o2 ) = O2 by its “real” dependency Γ (o2 ) = O2 . At the end of
the If command, we do the join of the two environments obtained after the
both branches, but in order to prevent cycles, we first replace the “symbolic”
Output-sensitive Information flow analysis
9
dependencies by the corresponding “real” dependencies for each output variable
that is assigned by the other branch.
As already stated above, our type system aims to capture the following noninterference condition: given a derivation p ⊢α Γ {c}Γ ′ , the final value of a variable x with final type t ⊔ α(XO ), should depend at most on the initial values of
those variables y with initial types Γ (y) ⊑ t and on the final values of variables in
XO . Or otherwise said, executing a program c on two initial states σ and ρ such
that σ(y) = ρ(y) for all y with Γ (y) ⊑ t which ends with two final states σ ′ and
ρ′ such that σ ′ (o) = ρ′ (o) for all o ∈ XO will satisfy σ ′ (x) = ρ′ (x) for all x with
Γ ′ (x) ⊑ t⊔α(XO ). In order to prove the soundness of the typing system, we need
a stronger invariant denoted I(t, Γ ): intuitively, (σ, ρ) ∈ I(t, Γ ) means that for
each variable x and A ⊆ XO , if σ =A ρ and Γ (x) ⊑ t ⊔ α(A), then σ(x) = ρ(x).
def \
Formally, given t ∈ L and Γ : V ar 7→ L, we define I(t, Γ ) =
=Γ,A,α(A)⊔t .
A⊆XO
The following theorem states the soundness of our typing system.
Theorem 1. Let us assume that AC(Γ ) and ∀o ∈ XO , α(o) 6⊑ t. If p ⊢α Γ {c}Γ ′
then c : I(t, Γ ) =⇒ I(t, Γ ′ ).
2.3
Soundness w.r.t. to output-sensitive non-interference
In this section we show how we can use the typing system in order to prove that
a program c is output-sensitive noninterferent. Let V are = V ar ∪ {o | o ∈ XO }.
def
Let us define L = {τA | A ⊆ V are }. We denote ⊥ = τ∅ and ⊤ = τV are and we
def
consider the lattice (L, ⊥, ⊤, ⊑) with τA ⊔ τA′ = τA∪A′ and τA ⊑ τA′ iff A ⊆ A′ .
The following Theorem is a consequence of the Definition 1 and Theorem 1.
Theorem 2. Let L be the lattice described above. Let (Γ, α) be defined by Γ (x) =
{τx }, for all x ∈ V ar and α(o) = {τo }, for all o ∈ XO . If ⊢α Γ {c}Γ ′ and for all
xl ∈ XL , Γ ′ (xl ) ⊑ Γ (XI ) ⊔ α(XO ), then c is (XI , XO , XL )-secure.
3
Output-sensitive constant-time
Following [1, 4], we consider two types of cache-based information leaks: 1) disclosures that happen when secret data determine which parts of the program are
executed; 2) disclosures that arise when acces to memory is indexed by sensitive
information. In order to model the latter category, we shall enrich the simple
language from section 2.2 with arrays:
c ::= x := e | x[e1 ] := e | skip | c1 ; c2 | If e then c1 else c2 fi | While e Do c oD
To simplify notations, we assume that array indexes e1 are basic expressions
(not referring to arrays) and that XO does not contain arrays. Moreover as in
[4], a state or store σ maps array variables v and indices i ∈ to values σ(v, i).
The labeled semantics of While programs are listed in Figure 4. In all rules, we
◆
10
Cristian Ene, Laurent Mounier, and Marie-Laure Potet
→
−
act ≡ r(σ( f ))
→
−
act ≡ w(σ(e1 )) : r(σ( f ))
act
(x := e, σ) −→ σ[(x, 0) 7→ σ(e)]
σ(e) 6= 1
act
(x[e1 ] := e, σ) −→ σ[(x, σ(e1 )) 7→ σ(e)]
→
−
act ≡ b(σ(e)) : r(σ( f ))
act
(While e Do c oD , σ) −→ σ
σ(e) = 1
→
−
act ≡ b(σ(e)) : r(σ( f ))
act
(While e Do c oD , σ) −→ (c; While e Do c oD , σ)
→
−
act ≡ b(σ(e)) : r(σ( f ))
σ(e) = 1 ? i = 1 : i = 2
act
(If e then c1 else c2 fi , σ) −→ (ci , σ)
Fig. 4. Syntax and Labeled Operational semantics
As1’
x 6∈ XO
→
−
p ⊢ct
Γ
{x
:=
e}Γ
[x
→
7
p
⊔
Γ
[α](f
v(e))][xl 7→ Γ (xl ) ⊔ Γ [α](f v( f )))]
α
x 6∈ XO
As1”
If
p1 = (Γ [α](f v(e1 ), f v(e))
→
−
pl = (Γ [α](f v(e1 ), f v( f ))
p ⊢ct
α Γ {x[e1 ] := e}Γ [x 7→ p ⊔ Γ (x) ⊔ p1 ][xl 7→ Γ (xl ) ⊔ pl ]
p′ = (Γ [α](f v(e)), Γ ) ⊳α aff O (c1 ; c2 )
→
−
pl = (Γ [α](f v( f )), Γ ) ⊳α aff O (c1 ; c2 )
p
⊢ct
α
p ⊔ p′ ⊢ct
α Γ {ci }Γi
Γ = Γ1 ⊳α aff O (c2 ) ⊔ Γ2 ⊳α aff O (c1 )
′
Γ {If e then c1 else c2 fi }Γ ′ [xl 7→ Γ ′ (xl ) ⊔ pl ⊔ p′ ]
Fig. 5. Typing Rules for Output Sensitive Constant Time (excerpts)
→
−
denote f = (fi )i , where xi [fi ] are the indexed variables in e. The labels on the
execution steps correspond to the information which is leaked to the environment
(r() for a read access on memory, w() for a write access and b() for a branch operation). In the rules for (If) and (While) the valuations of branch conditions are
leaked. Also, all indexes to program variables read and written at each statement
are exposed. We give in Fig. 5 an excerpts of the new typing rules. As above,
→
−
we denote f = (fi )i , where xi [fi ] are the indexed variables in e. We add a fresh
variable xl , that is not used in programs, in order to capture the unintended
leakage. Its type is always growing and it mirrors the information leaked by each
command. In rule (As1”) we take a conservative approach and we consider that
the type of an array variable is the lub of all its cells. The information leaked
→
−
by the assignment x[e1 ] := e is the index e1 plus the set f = (fi )i of all indexes
occurring in e. Moreover, the new type of the array variable x mirrors the fact
that now the value of x depends also on the index e1 and the right side e.
a
a
a
1
2
n
Definition 4. An execution is a sequence of visible actions: −→
−→
. . . −→.
A program c is (XI , XO )-constant time when all its executions starting with
XI -equivalent stores that lead to finally XO -equivalent stores, are identical.
Following [4], given a set X of program variables, two stores σ and ρ are Xequivalent when σ(x, i) = ρ(x, i) for all x ∈ X and i ∈ . Two executions
a1
an
b1
bm
◆
−→ . . . −→ and −→ . . . −→ are identical iff n = m and aj = bj for all
1 ≤ j ≤ n. We can reduce the (XI , XO )-constant time security of a command
Output-sensitive Information flow analysis
11
ω(•)
•
−
→
x := e
xl := xl : r( f ); x := e
−
→
x[e1 ] := e
xl := xl : w(e1 ) : r( f ); x[e1 ] := e
skip
skip
c1 ; c2
ω(c1 ); ω(c2 )
−
→
If e then c1 else c2 fi xl := xl : b(e) : r( f ); If e then ω(c1 ) else ω(c2 ) fi
−
→
−
→
While e Do c oD
xl := xl : b(e) : r( f ); While e Do ω(c); xl := xl : b(e) : r( f ) oD
Fig. 6. Instrumentation for ω(•)
c to the (XI , XO , {xl })-security (see section 2.3) of a corresponding command
ω(c), obtained by adding a fresh variable xl to the program variables f v(c),
and then adding recursively before each assignment and each boolean condition predicate, a new assignment to the leakage variable xl that mirrors the
leaked information. Let :, b(, )r(, )w() be some new abstract operators. The construction of the instrumentation ω(•) is shown in Fig. 6. As above, we denote
→
−
f = (fi )i , where xi [fi ] are the indexed variables in e. Then, we extend, as in
the rules As1′ , Ass1” from Fig 5, the typing system from section 2.2 to take into
account the array variables. The following lemma holds.
Lemma 1. Let c a command such that xl 6∈ f v(c), σ, σ ′ two stores , tr some
execution trace and [] the empty trace.
′
′
1. p ⊢ct
α Γ {c}Γ iff p ⊢α Γ {ω(c)}Γ .
tr ∗
2. (c, σ) −→ σ ′ iff (ω(c), σ[xl 7→ []]) −→∗ σ ′ [xl 7→ tr].
Now combining Theorem 2 and Lemma 1 we get the following Theorem.
Theorem 3. Let L be the lattice defined in the section 2.3. Let (Γ, α) be defined
by Γ (x) = {τx }, for all x ∈ V ar and α(o) = {τo }, for all o ∈ XO and Γ (xl ) = ⊥.
′
′
If p ⊢ct
α Γ {c}Γ and Γ (xl ) ⊑ Γ (XI )⊔α(XO ), then c is (XI , XO )- constant time.
4
Application to low-level code
We show in this section how the type system we proposed to express outputsensitive constant-time non-interference on the While language can be lifted to
a low-level program representation like the LLVM byte code [21].
4.1
LLVM-IR
We consider a simplified LLVM-IR representation with four instructions: assignments from a temporary expression (register or immediate value) or from a memory location (load), writing to a memory location (store) and (un)conditional
jump instructions. We assume that the program control flow is represented by a
control-flow graph (CFG) G = (B, →E , binit ) where B is the set of basic blocks,
12
Cristian Ene, Laurent Mounier, and Marie-Laure Potet
→
r ← op(Op, −
v)
r ← load(v)
store(v1 , v2 )
cond(r, bthen , belse )
goto b
→
assign to r the result of Op applied to operands −
v
load in r the value stored at address v
store at address v2 the value stored at address v1
branch to bthen if the value of r is true and to bf alse otherwise
branch to b
Fig. 7. Syntax and informal semantics of simplified LLVM-IR
→E the set of edges connecting the basic blocks, and binit ∈ B the entry point.
We denote by Reach(b, b′ ) the predicate indicating that there exists a path from
b to b′ . A program is a (partial) map from control points (b, n) ∈ B × N to instructions. Each basic block is terminated by a jump instruction. The memory
model consists in a set of registers R and the memory M (including the execution
stack). V al is the set of values and memory addresses. The informal semantics
of our simplified LLVM-IR is given in Figure 7, where r ∈ R and v ∈ R ∪ V al.We
consider an operational semantics where execution steps are labelled with leaking
data, i.e., addresses of store and load operations and branching conditions.
4.2
Type system
For a CFG G = (B, →E , binit ):
1. Function dep : B → 2B associates to each basic block its set of “depending
blocks”, i.e., b′ ∈ dep(b) iff b′ dominates b and there is no block b” between b′
and b such that b” post-dominates b′ . We recall that a node b1 dominates (resp.
post-dominates) a node b2 iff every path from the entry node to b2 goes through
b1 (resp. every path from b2 to the ending node goes through b1 ).
2. Partial function br : B → R returns the “branching register”, i.e., the register
r used to compute the branching condition leading outside b (b is terminated by
an instruction cond(r, bthen , belse )). Note that in LLVM branching registers are
always fresh and assigned only once before to be used.
3. Function P ointsT o : (B×N)×V al → 2R returns the set of registers containing
memory locations pointed to by a given address at a given control point. For
example, for a given address v, r ∈ P ointsT o(b, n)(v) means that register r
contains a memory address pointed to by v.
We define a type system to express output-sensitive constant-time property
on LLVM-IR. The main differences from the rules at the source level is that
the control-flow is explicitly given by the CFG. For lack of space we describe
only the rule for the Store instruction (Figure 8). It updates the type of v1 by
adding the dependencies of all memory locations pointed to by v2. In addition,
the type of the leakage variable xl is also updated with the dependencies of all
these memory locations lying in Am (since these locations are read).
Output-sensitive Information flow analysis
p(b, n) = store(v1 , v2 )
G
τ0 =
Γ [α](x)
St
Am = P ointsT o(b, n)(v2 )
A0 = Am ∩ X 0
τ1 = Γ1 [α](v2 ) ⊔ τ0
13
Γ1 = (Γ, α) ⊳ A0
τ2 = Γ1 [α](v1 )
x∈br(dep(b))
⊢α (b, n) : Γ ⇒ Γ1 [xl → Γ1 (xl ) ⊔ τ1 ][vs∈Am → Γ (vs ) ⊔ τ2 ⊔ τ0 ]
Fig. 8. store instruction
4.3
Well typed LLVM programs are output-sensitive constant-time
Definition 5. An LLVM-IR program p is well typed with respect to an initial
environment Γ0 and final environment Γ ′ (written ⊢α p : Γ0 ⇒ Γ ′ ) , if there is
a family of well-defined environments {(Γ )(b,n) | (b, n) ∈ (B, )}, such that for
all nodes (b, n) and all its successors (b′ , n′ ), there exists a type environment γ
and A ⊆ XO such that ⊢α (b, n) : Γ(b,n) ⇒ γ and (γ ⊳α A) ⊑ Γ(b′ ,n′ ) .
◆
In the above definition the set A is mandatory in order to prevent dependency
cycles between variables in XO . The following Theorem shows the soundness of
the typing system with respect to output-sensitive constant-time.
Theorem 4. Let L be the lattice from the section 2.3. Let (Γ, α) be defined by
Γ (x) = {τx }, for all x ∈ R ∪ M , α(o) = {τo }, for all o ∈ XO and Γ (xl ) = ⊥. If
⊢α p : Γ ⇒ Γ ′ and Γ ′ (xl ) ⊑ Γ (XI ) ⊔ α(XO ), then p is (XI , XO )- constant time.
4.4
Implementation
We developed a prototype tool implementing the type system for LLVM programs. This type system consists in computing flow-sensitive dependency relations between program variables. Def. 5 provides the necessary conditions under
which the obtained result is sound (Theorem 4). We give some technical indications regarding our implementation.
Output variables XO are defined as function return values and global variables; we do not currently consider arrays nor pointers in XO . Control dependencies cannot be deduced from the syntactic LLVM level, we need to explicitly compute the dominance relation between basic blocks of the CFG (the dep
function). Def. 5 requires the construction of a set A ⊆ XO to update the
environment produced at each control locations in order to avoid circular dependencies (when output variable are assigned in alternative execution paths).
To identify the set of basic blocks belonging to such alternative execution paths
leading to a given block, we use the notion of Hammock regions [15]. More precisely, we compute function Reg : (B × B × (→E )) → 2B , returning the set of
Hammock regions between a basic block b and its immediate dominator b′ with
respect to an incoming edge ei of b. Thus, Reg(b′ , b, (c, b)) is the set of blocks
belonging to CFG paths going from b′ to b without reaching edge ei = (c, b):
Reg(b′ , b, (c, b)) = {bi | b′ →E b1 · · · →E bn →E b∧∀i ∈ [1, n−1]. ¬Reach(bi , c)}.
14
Cristian Ene, Laurent Mounier, and Marie-Laure Potet
Fix-point computations are implemented using Kildall’s algorithm. To better
handle real-life examples we are currently implementing the P ointsT o function,
an inter-procedural analysis, and a more precise type analysis combining both
over- and under-approximations of variable dependencies (see section 6).
5
Related Work
Information flow. There is a large number of papers on language-based security aiming to prevent undesired information flows using type systems (see [26]).
An information-flow security type system statically ensures noninterference, i.e.
that sensitive data may not flow directly or indirectly to public channels [30, 24,
29, 28]. The typing system presented in section 2.2 builds on ideas from Hunt
and Sands’ flow-sensitive static information-flow analysis [20].
As attractive as it is, noninterference is too strict to be useful in practice, as
it prevents confidential data to have any influence on observable, public output:
even a simple password checker function violates noninterference. Relaxed definitions of noninterference have been defined in order to support such intentional
downward information flows [27]. Li and Zdancewic [22] proposed an expressive
mechanism called relaxed noninterference for declassification policies that supports the extensional specification of secrets and their intended declassification.
A declassification policy is a function that captures the precise information on a
confidential value that can be declassified. For the password checker example, the
following declassification policy λp.λx.h(p) == x, allows an equality comparison
with the hash of password to be declassified (and made public), but disallows
arbitrary declassifications such as revealing the password.
The problem of information-flow security has been studied also for low level
languages. Barthe and Rezk [8, 9] provide a flow sensitive type system for a
sequential bytecode language. As it is the case for most analyses, implicit flows
are forbidden, and hence, modifications of parts of the environment with lower
security type than the current context are not allowed. Genaim and Spoto present
in [16] a compositional information flow analysis for full Java bytecode.
Information flow applied to detecting side-channel leakages. Informationflow analyses track the flow of information through the program but often ignore
information flows through side channels. Side-channel attacks extract sensitive
information about a program’s state through its observable use of resources such
as time or memory. Several approaches in language-based security use security
type systems to detect timing side-channels [1, 18]. Agat [1] presents a type
system sensitive to timing for a small While-language which includes a transformation which takes a program and transforms it into an equivalent program
without timing leaks. Molnar et al [23] introduce the program counter model,
which is equivalent to path non-interference, and give a program transformation
for making programs secure in this model.
FlowTracker [25] allows to statically detect time-based side-channels in LLVM
programs. Relying on the assumption that LLVM code is in SSA form, they compute control dependencies using a sparse analysis [13] without building the whole
Output-sensitive Information flow analysis
15
Program Dependency Graph. Leakage at assembly-level is also considered in [6].
They propose a fine-grained information-flow analysis for checking that assembly
programs generated by CompCert are constant-time. Moreover, they consider a
stronger adversary which controls the scheduler and the cache.
All the above works do not consider publicly observable outputs. The work
that is closest to ours is [4], where the authors develop a formal model for
constant-time programming policies. The novelty of their approach is that it is
distinguishing not only between public and private input values, but also between
private and publicly observable output values. As they state, this distinction
poses interesting technical and theoretical challenges. Moreover, constant-time
implementations in cryptographic libraries like OpenSSL include optimizations
for which paths and addresses can depend not only on public input values, but
also on publicly observable output values. Considering only input values as nonsecret information would thus incorrectly characterize those implementations
as non-constant-time. They also develop a verification technique based on the
self-composition based approach [7]. They reduce the constant time security
of a program P to safety of a product program Q that simulates two parallel
executions of P. The tool operates at the LLVM bytecode level. The obtained
bytecode program is transformed into a product program which is verified by the
Boogie verifier [5] and its SMT tool suite. Their approach is complete only if the
public output is ignored. Otherwise, their construction relies on identifying the
branches whose conditions can only be declared benign when public outputs are
considered. For all such branches, the verifier needs to consider separate paths
for the two simulated executions, rather than a single synchronized path and in
the worst case this can deteriorate to an expensive product construction.
6
Conclusion and Perspectives
In this paper we proposed a static approach to check if a program is outputsensitive constant-time, i.e., if the leakage induced through branchings and/or
memory accesses do not overcome the information produced by (regular) observable outputs. Our verification technique is based on a so-called output-sensitive
non-interference property, allowing to compute the dependencies of a leakage
variable from both the initial values of the program inputs and the final values
of its outputs. We developed a type system on a high-level While language, and
we proved its soundness. Then we lifted this type system to a basic LLVM-IR
and we developed a prototype tool operating on this intermediate representation,
showing the applicability of our technique.
This work could be continued in several directions. One limitation of our
method arising in practice is that even if the two snippets xl = h; o = h and
o = h; xl = o are equivalent, only the latter can be typed by our typing system. We are currently extending our approach by considering also an underapproximation β(•) of the dependencies between variables and using “symbolic
dependencies” also for non-output variables. Then the safety condition from
Theorem 2 can be improved to something like ”∃V such that (Γ ′ (xl ) ⊳α V ) ⊑
16
Cristian Ene, Laurent Mounier, and Marie-Laure Potet
(Γ (XI ) ⊳α V ) ⊔ (β ′ (XO ) ⊳α V ) ⊔ α(XO )”. In the above example, we would obtain Γ ′ (xl ) = α(h) = β ′ (o) ⊑ α(o) ⊔ β ′ (o), meaning that the unwanted maximal
leakage Γ ′ (xl ) is less than the minimal leakage β ′ (o) due to the normal output.
From the implementation point of view, further developments are needed in order to extend our prototype to a complete tool able to deal with real-life case
studies. This may require to refine our notion of arrays and to take into account
arrays and pointers as output variables. We could also consider applying a sparse
analysis, as in FlowTracker [25]. It may happen that such a pure static analysis
would be too strict, rejecting too much “correct” implementations. To solve this
issue, a solution would be to combine it with the dynamic verification technique
proposed in [4]. Thus, our analysis could be used to find automatically which
branching conditions are benign in the output-sensitive sense, which could reduce the product construction of [4]. Finally, another interesting direction would
be to adapt our work in the context of quantitative analysis for program leakage,
like in [14].
References
1. Agat, J.: Transforming out timing leaks. In: Proceedings of the 27th ACM
SIGPLAN-SIGACT symposium on Principles of programming languages. pp. 40–
53. ACM (2000)
2. Al Fardan, N.J., Paterson, K.G.: Lucky thirteen: Breaking the tls and dtls record
protocols. In: Security and Privacy (SP), 2013 IEEE Symposium on. pp. 526–540.
IEEE (2013)
3. Albrecht, M.R., Paterson, K.G.: Lucky microseconds: A timing attack on amazon’s
s2n implementation of tls. In: Annual International Conference on the Theory and
Applications of Cryptographic Techniques. pp. 622–643. Springer (2016)
4. Almeida, J.B., Barbosa, M., Barthe, G., Dupressoir, F., Emmi, M.: Verifying constant-time implementations. In: 25th USENIX Security Symposium (USENIX Security 16). pp. 53–70. USENIX Association, Austin,
TX
(2016),
https://www.usenix.org/conference/usenixsecurity16/technicalsessions/presentation/almeida
5. Barnett, M., Chang, B.Y.E., DeLine, R., Jacobs, B., Leino, K.R.M.: Boogie: A
modular reusable verifier for object-oriented programs. In: FMCO. vol. 5, pp. 364–
387. Springer (2005)
6. Barthe, G., Betarte, G., Campo, J., Luna, C., Pichardie, D.: System-level noninterference for constant-time cryptography. In: Proceedings of the 2014 ACM
SIGSAC Conference on Computer and Communications Security. pp. 1267–1279.
ACM (2014)
7. Barthe, G., D’Argenio, P.R., Rezk, T.: Secure information flow by self-composition.
In: Computer Security Foundations Workshop, 2004. Proceedings. 17th IEEE. pp.
100–114. IEEE (2004)
8. Barthe, G., Rezk, T.: Secure information flow for a sequential java virtual machine.
In: TLDI’05: Types in Language Design and Implementation. Citeseer (2003)
9. Barthe, G., Rezk, T., Basu, A.: Security types preserving compilation. Computer
Languages, Systems & Structures 33(2), 35–59 (2007)
10. Bernstein, D., Lange, T., Schwabe, P.: The security impact of a new cryptographic
library. Progress in Cryptology–LATINCRYPT 2012 pp. 159–176 (2012)
Output-sensitive Information flow analysis
17
11. Blazy, S., Pichardie, D., Trieu, A.: Verifying constant-time implementations by abstract interpretation. In: European Symposium on Research in Computer Security.
pp. 260–277. Springer (2017)
12. Brumley, D., Boneh, D.: Remote timing attacks are practical. Computer Networks
48(5), 701–716 (2005)
13. Choi, J.D., Cytron, R., Ferrante, J.: Automatic construction of sparse data flow
evaluation graphs. In: Proceedings of the 18th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages. pp. 55–66. POPL ’91, ACM (1991)
14. Doychev, G., Köpf, B., Mauborgne, L., Reineke, J.: Cacheaudit: A tool for the static
analysis of cache side channels. ACM Trans. Inf. Syst. Secur. 18(1), 4:1–4:32 (Jun
2015). https://doi.org/10.1145/2756550, http://doi.acm.org/10.1145/2756550
15. Ferrante, J., Ottenstein, K., Warren, J.: The program dependence graph and its
use in optimization. TOPLAS 9(3), 319–349 (1987)
16. Genaim, S., Spoto, F.: Information flow analysis for java bytecode. In: Verification,
Model Checking, and Abstract Interpretation. pp. 346–362. Springer (2005)
17. Gullasch, D., Bangerter, E., Krenn, S.: Cache games–bringing access-based cache
attacks on aes to practice. In: Security and Privacy (SP), 2011 IEEE Symposium
on. pp. 490–505. IEEE (2011)
18. Hedin, D., Sands, D.: Timing aware information flow security for a javacardlike bytecode. Electronic Notes in Theoretical Computer Science 141(1), 163–182
(2005)
19. Hunt, S., Sands, D.: Binding time analysis: A new perspective. In: In Proceedings of the ACM Symposium on Partial Evaluation and Semantics-Based Program
Manipulation (PEPM’91). pp. 154–164. ACM Press (1991)
20. Hunt, S., Sands, D.: On flow-sensitive security types. In: ACM SIGPLAN Notices.
vol. 41, pp. 79–90. ACM (2006)
21. Lattner, C., Adve, V.: Llvm: A compilation framework for lifelong program analysis & transformation. In: Proceedings of the International Symposium on Code
Generation and Optimization: Feedback-directed and Runtime Optimization. CGO
’04, IEEE Computer Society, Washington, DC, USA (2004)
22. Li, P., Zdancewic, S.: Downgrading policies and relaxed noninterference. In: Proceedings of POPL. vol. 40, pp. 158–170. ACM (2005)
23. Molnar, D., Piotrowski, M., Schultz, D., Wagner, D.: The program counter security
model: Automatic detection and removal of control-flow side channel attacks. In:
ICISC. vol. 3935, pp. 156–168. Springer (2005)
24. Myers, A.C.: Jflow: Practical mostly-static information flow control. In: Proceedings of the 26th ACM SIGPLAN-SIGACT symposium on Principles of programming languages. pp. 228–241. ACM (1999)
25. Rodrigues, B., Quintão Pereira, F.M., Aranha, D.F.: Sparse representation of implicit flows with applications to side-channel detection. In: Proceedings of the 25th
International Conference on Compiler Construction. pp. 110–120. ACM (2016)
26. Sabelfeld, A., Myers, A.C.: Language-based information-flow security. IEEE Journal on selected areas in communications 21(1), 5–19 (2003)
27. Sabelfeld, A., Sands, D.: Declassification: Dimensions and principles. Journal of
Computer Security 17(5), 517–548 (2009)
28. Swamy, N., Chen, J., Chugh, R.: Enforcing stateful authorization and information
flow policies in fine. In: ESOP. pp. 529–549. Springer (2010)
29. Vaughan, J.A., Zdancewic, S.: A cryptographic decentralized label model. In: Security and Privacy, 2007. SP’07. IEEE Symposium on. pp. 192–206. IEEE (2007)
30. Volpano, D., Irvine, C., Smith, G.: A sound type system for secure flow analysis.
Journal of computer security 4(2-3), 167–187 (1996)