Recently, much progress has been made on achieving information-flow security via secure multi-execution. Secure multi-execution () is an elegant way to enforce security by executing a given program multiple times, once for each security level, while carefully dispatching inputs and ensuring that an execution at a given level is responsible for producing outputs for information sinks at that level. Secure multi-execution guarantees noninterference, in the sense of no dependencies from secret inputs to public outputs, and transparency, in the sense that if a program is secure then its secure multi-execution does not disable any of its original behavior.
This paper pushes the boundary of what can be achieved with secure multi-execution. First, we lift the assumption from the original secure multi-execution work on the totality of the input environment (that there is always assumed to be input) and on cooperative scheduling. Second, we generalize secure multi-execution to distinguish between security levels of presence and content of messages. Third, we introduce a declassification model for secure multi-execution that allows expressing what information can be released and where it can be released. Fourth, we establish a full transparency result showing how secure multi-execution can preserve the original order of messages in secure programs. We demonstrate that full transparency is a key enabler for discovering attacks with secure multi-execution.
As modern attacks are becoming more sophisticated, there is an increasing demand for protection measures more advanced than those offered by standard security practice. We demonstrate the problem with a motivating scenario from web application security, but note that the problem is of a general nature.
Motivation. In the context of the web, third-party script inclusion is pervasive. It drives the integration of advertisement and statistics services. As an indicative example, barackobama.com at the time of the 2012 US presidential campaign contained 76 different third-party tracking scripts [49]. The tracking was used for targeted political advertisement. Script inclusions extend the trusted computing base to the Internet domains of included scripts. This creates dangerous scenarios of trust-abuse. This can be done either by direct attacks from the included scripts or, perhaps more dangerously, by indirect attacks when a popular service is compromised and its scripts are replaced by the attacker. A recent empirical study [35] of script inclusion reports high reliance on third-party scripts. It outlines new attack vectors showing how easy it is to get code running in thousands of browsers simply by acquiring some stale or misspelled domains. A representative real-life example is the defacement of the Reuters site in June 2014 [50], attributed to “Syrian Electronic Army”, which compromised a third-party widget (Taboola). This shows that even established content delivery networks risk being compromised, and these risks immediately extend to all web sites that include scripts from such networks.
Access control mechanisms are of limited use because third-party scripts require access to sensitive information for their proper functionality. This is particularly important for statistics and context-aware advertisement services on the web. Similar scenarios arise in the setting of cloud computing where sharing the resources is desirable but without compromising confidentiality and integrity. This motivates the need for fine-grained information-flow control.
From static to dynamic information-flow control. Tracking information flow in programs is a popular area of research. Static analysis techniques have been extensively explored, leading to tools like Jif [34], FlowCaml [48], and SparkAda Examiner [10] that enhance compilers for Java, Caml, and Ada, respectively. Recently, dynamic monitoring techniques have received increased attention (cf. [5,6,23,27,28,45,47]), driven by the demand to analyze dynamic programming languages like JavaScript. While static analysis either accepts or rejects a given program before it is run, dynamic monitors perform checks at run time. There are known fundamental tensions [42] between static and dynamic analyses, implying that none is superior to the other. Although dynamic analysis might seem intuitively more permissive, it has to conservatively treat the paths that are not taken by the current execution.
Secure multi-execution (). Recently, there has been much progress on [7,11,12,18,20,24,25], a runtime enforcement mechanism for information flow. In contrast to the monitoring techniques, the goal is not to prevent insecurities but to “repair” them on the fly. This approach is secure by design: security is achieved by separation of computations at different security levels. The original program is run as many times as there are security levels, where outputs at a given security level are only allowed if the security level of the program is matched with the security level of the output channel. The handling of inputs is slightly more involved because inputs from less restrictive security levels are allowed to be used in computations at more restrictive levels. Secure multi-execution propagates inputs, once received, to the runs of the program that are responsible for the computation of outputs at more restrictive levels.
Original execution.
Typically, security levels are drawn from a lattice with the intuition that information from an input source at level ℓ may flow to an output sink at level only if [19]. For simplicity, we will often use the two-level lattice with a secret (high) level and a public (low) level of confidentiality. Figure 1 shows program P with a pair of input sources, labeled high and low , and a similarly-labeled pair of sinks. The baseline policy of noninterference [22] demands that low outputs do not depend on high inputs.
.
Figure 2 shows how secure multi-execution achieves noninterference. Program P is run twice, as at high and as at low levels. The high input is fed into the high run. The low input is fed into both the low and high run. Dummy default values are used whenever the low run asks for high input. High output is produced by the high run, and the low output is produced by the low run, while low output of the high run and high output of the low run are ignored. It is clear from the diagram that noninterference is enforced because the low run, the only producer of low output, never gets access to high input.
In contrast to the traditional dynamic analysis, there is no concern about executions not taken because the control flow of the low run cannot possibly be affected by high input. Further, secure multi-execution provides transparency, in the sense that if a program is secure then its secure multi-execution does not disable any of its original behavior.
Contributions. While secure multi-execution gains increased popularity, there are open challenges that need to be addressed before it can be applied widely. We overview the pros and cons of secure multi-executions compared to traditional information-flow control and, among other findings, point out that secure multi-execution (i) lacks support for fine-grained security levels for communication channels, (ii) relies on restrictive scheduling, (iii) lacks support for declassification, (iv) may reorder messages w.r.t. the original execution, and (v) lacks support for detecting attacks.
We push the boundary of what can be achieved with secure multi-execution. First, we lift the assumption from the original secure multi-execution work on the totality of the input environment (that there is always assumed to be input) and on cooperative scheduling. Second, we generalize secure multi-execution to distinguish between security levels of presence and content of messages. Third, we introduce a declassification model for secure multi-execution that allows expressing what information can be released and where it can be released. Fourth, we establish full transparency showing how secure multi-execution can preserve the original order of messages in secure programs by barrier synchronization. This enables the use of secure multi-execution to discover counterexamples to noninterference, i.e. attacks, on run time.
This journal paper extends and improves an earlier conference version [39]. The present journal version presents a complete overhaul of Section 5 on declassification in , resulting in new results and substantial improvements. Notably, we give a critical evaluation, justification and motivation of our model of declassification. We clarify full release, our model of declassification to confine release to data of specified levels of sensitivity. This model was introduced in the conference version, and we now generalize it and develop theoretical results for it. Further, we show that our declassification model provides additional assurance: drawing on the knowledge-based gradual release [2,3] model, we demonstrate that information release may only take place at declassification points and nowhere else during the execution. We develop theoretical results for it, including a knowledge-based noninterference which we show is equivalent to the noninterference notion we use throughout the paper. We prove soundness for this model, establishing that our declassifying only leaks information through declassification actions. This is the first such result for . We generalize the declassification semantics to support multiple channels of declassification, enabling modeling of the semantics of a declassified value in the name of its declassification channel. For the remainder of the paper, we have improved readability by including corrections to the original paper and by revising notation and formatting. We have updated the related work section with work on that has appeared since our original publication. Finally, we present the full proofs for all of our technical results.
Pros and cons of secure multi-execution
We overview the pros and cons of secure multi-execution with respect to direct information-flow enforcement. The overview has two goals: provide a general basis to decide which enforcement mechanism to pick in a particular case and identify the most pressing shortcomings, subject to improvements by this paper. For a more detailed account of the state of the art, we refer the reader to the related work section. We start by listing what we view as the pros of secure multi-execution.
Noninterference by design. A significant advantage of secure multi-execution is that it enforces noninterference in a straightforward manner by a simple access-control discipline: computation responsible for output at a given level never gets access to information at more restrictive or incomparable levels. This provides noninterference guarantees.
Language-independence. A major benefit is that secure multi-execution can be enforced in a blackbox, language-independent, fashion. The enforcement only concerns input and output operations allowing the rest of the language to be arbitrarily complex. This is particularly useful for dynamic languages like JavaScript that are hard to analyze.
Transparency for secure programs. If the original program is secure, there are transparency guarantees that limit ways in which semantics can be modified. The original work on secure multi-execution shows per-channel transparency (or precision in the terminology of Devriese and Piessens [20]). This means that if the original program is secure then, from the viewpoint of each channel, the sequence of I/O events in a given run of a program is the same in the original run and in the multi-executed run.
Transparency at top level. In addition, we note another transparency property which holds when e.g. the willingness of a program to consume low input is independent of high information: the high run in the secure multi-execution of a program performs the same inputs and outputs as the program does without being securely multi-executed. This property can be seen from Figs 1 and 2. Clearly, the original run of the program in Fig. 1 and the high run of the multi-executed program in Fig. 2 get the same inputs. Hence, the high output behaviors are the same no matter whether the original program is secure or not.
We now turn to the cons of secure multi-execution.
Coarse-grained labels for channels. In work on secure multi-execution so far, communication channels are provided with a single security label. This is often too coarse-grained: for example, the presence of a message might be public but the content is secret. This granularity might be useful for statistics services that might be counting different types of events without revealing their content. For example, Google Analytics is routinely used for various types of counting: how many clicks on the page, how many times a video is played, and how many visitors have viewed a page.
Devriese and Piessens [20] assume total input environments: that the input is always present. This does not allow modeling scenarios where the presence of secret input is secret (for example, whether or not the user visits a health web site). Bielova et al. [12] allow non-total environments but at the price of ignoring information leaks through termination behavior (targeting termination-insensitive noninterference [53]). This implies that the leaks as in the example with the health site are still ignored because the one bit of information of whether the user has visited a heath web site is allowed to be leaked.
This motivates the need for fine-grained secure multi-execution. We remove the assumption on total input environments and introduce fine-grained labels for communication channels, where the levels of presence and content of messages are distinguished.
Restrictive scheduling. With the exception of work by Kashyap et al. [25], secure multi-execution heavily relies on the low-priority scheduler that lets low computation run until completion before the high run gets a chance to run. The low-priority scheduler is both at the heart of the soundness results by Devriese and Piessens [20] and at the heart of FlowFox [18], an extension of Firefox to enforce secure information flow in JavaScript. The security theorem in the abstract setting of secure multi-execution [20] takes advantage of the low-priority scheduler and establishes timing-sensitive security. This is intuitive because the last access of low data occurs before any high data is accessed. Whenever the timing behavior is affected by secrets, there is no possibility for the attacker to inspect the difference.
However, the situation is different in the presence of event handlers, reactive program snippets that are triggered upon occurrence of events. The low-priority scheduler is fundamentally problematic because it is not possible to extend the low-priority discipline over multiple events – simply because it is not possible to run the low handlers that have not yet been triggered. As a compromise, FlowFox [18] multi-executes JavaScript with the low-priority scheduler on a per-event basis. However, as illustrated by a leak in Appendix A, this strategy is at the cost of timing-sensitive security. All we need to do is to set a low handler to execute after the high run of the main code has finished. Then the low handler can leak via the computation time taken by the high run. This is indeed what happens in the example program. Using setTimeout, the main code creates a new handler whose job is to report the time difference since the start of the program. Then the main code branches on a secret and performs a short or long computation depending on the secret. Upon the exit of the main thread, the handler is triggered to report the time difference to the attacker.
This motivates the need for flexible scheduling strategies and the need for (fair) interleaving of the runs at different levels, as pursued in this paper.
Declassification. Declassification is challenging because secure multi-execution is based on separating information at different security levels. Feeding secret information to a public run might introduce unintended leaks. Coming back to the example of tracking and statistics, we might want to track the popularity of items in a shopping cart or track various average values for transactions.
This motivates the need for declassification in secure multi-execution. The event of declassification should not leak information about the context (branching on a secret and declassifying in the body would leak the Boolean value of the secret). It turns out that the support for fine-grained communication channels provides us with a natural treatment of declassification. Indeed, declassification is about communicating a secret value from the high run to the low run, but without leaking through the presence of the communication event. Exactly this is provided by channels with high content and low presence! Hence, a declassification event corresponds to output on a high-content low-presence channel (in the view of the high run), and to input on a low-content low-presence channel (in the view of the low run).
Order of events modified. The transparency guarantees of secure multi-execution are per channel, allowing the order of events to be modified across different channels. This leads to unexpected results in an interactive setting.
This motivates the need for stronger transparency, where the behavior of secure programs is unmodified across the different levels. We show how to achieve this by careful scheduling of the runs at the different levels.
Silent failure. The behavior of secure and insecure programs is silently modified. As mentioned above, there are cases when the run at the top security level is immune to such modifications as it never gets dummy values. However, the behavior at less restrictive levels might be modified, leading to loss of important functionality. This directly connects to undiscovered attacks, addressed below.
Undiscovered attacks. Related to the silent failure point above, secure multi-execution “repairs” problematic executions on the fly, with no means to identify if there were any attempted attacks and what caused such attacks.
This motivates an enhancement of secure multi-execution that allows for detecting attacks. Intuitively, we introduce barrier synchronization of the runs at the different security levels and track the consistency of the values they produce. In the two-level lattice, we check if the low output produced by the low run matches the value produced by the high run (which is the same as the low output of the original program). If they are inconsistent, we have found an attack. Full transparency is the key for this result because it guarantees that secure programs must have exactly the same I/O behavior as their securely multi-executed versions.
Nondeterminism. While not required for soundness, the executions at different levels need to make the same nondeterministic choices for secure multi-execution to be transparent. Although this has not been explicitly handled in previous work, a natural possibility is to assign security levels to the source of nondeterminism [36] and propagate it to the relevant executions in a fashion similar to propagating inputs.
Dummy values. Dummy values are fed into executions that are not authorized to have access to sensitive input. An unfortunate choice of values might lead to the program crashing. Defensive programming is then needed to ensure that programs are stable under variation of allowed input.
Performance. Executing the program several times implies obvious performance overhead. At the same time, secure multi-execution benefits from multicore architectures, in particular when the number of executions is less than the number of cores [20]. Also, as we discuss in Section 7, optimizations are possible for simulating multiple executions by computing on enriched values [7].
Framework
We lay the foundation for our technical contributions outlined in the Introduction by presenting a framework for information-flow security of interactive programs [15,17,36–38].
Input–output labeled transition systems
Our model of computation is a labeled transition system (). An is a triple , where S is a set (of states), L is a set (of labels), and (a labeled transition relation). Computation occurs in discrete steps (transitions), each taking a (unspecified) unit of time. We write iff , and iff for some .
The systems we consider in this paper interact with their environment through channel-based message-passing. Such systems have three kinds of effects: (message-)input, output, and silence. The two latter effects are “productions”, referred to as output o, and the first effect is a “consumption”, referred to as input i. Collectively, these are actions a.
Here, (resp. ) denotes a message received (resp. sent) on channel c carrying value v, and ∙ denotes a non-interaction. Let a, c and v range over the (nonempty) sets , and respectively. Actions are the only external interface to our systems; systems are “black boxes” in every other respect.
An input–output () is an , with L ranged by a.
Practical languages for which this model of computation is appropriate include Erlang and JavaScript. Bohannon et al. give the semantics of a JavaScript-like language as an in [15] and Clark and Hunt give the semantics of an imperative language with I/O (used in our examples) as an in [17]. Since all our results apply to any state, our contributions are general.
Interactive programs
Definition 3.1 defines a general model of interaction that places no restrictions on how an interacts with its environment. The interactive programs we consider in this paper are a class of which interact with their environment in a particular way. We formalize this interaction pattern as three properties: input-neutral, input-blocking, and deterministic. An input-neutral will, when it is ready to perform input on a channel, accept any value the environment provides on that channel. An input-blocking will, when attempting to perform input on a channel, block until one is available. We formalize this as an input action with a distinguished value (blank); when , then s has waited one time unit for an input on c without receiving one ( has no specific meaning). A deterministic can either only do a (unique) output, or only do input on a (unique) channel, and in both cases enter a state uniquely defined for the action it took. We require that these properties are preserved through execution, i.e., hold for all reachable states. In the following, let be the set of states reachable from s. That is, , and for all we have for all a and for which that .
For all ,
is input-neutral iff .
is input-blocking iff .
is deterministic iff
, and
.
Point (1) states that if s is ready to perform input on c, s is receptive to any v on c. Point (2) states that input is a blocking operation, by asserting that s does not change state while waiting for input. Point (3)(a) says if , then iff (so s can be input-neutral), and implicitly, if , then iff . Point (3)(b) says s has no internal nondeterminism. Unless stated otherwise, any s we consider in this paper satisfies Points (1), (2) and (3). We discuss the assumption of Point (2) further in Section 4.
Traces
We will reason about the behavior or systems in terms of the sequences of actions the system can perform. We therefore formally define such sequences, and ways of comparing them, now. A trace is a (finite) list of actions, denoted . We let ϵ denote the empty trace, “.” as the cons operator, and we usually omit ϵ in nonempty traces. We write if for some and . Let , and denote the projection of to its input-, output- and c-messages, respectively. E.g., if , then , , and . extends to for in the obvious way. All of these, and other, projections used throughout the paper are given formally in Appendix B. We write as short for ; we refer to each as a projection predicate. With defined as above, .
We write when, for some , . Here, is the concatenation of and . Throughout the paper, all the relations on traces that we use are defined as ⩽ or = after first applying projection functions in a particular order on both sides of the relation. To reduce notation, instead of using a new symbol for each such combination of relation and projection functions that we use, we develop a notation for applying projection functions in order to both sides of a relation. For a relation R, is short for . Note that . With defined as above, .
Observables
The observables of our programs are its effects. The observability of a message is given by the security level associated with the channel carrying the message. As foreshadowed earlier, we assume a lattice , with ranged by ℓ, of security levels which express levels of confidentiality. Each channel is labeled with two security levels; is the level of the presence of a message on c, and is the level of the content or value of a message on c. We require for all c that , the intuition being that an observer who can infer the value of a message can infer that there was a message carrying this value. In examples, we frequently represent a channel by its security labels; we then write in place of c (in code, ). Note, however, that we do not assume that there is only one channel associated with each security level. A classic example is the two-level lattice with , for “low” confidentiality, for “high”. We let , , denote , and , resp. Since our results apply to any lattice, our contributions are general. In our technical results, we assume a fixed lattice.
Original execution with fine-grained security.
Figure 3 illustrates the flow of information in the case of . Input on is depicted in-between the and input. The presence of such an input is (this dependency on is illustrated by the dashed line) while the content is (this dependency on is illustrated by the solid line). Similarly, output on is depicted in-between the and output. Its presence is observable at level (dashed arrow), and its value is observable at level (solid arrow).
The security labels express who can observe what. An observer is associated with a security level ℓ. An ℓ-observer is capable of observing the presence (resp. content) of a message on c iff (resp. ). removes ℓ-unobservable parts of actions in . For , . Here, got replaced with ∙ since communication on is unobservable to a -observer (thus looks like a ∙). got replaced with (for a fixed ), since a -observer only observes presence of messages on (all look the same).
Timing and progress. Eventually we enforce a property stating that variations in unobservable inputs to a system do not cause an ℓ-observable difference in the traces the system can perform. Trace equivalence defines the class of attackers such a property guarantees security against. We consider two classes of attackers: timing- and progress-sensitive ones. Since each action takes a unit of time, these two attackers differ in whether or not they observe non-interaction. Since no message is passed when a system is blocking on input, we treat blank input as non-interaction. replaces all with ∙. With defined as above, .
A timing-sensitive (e.g. [1,20]) attacker measures time between observables in a trace. removes trailing ∙ from . E.g. . Define timing-sensitive ℓ-equivalence as (see Section 3.3 for a definition of ). Let and , and consider
Since this program can perform and , this program is not secure against a timing-sensitive -observer since ( is produced faster in the latter trace).
A progress-sensitive (e.g. [3,36,38]) attacker observes whether more observables are forthcoming. removes all ∙ from . With as above, . Define progress-sensitive ℓ-equivalence as . and are not evidence that the above program is insecure against progress-sensitive ℓ-observers; (in both traces, eventually appears). A progress-sensitive timing-insensitive attacker is strictly weaker than a timing-sensitive one since .
Environments
Inputs to our systems come from the environment in which our systems run. Clark and Hunt [17] have demonstrated that when analyzing deterministic programs for security, an environment does not need to be adaptive to provoke a particular (leaking) behavior. Thus it is sufficient for our purposes to consider environments represented as a stream (infinite list) of inputs for each channel. So, an environment e is a mapping from input channels to the stream of inputs the environment provides on that channel. Since streams can contain blanks, our framework considers attacks driven by varying the timing of input.
The jth element in represents what e provides on c in time unit j; if this element is , then e provided value v on c in time unit j; if the element is , then e provided no value in time unit j. Since any program we consider can consume at most one input per computation step, we do not need to consider scenarios (or their security implications) where e provides input at a rate faster than the program can consume them. Since a program is not necessarily ready to receive an input when the environment provides it, we assume that the interface between e and the program manages a buffer for each input channel, and that the program draws input on a channel c from the c-buffer (in FIFO order), drawing a blank when the c-buffer is empty. We also assume that this interface never prevents a program from performing an output. The interaction between a program and its environment is therefore asynchronous.
We formalize this interaction using a relation that defines when a trace is possible under a given environment e. Intuitively, is possible under e if, for any c, (1) the c-inputs in are (in value and order) as provided by e, (2) each c-input occurs no sooner in than e could have provided it, and (3) a blank is drawn only when no c-input is buffered. Let , and let denote the prefix of length n of . Formally, is consistent with e, written , iff for all c, we have for all , with , that
This states that for each prefix of and each c, the list of non-blank inputs in must prefix the list of non-blank inputs in the same-length prefix of , and that ends with a blank input on c only if all c-inputs provided by e up to this point are in and e provided no new c-inputs in time unit ( is a wildcard). The quantification and definition of and formalizes (2), the trace equivalences formalize (1), and the case addresses (3). Since running s under e constrains the traces which s can perform, we obtain a definition of interaction as follows: s performsunder e, written , iff and . Let s be the initial state of the following program.
Let be defined as on the left below. Then the judgments on the right hold.
These judgments hold regardless of how for and are defined (s only reads from c).
Equivalence. We compare the streams in the environments the same way we compare traces. So we define observational equivalence of environments as follows:
Totality. An environment is total if it always provides a system with input whenever the system needs it. In our framework, e is total if ⋆ does not occur in any . Previous work on security for interactive programs [17,36] assume environments are total. However, as we have demonstrated previously [37], this assumption limits (undesirably) the space of possible attacks on input-blocking interactive programs, since the presence of a message can depend on high data. Consider the program in Section 3.4. Let and for all . While this program can perform under , the program cannot perform an -equivalent trace under . Since a program can encode a bit in the presence of a message, these attacks become crucial in an interactive setting. To emphasise the gravity of this, we give an example, from [37], of three interactive programs, each secure under total environments, which, when run in parallel (e.g. with the semantics in [37, Fig. 2]), leak the input on , bit by bit, on , by encoding the received value in the presence of and messages.
In summary, the lack (resp. delay) of input impedes on the progress (resp. timing) behavior of input-blocking interactive systems. To guarantee protection against attacks powered by varied input presence, nontotal environments (e.g. our e) must be considered. This in part motivates our fine-grained security levels; since no low observables are allowed to occur after a high input in deterministic input-blocking systems, the only way for such a system to input a high value before performing low observables is if the presence level of the input is low [37].
Noninterference
As mentioned earlier, our target policy is noninterference. The idea behind noninterference is the following. Assume an ℓ-observer observes all system effects which he is privileged to observe, i.e. all ℓ-observable actions. A system is noninterfering if, by observing ℓ-observable actions, the ℓ-observer learns nothing he is not privileged to learn, i.e., unobservable input does not interfere with observable behavior. Noninterfering systems are thereby not responsible for leaks. The formalization of this idea we use is that of possibilistic noninterference for interactive systems [17,36,37]. It states that, for any two ℓ-equivalent input environments, the respective sets of traces produced under either of them are ℓ-equivalent. Thus, an ℓ-observer, by observing ℓ-observables, cannot tell one input environment apart from any other input environment that differs only in ℓ-unobservable input. The following definition is a definition schema, parameterized by an security-level-indexed equivalence relation defined on traces and environments. We will later instantiate this schema with and (both security-level-indexed equivalence relations on traces and environments) in place of .
s is-noninterfering () iff
Note that for nondeterministic programs, possibilistic noninterference is a somewhat weak notion of security, since it requires that a system can, by making the appropriate nondeterministic choices, match behavior. Since our systems are deterministic, however, the stream of actions a system can perform under a fixed e is unique. Possibilistic noninterference thus requires that, for any , any prefix of the stream of actions s performs under must be matched by some prefix of the stream of actions s performs under , and vice versa, since . Possibilistic noninterference (due to limited possibilities) is thus rather strong in our setting.
By instantiating this definition with the two ℓ-equivalence relations from Section 3.4, we get the two definitions of noninterference we will consider in this paper.
s is timing-sensitive, progress sensitive noninterfering () iff .
s is timing-insensitive, progress sensitive noninterfering () iff .
For the system models under consideration in this paper, is a weakening of . The details of this, and all other proofs, are in Appendix C.
.
Note that this result (and others) is sensitive to the assumptions we make in Definition 3.2. Consider a system s that times the arrival of an input on a input channel (by counting ⋆s), and outputs the time on a channel. Such a system is -secure, and not input blocking. However, under -equivalent environments, the timing of input is allowed to differ; under such environments, s leaks the timing difference into a value in output, which a progress-sensitive observer can observe; a -insecurity.
Fine-grained secure multi-execution
The opening series of our contributions develops a generalization of [20] with respect to several dimensions. We lift the assumption on the totality of the input environment (i.e. that there is always assumed to be input) and on cooperative scheduling. Furthermore, we distinguish between security levels of presence and content of messages. In addition, we generalize to arbitrary deterministic and strengthen the guarantees provides.
with fine-grained security.
By design, our formalization of ensures that the ℓ-observable part of the interaction on channels with ℓ presence depends only on ℓ-observable parts of input on channels with presence, thus enforcing a noninterference policy. Figure 4 illustrates the intuition in our handling of the channels with fine-grained security levels for the two-level lattice. In addition to propagating low input to the high run (as in Fig. 2), we propagate to the high run the fact that an message has arrived to the low run. This allows consistent processing of the message. At the output, the presence of an message is observable at the low level (cf. dashed output arrow). On the other hand, the value of an output is produced by the high run (cf. solid output arrow).
Our of s runs, concurrently, a copy of s for each level in the security lattice. The of s can input on c iff the -run can input on c. An ℓ-run which can consume a c-input with is fed a (constant, pre-determined, input-independent) default value, denoted , by . An ℓ-run which can consume its nth c-input with gets a copy of the nth input consumed by the -run, unless is yet to consume n c-inputs, in which case the ℓ-run blocks until the -run has done so. However, if , then the ℓ-run is fed instead of the value in the nth c-input. The of s can output on c iff the -run can output on c. A c-output produced by a ℓ-run for which is discarded by (as opposed to being sent to the environment). When an ℓ-run produces its nth c-output with , this output is sent straight to the environment, except when ; in that case first checks whether the -run has produced its nth c-output. If so, then the value of the nth c-output produced by the of s becomes the value of the nth c-output produced by the -run. Otherwise, the value is .
Semantics
We now give a semantics for the of an arbitrary s satisfying the assumptions in Definition 3.2, as an state. Concurrent executions of ℓ-runs of s are scheduled by a scheduler. We consider schedulers which are autonomous and independent of input and of the behavior of ℓ-runs, since letting scheduling decisions depend on these can make susceptible to subtle timing attacks (as demonstrated by Kashyap et al. [25], and discussed further in Section 4.2). Furthermore, to make transparent, we require that schedulers are fair, in the sense that the scheduler schedules all ℓ-runs infinitely often, and deterministic, in the sense that the sequence of scheduling decisions the scheduler makes is unique.
A scheduler, , is an with labels ranged by ℓ. A scheduler, σ, is a state of an . For all ,
is deterministic iff
, and
.
is fair iff
.
Point (1)(a) states that the way future decisions is made is uniquely defined by the next choice, and Point (1)(b) stipulates that the choice of which ℓ-run to schedule next is unique. Point (2) states that no matter how many scheduling decisions have been made, each ℓ-run will eventually be scheduled. Unless stated otherwise, σ is deterministic and fair. Thus, since ℓ and for which are unique and always exist, we use list and stream notation to represent and manipulate schedulers. An example of deterministic and fair schedulers is the round-robin schedulers. For instance, for , and are deterministic fair schedulers (that repeat resp. , infinitely).
Semantics of . (a) ℓ-stepper. (b) ℓ-chooser. (c) history.
The semantics of is an of -states. A -state is a triple , where is the list of actions which the has performed so far, σ the state of the scheduler, and S contains the state of the ℓ-runs. S maps each security level ℓ to a pair , where is the list of actions which the ℓ-run has performed so far, and is the current state of the ℓ-run. For a given σ, the of s, , is defined as . The transition relation for the is given in Fig. 5. The transition relation is presented in three layers, in Fig. 5(c), Fig. 5(b) and Fig. 5(a) respectively. Each rule in each layer uses only rules in the layer directly above it. We start with the bottom-most layer, Fig. 5(c), and work our way upwards. The derivation of any transition begins with the (history) rule (the judgment in the premise, which we will turn to momentarily, is defined in Fig. 5(b)). The purpose of (history) is to keep track of the interaction which has had with the environment. Note that , so we sometimes omit the trace label on a transition. We put on the left side of “⊧” in the next layer of the semantics, Fig. 5(b), to show that this layer only reads (we apply the same convention throughout the paper; this use of symbol “⊧” is not to be confused with the use of “⊧” in Section 3.5). The rules at the Fig. 5(b)-layer are responsible for, by use of σ, deciding which ℓ-run takes a step next, using the rules in the third (i.e. top) layer, Fig. 5(a). This third layer is responsible for hiding from the Fig. 5(b)-layer all the different ways which an ℓ-run can take a step without interacting with the environment ((dead), (silent), (o-old), (i-old)), and signaling to the Fig. 5(b)-layer when the ℓ-run requires I/O with the environment to proceed ((o-new), (i-new)). Each rule at the Fig. 5(a)-layer appends to the ℓ-run trace the action the ℓ-run performed during the step (which is not necessarily the same action as the one performed by the whole -state). We equate a terminated ℓ-run with an infinitely silent one, as indicated by (dead) (not making terminated runs unschedulable excludes several timing attacks described by Kashyap et al. [25]). The Fig. 5(a)-layer stores output on channels with presence without forwarding it to the environment, as per (o-old). (i-old) covers multiple scenarios for the ℓ-run performing an input action on a channel which does not result in the -state consuming input from the environment on c in this step. When , input . When , this rule is only applicable if the ℓ-run has not already read all the c-inputs which the -run has read. When , input the same value received from the environment when the -run performed the corresponding input action. Otherwise, input instead. (i-new) indicates that the ℓ-run requires input to proceed, and for the value v received from the Fig. 5(b)-layer, indicated on the transition label, instead feeds to the ℓ-run iff ( is a function of c, ℓ, and v). The previous layer has two rules for this scenario. When , then the ℓ-run blocks until the -run reads on c, by (i-block). When reads on c, the input is fed to every -run blocking on c, by (i). (o-new) notifies the Fig. 5(b)-layer that the ℓ-run has a fresh output for the environment. Rule (o) in the previous layer handles this scenario, checking if the -run has already provided content for this output, and if so, replaces the value in the output with the value in the corresponding -run c-output.
When , the output value is replaced by iff has not yet produced the corresponding value. Having the -run instead wait for the -run to reach the corresponding c-output, or giving responsibility of producing the c-output to the -run, can introduce a leak:
Here the time it takes for the -run to produce the -output (for nonnegative h), and whether produces the output at all (for negative h), depends on h, in the of this program.
While Fig. 5(b) indicates that controls each step of each ℓ-run, in practice the responsibility of can be distributed to the ℓ-runs, such that each ℓ-run is autonomous, as follows. Each ℓ-run is made responsible for environment I/O on all , since performs I/O iff the ℓ-run of s performs it. Each ℓ-run makes input on each and output on each available in a shared resource (e.g. memory) such that -runs can obtain a copy of the input when they need it, and an -run can obtain the actual value to output on c. Each ℓ-run processes (after sharing, when ) in place of the inputted value when and , and outputs when the -run is yet to share the value to put into the output when . This approach is taken in a benchmark by Devriese and Piessens [20]. Forcing ℓ-runs to diverge and recording full traces can be avoided [20,25]. This approach is sound as long as the ℓ-run threads cannot influence the scheduler.
While s is input-blocking, is not; varied presence of input on cannot impede progress or timing of -runs where . This effect is achieved by actions; if is in a state where an ℓ-run wants input on c, and e does not have one ready (yet), the ℓ-run can do a -action, allowing to pass control to another -run. In contrast, the formalization (as opposed to the benchmark implementation) of by Devriese and Piessens [20] is input blocking; if an ℓ-run is scheduled before a -run with , the nonpresence of input on can interfere with the -run. This hinders sound scheduling of runs for arbitrary nonlinear lattices.
Soundness
By design, enforces timing-sensitive noninterference.
.
We first highlight the implication of this result by contrasting it with similar results in related work. Afterwards, we give an intuition for why this theorem is true.
In contrast to Devriese and Piessens [20], who prove soundness for a cooperative scheduler for linear lattices, and to Kashyap et al. [25], who prove soundness for two round-robin schedulers (the “Multiplex-2” and “Lattice-based” approaches), we prove a more general result: soundness for arbitrary deterministic and fair schedulers. While Devriese and Piessens claim their scheduler, called , which executes the ℓ-runs to completion in increasing order by ⊑, works for any linearization of a nonlinear lattice, Kashyap et al. have shown that introduces a timing dependency between ℓ-runs at incomparable levels in nonlinear lattices. For instance, with and ⊑ being the reflexive transitive closure of , with linearization and , the time it takes for to emerge from the of the following program is, under , a function of the input on .
In the presence of nontotal environments, the situation is even worse; in the of the following program under , the presence of input on leaks to .
While swapping and in the linearization resolves the issue in the above program, the following program has no linearization of for which schedules ℓ-runs soundly.
We show in Appendix A that assuming that any ℓ-run can run to completion of all of its inputs (necessary for to schedule ℓ-runs soundly for linear lattices) is problematic when program input arrives arbitrarily in time.
The proof of Theorem 4.2 is a corollary of the following lemma, which can be obtained by removing the last two elements in the conjunction in the conclusion of the lemma, and comparing the result with Definition 3.4. We write iff .
Such a strong correspondence is achievable since, for each , the -run of s, in and , behaves as , where
(While for , the number of preceding a of an -run in compared to can differ due to σ, this number is the same in compared to . Since s is input-blocking, all three are in the same state at the time of the non-blank read, and consume the same input, by .) Thus, since and are both run under the same σ, we have that after any number of transitions, the -runs will in both runs have performed the same number of actions, consumed the same inputs, produced the same outputs, and be in the same state.
Transparency
We show that does not adversely modify the I/O behavior of a progress-sensitive noninterfering program (and therefore also a of timing-sensitive noninterfering program). Let , ℓ, e and σ be arbitrary. In s and , the interaction on ℓ-presence channels is ℓ-equivalent.
,
.
When all ℓ-presence outputs also have ℓ-content, the ℓ-presence interaction in s and is the same. This is an improvement on Theorem 2 in [20] which establishes only the (a)-part of Theorem 4.4 for the interaction on each channel (as opposed to, for each ℓ, the interaction on all channels with presence level ℓ), and only for terminating runs of termination-sensitive s. Furthermore, under and nontotal environments, yields a nontransparent run for the following program, as no occurs if no input on arrives.
However, when s outputs on c with , might replace the value in its corresponding output with . Thus, the timing behavior of can impede the ability of a σ to soundly schedule runs in such that the -run reaches the output before the -run does irrespective of previously inputted values. In programs, however, all ℓ-runs for which will reach an output on c after the same number of reduction steps. This includes the -run, since . Thus, if we ensure that any ℓ-run never “outruns” its parent-runs (in the sense that the ℓ-run has made more progress on its (nonblocking) actions than -runs), we can ensure that the content-provider of an output reaches the output before its presence-provider does. It is, however, not sufficient to require, for instance, that at any given point, has been scheduled more often than , as the -run can waste its turns blocking on -presence input (we do not need to worry about a -run blocking on -presence input, because for a deterministic program to satisfy (and therefore ), it must be impossible for any effect to follow a -presence input [37]). For instance, the of the following program under any σ satisfying for any is not transparent.
What we need is a schedule which ensures that when the -run reaches an action involving interaction on a -presence channel, is either already blocking on input on said channel (in case the -run is performing input on it), or has already moved past the output on said channel (in case the -run is performing output on it). We achieve this by making sure that, before scheduling , we have already scheduled since was last scheduled. The following predicate formalizes this; when invoked as , the predicate yields 1 when and have been scheduled in such a manner in , and 0 otherwise.
This formalization achieves this effect by walking through , assigning a bit to 1 upon encountering a (signifying that has been scheduled since was last scheduled), and assigning the bit to 0 upon encountering a only if the bit is 1 (if it is 0, the schedule is rejected).
With this predicate, we can formalize schedulers which never allow runs to “outrun” their parent runs, for any lattice. We call these high-lead schedulers.
σ is a high-lead scheduler () iff
An example of a high-lead scheduler is the round-robin scheduler which schedules levels in (increasing) order of maximal descendancy from top (ties broken arbitrarily). For instance, for and ⊑ being the reflexive transitive closure of , σ which infinitely repeats or is a high-lead scheduler. It is for these schedulers that, when , the interaction on ℓ-presence channels in and is the same, for all ℓ.
,
.
Thus, if puts a in an output when run using , then this must have been done to prevent a (timing or progress) leak – a desired effect.
Declassification
Many systems intentionally leak information as part of their function [46]. For instance, systems with a login interface leak the (mis)match of a username–password pair through the success/failure of a login attempt, systems that release the average salary of workers for statistics purposes leak information about the salary of each worker, and displaying the popularity of an item in an online shop leaks information about the purchases of customers. The target properties of interest for such systems are ones which stipulate that all leaks (if any) are intentional. An intended leak is referred to as a release, and we refer to the act of releasing information as a declassification (note: while these words are typically synonymous in literature, we use them as prescribed here). Such properties, i.e. models of declassification, have proven to be highly scenario-specific; as of yet, there is no one model universally applicable. Exploring such models is an active area of research, the state of the art being a classification of models by declassification goals (called dimensions of declassification), and a set of principles which a model should follow [46].
As is, enforces noninterference, which disallows all leaks, intentional or otherwise. When applied on a system with intentional leaks, removes the leaks, thus removing a feature from the system. This makes impractical for this broad class of systems. To remedy this, we present a variant of , , which supports declassification. A declassification model which would be a good fit for our scenario is one which requires that (1) declassification only takes place where the system needs it, and (2) what leaks are allowed must be defined outside the system (so they can be blackbox enforced by ). These goals are primarily along the where (in the sense of where in the code the release may take place and where in the security lattice the affected information might be) and what (in the sense of what information may be released) dimensions of declassification [46], although the who dimension plays a role since attacker-controlled code and input must not affect which leaks are allowed. While models along the when dimension (which e.g. strive to delay release, release infrequently, or release only after a session has completed) provide useful guarantees, we find that facilitating them requires nontrivial extensions to our semantic and information-flow model for goals which are ultimately domain-specific.
While looking for a model matching the above goals, we discovered that none of the models we studied and their accompanying enforcements proved to be an ideal fit for our scenario. Whereas is a blackbox dynamic enforcement operating on interactive systems, most models of declassification are designed for substantially different system models, and most enforcements are whitebox and static [46]. Furthermore, in many models of declassification, intended leaks are defined through annotations (e.g. ) in the program (and thereby assumed to be desired by principals); such an approach would not work in our scenario, since the systems operates on are possibly-malicious black boxes.
To show that enforces our desired goals, we prove it sound w.r.t. two models of declassification. One is gradual release [2], a where model which we have adapted to our scenario. Gradual release, along with an accompanying static enforcement, has previously been given for a semantic model for noninteractive imperative programs [2], and a generalization of gradual release with what goals with an accompanying hybrid enforcement, has previously been given for interactive programs [3]. In both cases, enforcements are whitebox, intended leaks are defined by the program, and the models were timing-insensitive. One reason for the above-mentioned generalization is that gradual release allows leaking arbitrary contextual information through a declassification action. Addressing the what dimension of declassification, we introduce a new model of release, full release, which is a blackbox what model that disallows leaking arbitrary contextual information through a declassification. Essentially, satisfies full release by virtue of how separates input at different security levels into independent runs. To this end, while being primarily a what condition, full release has aspects of where in the security lattice [46] since it limits the effects of declassification to the declared security levels.
with declassification.
This very separation makes declassification in nontrivial, since, by design, e.g. the run does not have information as part of its state when information is to be declassified to ; effects are controlled (only) by the run, and input is fed (only) to the run. To let effects depend on declassified information in , we need to move (only) the declassified information from the run to the run in a controlled way, without breaking the kind of guarantee was originally designed to provide. It turns out that the communication model from Section 4 is an excellent fit for secure communication between the runs at different levels. Recall that we wish to prevent the occurrence of declassification events from leaking information about the context while allowing intended release of the value to be declassified [46]. This is exactly the problem we needed to solve to properly handle channels with different security levels for presence and content! Conveniently, the same approach works here. The core idea is depicted in Fig. 6. Declassification corresponds to routing an output (containing the declassified value) from the run into the run. As with output in , the occurrence of the declassification in the run in is not leaked.
We begin this section with a brief departure from to formalize our declassification goals in Sections 5.1 and 5.2. We then return to in Sections 5.3–5.5 where we give a sound and transparent variant of , , that enforces these declassification goals, and discuss a variant in Section 5.6.
Gradual release
One of our declassification goals is that information release only takes place where the system needs it. However, the systems we consider are black boxes which send and receive messages; at the point the system performs a declassification, the system is performing a noninteraction. When the effect of the declassification is then observed (much) later in the system-environment interaction, it is difficult to assess whether the observed leak was caused by the declassification or not. To address this issue, gradual release assumes that systems make declassifications an observable effect, thus providing the released information to its observer right where the declassification occurs. These effects form the interface the system uses to declare release intent to the gradual release property. The system then only leaks where needed if the system only leaks through these release actions, which is what gradual release stipulates.
We model s which make declassifications (i.e. the declarations of release intent) observable effects in our semantic model as follows. We use our channel abstraction to define release actions. Let be the set of release channels, ranged by , and let be the set of release-actions, ranged by . A release action leaks information from one security level, to another. Let denote the from-level, and denote the to-level of . The set of actions that release information to an ℓ-observer is then given as follows.
The following inference rule illustrates how the semantics of declassification, in a simple imperative language with I/O, can be given such that declassification becomes an effect.
The action label on the transition signals, to gradual release, that the release is intended. This declassify construct is more fine-grained than the standard one as it specifies both the from level and the to level of the declassification operation. Furthermore, the ability to support multiple channels releasing information from, say, to , enables us to encode the semantics of the value being released in the name of the channel; one channel could release age category, another could release gender, etc.
We say that s is releasing if it can perform a release action, and that s is release-compliant if all its release actions are output actions (s does not ask for permission to release; it just declares it; hence the release action must be an output).
For all ,
is release-compliantiff .
is releasing ()iff .
Unless stated otherwise, any s we consider in this paper is release-compliant.
Leaks through actions and reduce uncertainty about secrets.
Gradual release stipulates that an ℓ-observer only learns about ℓ-unobservables at points where the system performs a declassification. To formalize this, we first formalize what it means for the attacker to gain knowledge (cf. [2,3,9,21]). Recall the idea behind noninterference from Section 3.6. Assume the attacker knows the semantics of a system s and knows (or chooses) the ℓ-observables in the input environment e. From the attacker’s point of view, the input environment could be any one of . The goal of the attacker is to rule out elements of this set as possible input environments, by observing the ℓ-observable part of the interaction of s with e. If the attacker cannot, then s satisfies noninterference. If the attacker can rule out an environment as a possible input environment, then the attacker obtains the knowledge that the ℓ-unobservables in e are not as defined by (thus learning things he is not privileged to learn). We define the knowledge of an ℓ-observer after observing a sequence of actions performed by a system s under environment e as the set of input environments under which those observables were possible:
The smaller this set is, the less uncertainty there is about the input environment, and thus, the greater the knowledge of the ℓ-observer. This is depicted in Fig. 7. There, actions and , when observed by the ℓ-observer, reduce the uncertainty about the secrets in the input environment, and thus leak information to ℓ.
As more actions are observed, knowledge monotonely increases.
,.
As hinted above, if an ℓ-observer never obtains knowledge about ℓ-unobservable input by observing ℓ-observable parts of the system-environment interaction, then the system satisfies noninterference.
s is- () iff
As the name suggests, this knowledge-based formalization of noninterference is equivalent to the two-run formalization given in Section 3.6.
,.
Gradual release states that an ℓ-observer can only gain knowledge by observing release actions. In terms of Fig. 7, gradual release requires that .
s satisfies-gradual release () iff
By comparing Definitions 5.5 and 5.3, it is apparent that weakens by strengthening the antecedent of the implication such that the consequent needs only hold for nonrelease actions. Thus, for the class of s which do not release information, gradual release and noninterference are equivalent. This is known as the conservativeness principle of declassification [46] that stipulates that for systems with no information release, the security condition is equivalent to noninterference.
,.
To restore the typical semantics of declassification (which does not make declassification an effect) in an s, we simply place s in a wrapper which withholds release actions, as per , given below.
We let , if , and otherwise. When a system satisfies gradual release, withholding its release actions can only reduce the amount of information it releases.
.
Full release
Gradual release provides a natural way to formalize where goals in untrusted blackbox systems. However, on its own, gradual release does not satisfy our what declassification goal. To see why, first consider the following program , with from-level and presence-level .
This program is not secure; it leaks contextual information a through the presence of release action . If a -observer does not observe (after a certain number of computation steps, or upon observing the output in the progress-sensitive timing-insensitive case), then the -observer can infer that a is even. Fortunately, gradual release rejects . However, the following variant does satisfy gradual release.
Let (resp. ) be a bijection between the integers and the odd (resp. even) integers. Then l is odd iff . While the presence of the release action is invariant of -unobservables, this program leaks the sensitive context, a, through the value of the release action. Being a pure where condition, gradual release abstracts away the fact that these are different declassification statements (occurring in different lexical contexts). This is easier to see if we modify the program again, to , where , and , which is likewise not secure but accepted by gradual release.
Our declassification goals require further restrictions in addition to gradual release to limit what can be released during a release action.
Permitted flows to given .
To address the what dimension, we introduce a new model of declassification: full release. Unlike gradual release, full release has no particular interface a system must make use of. Full release treats a system as a black box, operates only on its inputs and outputs, and stipulates that all leaks in a system are in accordance with a predefined release policy, which is external to the system. This is a good match for our what declassification goal, which states that permitted leaks must be (able to be) provided independently of the system, since systems are not trusted.
A release policy ρ is a set of pairs for which . These pairs define exceptions to the standard only-upwards flows policy that noninterference stipulates. For instance, when in , ρ permits the standard only-upwards flows of information that noninterference permits, but furthermore permits information to leak from to . A release policy is therefore similar to the intransitive downgrading relation ⇝ used in intransitive noninterference [30,31]. Let be defined as the reflexive transitive closure of . This relation expresses which flow paths become permitted once the leaks in ρ are permitted. This is illustrated in Fig. 8. When , then the permitted flow paths become , same as for noninterference. Thus (only) information with security levels in the C-L rectangular region of the lattice is permitted to flow to . However, if information is permitted to leak from A to X and from B to Y, then . Since and , information with a label anywhere in the gray region of the lattice is permitted to flow to C. Assuming an ℓ-observer observes all information which can travel along permitted flow paths to ℓ, this leads to the following new notion of equivalence of environments.
andare ρ-ℓ--equivalent () iff .
Observe that we already have . The minute, yet key, difference is the ρ on the ⊑, which requires furthermore holds for for which .
.
The more leaks that are allowed, the stronger ρ-ℓ--equivalence becomes.
.
Together, this gives that ρ-ℓ--equivalence is most relaxed when no leaks are allowed.
.
Full release states that inputs which are not permitted to flow to an ℓ-observer must not interfere with ℓ-observables.
s satisfies-ρ-full release () iff
By comparing Definitions 5.12 and 3.3, it is apparent that , for any ρ, weakens by strengthening the antecedent of the leftmost implication such that its consequent needs to hold for fewer environment pairs. To make this conservativeness of declassification [46] result clearer, we need to make two observations. First, when , , so , and thus, ∅-full release is just noninterference.
.
Second, the more leaks are allowed, the weaker full release becomes. Full release is thus monotonely weakening in the size of .
.
Together this shows that full release follows the conservativeness principle of declassification, for any ρ.
.
We close this section with a few examples that contrast full release against gradual release, highlight the main shortcoming of full release (that it is coarse-grained) and show the way these declassification goals complement each other.
Full release stipulates what information is allowed to leak. Thus, when the release policy does not allow a leak from ℓ to , then a system satisfying full release can by no means leak from ℓ to . For instance, full release rejects and when (correctly identifying the implicit flow of -information, present in the context of the declassification, to ), and rejects when . However, full release does not place demands or restrictions on how leaks are made, i.e. whether or not they only occur where the system declares intent by performing a declassification action. For instance, the following two programs and are treated exactly the same way by full release, both accepted if , and both rejected otherwise (with and ).
Since gradual release rejects the former program (which leaks without declaring intent), and accepts the latter (which declares intent), the two models of declassification complement each other to a large extent. However, full release is restrictive when it comes to systems that declare intent for some leaks from ℓ to , but not for other such leaks. For instance, consider the following variant of programs to .
Program satisfies gradual release, despite the leak. However, there is no ρ which makes full release accept and reject ; full release will always accept both of them if , and reject both otherwise. Full release is therefore coarse-grained, allowing leaks in an all-or-nothing manner. It is, however, necessarily so; since systems are black boxes, full release cannot tell whether or not a system that leaks intentionally from to is unintentionally (or maliciously) encoding all input in that one leak.
Semantics
We now return to to formalize a variant with declassification support, , which, in addition to enforcing , enforces the declassification goals developed in the previous sections. The main challenge in developing is the fact that ℓ-runs are black boxes: Consider a system which must leak a function of some inputs as part of its function. The only interface has to the system are its effects (i.e. action labels); since systems are black boxes, as-is cannot tell the system apart from another system which leaks a different function of inputs as part of its function, or one that does not need to leak at all, and therefore cannot provide to the -run only the (parts of) input the system needs to perform its function. If provides some input to the run, a leak may occur. If provides no input to the run, system functionality may break.
Our approach is to add to an interface which a wrapped system can utilize to ask for permission to declassify information. The semantics of are obtained by adding rules to the semantics of for managing this interface. The declassification interface assumes that the wrapped system exposes a piece of its plumbing – the declassifications – as effects which describe the declassifications and allow the context (in our case, ) to manipulate them. Any attempt by an ℓ-run to leak information that has not explicitly allowed will fail, due to the way , like , separates input at different security levels into independent runs.
Analogous to our approach to define the release interface between a system and gradual release in Section 5.1, we turn to our channel abstraction to define the effects of the declassification interface. The similarity of the two formalizations is no accident; we will later build an interface to gradual release on top of our declassification interface. Let be the set of declassification channels, ranged by , and let be the set of declassification actions, ranged by . A declassification leaks information from one security level, to another. Let denote the from-level, and denote the to-level of (φ is defined on both release- and declassification channels) (we will return to the assumption in Section 5.5). A particular can represent something as general as “declassify some information to ”, in which case and , or something as specific as “declassify the first character in Alice’s password to Bob”, in which case e.g. (Alice) and (Bob).
The semantics of requires that systems expose their declassification plumbing to the declassification interface through declassification actions as follows. To declassify a value v from ℓ to , the system first performs output , where , for which and , represents the information being declassified. The systems should then block on input from . The following inference rule illustrates how the semantics of declassification, in a simple imperative language with I/O, can be given in a manner satisfying this requirement. Again, this construct is more fine-grained than the standard one, for the same reasons as the declassification construct given in Section 5.1 is.
To restore the typical semantics of declassification (which does not make declassification an effect) in a system s satisfying the above requirement, we simply place s in a wrapper which makes communication on declassification channels a feedback, as per , given below.
However, the point of this requirement is that the immediate context of s, in our case , can control which value actually gets declassified by feeding any value back into s in place of v. To illustrate how uses this feature to only release values which pass through this declassification interface and that allows, let , , and assume the -run has announced a -declassification by performing . If the -run has already performed a corresponding , and allows this declassification, has the -run perform as its next action. Otherwise, has the -run perform as its next action. Thereby, the system only leaks at the point of declassification (since declassification is nonblocking), and by separation, only leaks information available to the -run to the -run (as opposed to leaking, say, arbitrary information from the lexical context of the declassification statement). We will discuss the rationale for making declassification actions nonblocking in Section 5.6.
This approach, and , only have the desired effect if s adheres to our declassification interface, by first performing an output on a , and subsequently performing input on . We define this class of s now.
For all ,
is declassification-compliant iff
, and
.
is declassifying () iff .
Unless stated otherwise, any s we consider in this paper is declassification-compliant. We parameterise with a set of desired declassifications, which consults upon encountering a declassification announcement; if , the declassification is turned into a feedback. Let be the set of desired declassification channels which an ℓ-observer can observe the target, but not the source, of.
Semantics of . (a) ℓ-stepper. (b) ℓ-chooser. (c) history.
The semantics of is given in Fig. 9. A state is the same as a state; the only new component, δ, is stateless, and used to instantiate the semantics of . Note that interacts only on communication channels, that is, ; all declassification channel interaction is handled internally. By (-no), any undesired declassification is a feedback. Furthermore, when an ℓ-run requests a declassification on which is desirable, but which ℓ is not a valid target of, the request is a feedback. By (-), when a valid target ℓ-run of a declassification needs the declassified value before the source -run produces it, is declassified instead. Otherwise, by (-yes), if a valid target of a declassification has already received for the declassification in question, so does the ℓ-run (either every valid target of a declassification that requests it gets the value produced by (if one was produced), or none of them do). This is to prevent the presence or timing of a -declassification from leaking through the declassification action, analogous to our treatment of -output in . Otherwise, has already produced the value to be declassified into the ℓ-run, and no other valid target has requested the value before it got produced, so a declassification is made by transferring the declassified value from the -run to the ℓ-run.
Soundness
We now show how fits into our declassification models. Recall that takes as parameter the set δ of desired declassifications defining what can be leaked, and that utilizes rule (-) or (-yes) in Fig. 9(b) where a declassification occurs. To intentionally leak information, a system utilizes the declassification interface of . This provides with the information it needs to circumvent ℓ-run separation and support intentional release as a system feature, while at the same time only releasing information between security levels as desired by δ, which is our desired what goal. Furthermore, only declassifies information using rules (-) or (-yes). This provides us with the information we need to prove that only releases information through declassification actions, which is our desired where goal. We do this by making actions derived with (-) and (-yes) release actions, to interface with gradual release.
We start with the what results. Let be the reconciled releases of δ. As per the discussion on the coarseness of full release at the end of Section 5.2, since systems are (possibly malicious) black boxes, and since there therefore is no way to know or control what -information a system leaks through , any leakage of -information to the system makes must be reconciled. Fortunately, are the only leaks can make. Let .
.
The proof of this theorem follows a similar pattern as the proof of Theorem 4.2, utilizing a lemma which is nearly identical to Lemma 4.3.
If a system does not utilize the declassification interface, running the system in causes no information to be released; the resulting execution is noninterfering. This is a corollary of Theorem 4.2, since no step in a trace from is derived using any of the new rules from Fig. 9.
.
To provide our where results, we need to interface with gradual release. Before we do that, we show how to interface the systems operates on (i.e. declassification-compliant ones) with gradual release. We do this my creating a mapping from declassification-channels to release channels, as follows: Let be an injective function associating a release channel with each declassification channel, in such a way that the from- and to-levels match, that is, and (assume and are disjoint). Then, for the declassification semantics in Section 5.3, wrapping a declassifying system in the following declassification feedback will likewise perform a release action iff the system performs a declassification.
In , there are, for each declassification, (potentially) multiple ℓ-runs receiving it. Since not all receiving runs are necessarily ready to receive it at the time the value being declassified is produced by the from-level-run, the value cannot be fed to all of them at once. Indeed, the presence of a particular declassification action in those receiving ℓ-runs can vary, and each such (non)reception can leak different information to different observers. Furthermore, performing a release action when the from-level creates the value to be declassified leaks the presence of the declassification action in the from-level. Therefore, we make the reception of a declassified value, by each valid target of said declassification, a separate release action. We overload to a partial injective function (↛ denotes partial function) such that is defined iff , and such that and . Rules (-) and (-yes) in Fig. 9(b) are responsible for providing a declassified value to a valid target. By modifying the conclusion of these rules from the form
to the form
we obtain a variant of which performs a release action iff a declassified value is provided to a valid target run.
We are now ready to present the where result. The following technical lemma is in the style of Lemma 4.3. It states that can, under all the environments which an ℓ-observer knows could have caused , not only match , but do so in such a way that all -runs, for , are in exactly the same state. Let .
We now have that enforces gradual release, for any desired declassifications. Let .
.
Thus, only releases information through declassifications. Our instrumentation of with release actions was done to provide the where guarantee we needed. In practice, however, release actions will not be present in the of any system. To show that our instrumentation is nothing more than a tool to reason about where information leaks occur, we show that leaks at most as much as . First, for any list of actions can perform, can perform that same sequence of actions with release actions withheld. This follows from the definition of .
We refer to the in the above corollary as . The following result is what we are after. It follows from the above and Corollary 5.7.
In summary, our full release soundness result states that the only leaks can have are those declared as desired during instantiation of , and our gradual release soundness result states that only leaks through desired declassification actions. This, plus the way otherwise separates information like , ensures that ℓ-runs only leak information that has been declassified to them, and thus cannot leak arbitrary contextual information. For instance, in program , the of allows the declassification but prevents the implicit flow of a at the same time! This is a fruitful byproduct of our what model of declassification and the separation of computation into ℓ-runs; the -run never obtains -information, and thus cannot leak it (not even implicitly). At last, of the following program, with , and , allows the announced declassification, but stops the explicit flow. This follows from our where guarantee and separation; the -run receives dummy values as input on , and only receives the right value where the declassification occurs.
Transparency
The new declassification features we added to introduce new circumstances under which transparency is broken. If a system attempts a declassification which does not reconcile, then will deny the declassification by feeding to the to-run, thus breaking transparency. However, can impede transparency even if all releases made by a system are reconciled. By Corollary 5.18, when s attempts to leak information without utilizing the declassification interface, the corresponding control in never receives the declassified value. For instance, with , consider the system s defined by program in Section 5.2. We have (i.e. if we reconcile all releases made by s, s is otherwise secure). However, the -run in never gets the -value in the -input, and thus, cannot be transparent. Thus is too weak an assumption to guarantee that is transparent. What is needed is a property stipulating that a system only releases information through its declassification interface. By design, this property is ! Due to the assumption in Section 5.3 that for all , assumes that an ℓ-observer who can observe the to-level of a declassification also observes the values being declassified. So for declassifying systems, says that if we fix declassified values arbitrarily, no information is released. This implies that systems do not release non-declassified values, i.e., for systems, release is only possible through the declassification interface. However, even if we assume , a similar problem arises when the -run reaches a declassification before the -run does; then the -run instead receives . This occurs in the of from Section 5.2 ( replaced with ) if is scheduled too often before . Fortunately, we can rule out this scenario by assuming high-lead schedulers.
It turns out that these three scenarios – (1) preventing undesired declassifications, (2) systems not utilizing the declassification interface to leak, and (3) the to-level of a release reaching the declassification action before the from-level does – are the only inhibitors for transparency. So by assuming high-lead scheding, that , and that all declassifications attempted by s are desired by (that is, ), we get transparency – that is, that the interaction on ℓ-presence channels, of s under cf. s with declassification channels in feedback, is ℓ-equivalent.
, with,
,
.
Program satisfies ; when input (which has presence and content) is fixed by the environment, changes in input do not affect the value declassified. Also, the presence of the declassification action does not depend on -unobservables. It is easy to see that if and , then of routes the value announced by the -run (which is the actual value received on ) to the -run in the desired way, thus yielding a transparent run. When , of stops the forbidden declassification to preserve soundness. Since , our transparency result does not guarantee transparency. Indeed, transparency does not hold, since in , the declassification is prevented.
To further clarify the scope of the above transparency result, it is worth noting that there are programs which, when declassification is a noninteraction, satisfy , but when their declassification plumbing is pulled out to adhere to the declassification interface, do not satisfy ; the following modification of is such a program.
If is made into feedback, the result is a program which is not in and satisfies (and thus has no leaks). However, without said feedback, since the program compares the value it received on with the value it sent on , the program fails to satisfy , so does not have to be transparent for it. Indeed, as it turns out, the of this program attempts to leak whether the actual-input received by the of equals or not (which δ then either permits or prevents), so of , while sound for any δ, is not transparent. Thus, for programs in requires that a program can, without causing further leaks, let an arbitrary value (provided by the environment, independent of program state) be the result of executing a declassify statement. This rules out programs that behave like . This is needed by since ensures that the -run never gets the input it needs to construct the correct value to be declassified, to ensure that the only values the -run gets are ones that have been declassified. Without this assumption on s, can only guarantee soundness, not transparency. This explains why we did not assume in our transparency result (which is otherwise more natural). On a related note, this approach seems to be one way of resolving the issues with the scrambling declassification semantics of (qualified) robustness [32] mentioned by Sabelfeld and Sands [46].
Blocking on declassification
We close this section with a justification for the part of the semantics of which makes declassification actions performed by ℓ-runs nonblocking operations. Consider a variant of which does block the to-level-run of a declassification until the from-level-run has produced the value to be declassified. To keep the justification concrete, we consider only the below, and note that the justifications generalize to arbitrary lattices.
It turns out that is both transparent and sound. The transparency proof is the same as for (since, as noted at the end of as noted in Section 3.5, no actions are permitted to follow a input in secure programs). The soundness proof applies if we have produce a release action each time the -run is scheduled while blocking on a declassified value. The reason why this change to the soundness proof is needed – and the reason we chose to have make declassifications nonblocking – is that the nonpresence of the declassification output from the -run can leak 1 bit about the state of the -run, each time the -run is scheduled, until the -run produces a value to be declassified. This bit could be all the information contained in the -run state, and this could be a different bit every time the -run is scheduled, as is the case in the below program, for scheduler (which we assume is known to the attacker).
In contrast, leaks at most the whole state of the H-run once for each declassify action the L-run attempts (in the above example, one bit). We find that with the declassification semantics in , it is harder to assess what and how much is leaked (e.g. when the program running under is white-box), as the leak for a single declassify action can continue over time, forever. Hence we settled for .
Full transparency
This section shows how to achieve full transparency for secure multi-execution by barrier synchronization. Full transparency, in contrast to per-channel or per-level transparency, guarantees that our enforcement preserves the I/O behavior of secure programs, including the ordering of I/O messages. Thanks to such a strong property, we are able to deploy to detect attacks.
with barrier synchronization.
The core idea is pictorially summarized in Fig. 10. In contrast to Fig. 2, we are not ignoring the low output produced by the high run. Instead, we match it with the low output produced by the low run. If the program is secure, this approach guarantees that there will not be any deviation in this matching. Thus, if there is a deviation, it must be due to the insecurity of the original program. From this deviation, we can construct a counterexample to noninterference.
Semantics
A counterexample to is a proof of the logic negation of . That is, a level of observation ℓ, two -equivalent environments, and a trace which s can perform under one of those environments, but cannot -match under the other. We refer to such a counterexample as an -attack on s.
An -attack α is a 4-tuple with and . The attack is an -attack on s iff
, and
.
We now formalize our variant of , , which can construct attacks on run-time. Its semantics for a two-point lattice is given in Fig. 11. adds two new components to the -state, and , which contain the list of (potential) attacks discovered so far, making the -state a quintuple . The semantics works as follows. While nothing inhibits the -run from performing non--presence actions (by (-a) and (∙)), a barrier forms when the -run reaches a -presence action (by (-block)). The -run then only proceeds once the -run reaches a -presence action. When the -run reaches a -presence action, and the -run is yet to perform the corresponding action, a barrier forms (by (-wait)). The -run then only proceeds once the -run has done one of two things. (1) reached an -observable action before advancing t steps beyond the -run (by (-a)), or (2) advanced t steps without reaching a -observable action (by (-timeout)). In (1), if the -run reached a -observably different action, we note the discrepancy in . The -run will then be replaced by infinite silence (by (conflict)). In (2), we note the timeout in . Input environments are constructed from traces using , defined as .
Semantics of . (a) -stepper. (b) -chooser. (c) history.
Not every attack discovered by is an attack on s; we will establish when a discovered attack is an attack on s in Section 6.4.
Soundness
enforces . This is easily seen by observing that the traces produced by and are -equivalent. By allowing the -run to wait up to t steps for the -run to match an -observable, introduces a timing leak into s when , and thus does not enforce .
.
We note, however, that does enforces when , and that the attacks discovered are -attacks. We find, however, that becomes less practical with , since is much more likely to detect timeouts or discrepancies; when detects these, “freezes” the -run to avoid leaks, making the -run semantically equivalent to a program producing ∙ infinitely, by (conflict). A more practical version of would instead have the -run behave like it would under henceforth. We hypothesize (but do not prove) that this modification of yields a sound enforcement. In any case, this weakening of the soundness guarantee compared to is easily controlled by simply wrapping in a blackbox timing leak mitigator [4].
Transparency
Modulo ∙, and s produce the same sequence of I/O (up to discrepancy or timeout in ). This holds even when s is not secure. Point (a) below states that cannot break transparency without producing an attack on s, and Point (b) states that any trace that s can perform under which does not produce an attack, can be matched by s not running under .
,
.
A corollary of the above is that if , then s and have the same (i.e. -equivalent) I/O behavior! This is because never generates attacks for . In contrast to e.g. Devriese and Piessens [20], who swap the order of outputs in the following two programs (for linearization ), we have full I/O correspondence between each program and its .
However, the same I/O correspondence cannot hold in general if , since it is impossible (without solving the Turing halting problem) to determine whether the -run is taking forever, or just a very long time, to match the action by the -run. This can be demonstrated by the following program; for any predetermined value of t, there is an input on for which of the program times out while waiting for the -run to reach the output statement.
Attacks
It is important to note that even when s is not secure, running s under does not guarantee attack discovery; the of s might take branches of control in such a way that insecure states are never entered, and only detects attacks along the control flow path that its ℓ-runs take. However, if does detect a discrepancy between the -run and the -run on which -observable comes next (before a timeout has occurred), then has indeed found a concrete proof that .
is an-attack on s.
This theorem states that if the first attack discovered is a discrepancy, then the discrepancy is an -attack on s. Further discrepancies discovered before timeouts are discovered are -attack on s as well; we focused on the first attack in the above theorem since attacks discovered later may simply be extensions of the first attack. Unfortunately, as discussed above, we cannot infer in general that a timeout is an attack on s. Likewise, if a timeout is discovered before a discrepancy, we cannot conclude that the discrepancy is an attack on s, since the discrepancy might be the consequence of a timeout, which is not necessarily the basis of a leak in s.
We end this section with two -insecure programs, and describe the attacks which finds on them. Consider the following program.
With , and initial input 1, generates an -attack on s in , where , . Now consider the following program.
With , and initial input , generates an -attack on s in , where , . With initial input 5, no attack is generated. With initial input 500, however, an attack is generated which is not an attack on s (it merely took “too long” for the -run to match ).
Related work
Referring the reader for general overviews on language-based information-flow security [43], on dynamic information-flow control [26], and on declassification [46], we focus on related work on multi-execution.
Li and Zdancewic [29] observe that “a noninterfering program can usually be factored to a ‘high security’ part and a ‘low security part’ that does not use any of the high-level inputs h. As a result, noninterference can be proved by transforming the program into a special form that does not depend on the high-level input”. They propose relaxed noninterference that allows information release through a set of prescribed syntactic expressions. Their focus is on enforcing relaxed noninterference statically, by a security type system.
Russo et al. [40] sketch the idea of running multiple runs of a program, where each run corresponds to the computation of information at a security level. They discuss that by running the public computation ahead of the secret run, certain classes of timing attacks can be prevented.
Capizzi et al. [16] consider enforcement of secure information flow in the setting of an operating system. The enforcement is based on shadow executions as operating system processes for different security levels. They report on an implementation and an experimental study with benchmarks.
As discussed earlier, Devriese and Piessens [20] develop a general treatment of secure multi-execution at the application level and establish soundness and precision under the assumption of total environments (there is always new input), linear lattices and low priority scheduling.
Bielova et al. [12] investigate multi-execution in a reactive setting. Bielova et al.’s model multi-executes Featherweight Firefox [14], a formalization of a web browser as a reactive system. The environments of Bielova et al. are not necessarily total, but the security guarantee is weaker (than Devriese and Piessens’ [20]): termination-insensitive noninterference. The I/O model targets the browser setting, with handlers under cooperative scheduling. The full version [13] contains an informal discussion of what the authors call sub-input-event security policies, which corresponds to more flexible policies on input events (flexible policies on output events are not considered). These policies are defined by projections that describe how much is visible at each level. This mechanism is however not formalized. A formalization would require reasoning about policy consistency: for example, projections for less restrictive levels should not reveal more than projections for more restrictive levels.
Kashyap et al. [25] show that the low-priority scheduling might exhibit timing leaks for non-linear security lattices, and present several sound schedulers. We show (Appendix A) that in the presence of handlers, it is not necessary for the lattice to be non-linear to produce attacks on the low-priority scheduler. Timing leaks can freely occur in linear lattices, including the simple low-high lattice.
Jaskelioff and Russo [24] implement a monadic library for secure multi-execution in Haskell. Austin and Flanagan [7] introduce faceted values to simulate secure multi-execution by execution on enriched values. Faceted values can be projected to the different security levels. The projection theorem assures that a computation over faceted values faithfully simulates non-faceted computations. They show that faceted values guarantee termination-insensitive noninterference. Faceted values have been implemented in practical programming languages: for JavaScript by Austin and Flanagan, and for Jeeves [54] by Austin et al. [8]. Faceted values provide a viable alternative for an efficient implementation of our technique. Austin and Flanagan also show how to relax noninterference by facet declassification, based on robust declassification [33,56]. Robust declassification operates on both confidentiality and integrity labels, requiring the decision to declassify to be trusted. This leads to the introduction of integrity labels to model trust and integrity checks that the declassification operation is not influenced by untrusted data. This corresponds to the who dimension of declassification [46]. Compared to this approach, our declassification has aspects of what is declassified and where in the lattice and in the code information release may take place. We are able to capitalize on what secure multi-execution is best at: built-in security against implicit flows. No matter where in the code declassification occurs, it will not leak information about the context. There is no need to track the integrity of the code in our model.
Barthe et al. [11] present a “whitebox” approach to secure multi-execution. They devise a transformation that guarantees noninterference via secure multi-execution for programs in a language with communication and dynamic code evaluation primitives
De Groef et al. [18] implement secure multi-execution as an extension of the Firefox browser and report on experiments with browsing the web. Compared to the work by Bielova et al. [12] discussed above, De Groef et al. multi-execute the actual scripts in web pages rather than the entire browser. The main focus of their experiments is to confirm that the enforcement of simple policies does not modify the behavior of secure pages.
Compared to the work above, this paper enriches secure multi-execution with the following features: (i) channels with distinct presence and content security levels, (ii) the what dimension of declassification for secure multi-execution, (iii) full transparency results that preserve the order of messages, and (iv) show how secure multi-execution can be used to detect attacks. To the best of our knowledge, none of these features have been previously explored in the context of secure multi-execution.
This paper stands on the ground laid by our previous work [37] on the foundations of security for interactive programs. This earlier work presents a general framework for environments as strategies, lifts the assumptions of the total environment, and distinguishes between the security level of message presence and content in the general setting. While the previous work provides an excellent starting point for the present paper, it does not treat secure multi-execution.
Performance-wise, like Devriese and Piessens [20], the time complexity of our approach is linear in the size of the security lattice, since a process is created for each lattice element. That being said, when the size of the lattice is smaller than the number of CPU cores, the overhead of our approach is negligible, and can even yield an improvement since runs synchronize less with the environment. This is indicated by benchmarks performed by Devriese and Piessens, which are portable to our setting.
Unno et al. [51] focus on the problem of finding counterexamples against noninterference: pairs of input states that agree on the public parts and lead to paths that disagree on public outputs. Their technique combines type-based analysis and model checking to explore execution paths for programs that may cause insecure information flow. They show that this method is more efficient than model checking alone. In comparison, our attack-detection technique does not require program analysis and allows reasoning about the security of individual runs.
In an independent effort, Zanarini et al. [55] apply secure multi-execution for program monitoring in a reactive setting modeled by interaction trees. This work relates to our attack detection results, although it focuses on a more relaxed, progress-insensitive, security condition. Given a program, the goal is to construct a scheduler for secure multi-execution that mimics the execution of the original program. Whenever a deviation is detected, the execution is blocked to avoid leakage. This approach enforces progress-insensitive noninterference.
Most recently, Vanhoef et al. [52] have investigated an approach to declassification in secure multi-execution. This is accomplished through escape hatch [44] expressions, provided as policies for release, separately from code. Only through these expressions it is possible to declassify information to lower and incomparable security levels. This allows expressing what is released in a fine-grained fashion, but does not allow controlling where in the program the release may take place. Our approach is more coarse-grained for specifying what is released (per-level granularity rather than per-expression), yet it has the benefit of ensuring that information release takes place only at designated declassification points, thus also controlling where information can be declassified.
Conclusion
Secure multi-execution emerges as a promising technique for enforcing secure information flow. We have overviewed the pros and cons of secure multi-executions and identified most pressing challenges with it. This paper pushes the boundary of what can be achieved with secure multi-execution. First, we lift the assumption from the original secure multi-execution work on the totality of the input environment (that there is always assumed to be input) and on cooperative scheduling. Second, we generalize secure multi-execution to distinguish between security levels of presence and content of messages. Third, we introduce a declassification model for secure multi-execution that allows expressing what information can be released and where in the program the release can take place. We prove that declassification only affects the declared security levels and that our declassification mechanism restricts release to program points with declassification annotations. Fourth, we establish a full transparency result by barrier synchronization of the runs at different security levels. Full transparency guarantees that secure multi-execution preserves the original order of messages in secure programs. We demonstrate that full transparency is a key enabler for discovering attacks with secure multi-execution.
Representing reactive systems in our setting is an interesting topic of future work. In a reactive setting, an incoming input event determines which handler may be triggered. We can model this by tagging input values with a channel ID. The program can then pattern-match on the tag to dispatch the value to the handler associated with the channel.
Future work also includes implementation and case studies. We plan to experiment with modifying the Firefox browser to accommodate fine-grained, declassification-aware, and transparent secure multi-execution. The modification will allow us to multi-execute JavaScript code in an environment with preemptive scheduling of the runs at different levels.
Footnotes
Acknowledgments
Thanks are due to Frank Piessens for generous feedback, and to Daniel Hedin, and David Sands for the useful discussions. This work was funded by the European Community under the ProSecuToR and WebSand projects, by the Swedish research agencies SSF and VR, the US Naval Research award no. N000141310156 and NSF grant award no. CNS1320470.
FlowFox leak
The leak exploits the fact that FlowFox [18] multi-executes JavaScript with the low-priority scheduler on a per-event basis. Low priority implies that the low run is executed first and without preemption. The low-priority scheduler first applies to the main code. If the main code sets event handlers, they are processed after the multi-execution of the main code. Low handlers are multi-executed. High handlers are only run once, at the high level.
Note that the problem with low-priority scheduling is fundamental because it is not possible to extend the low-priority discipline over multiple events – simply because it is not possible to run the low handlers that have not yet been triggered.
The security theorem in the abstract setting of secure multi-execution [20] takes advantage of the low-priority scheduler and establishes timing-sensitive security. This is intuitive because the last access of the low data occurs before any high data is accessed. This implies that whenever the timing behavior is affected by secrets, there is no possibility for the attacker to inspect the difference.
We show that the situation is different in the presence of handlers. All we need to do is to set a low handler to execute after the high run for the main code has finished. Then the low handler can inspect the computation time taken by the high run. For a simple experiment, we consider the default example policy from the FlowFox distribution1
in Listing 1. The listing omits the non-customizable part of the policy, focusing on the sources and sinks. This policy defines same-origin domain as HIGH and cross-origin domains as LOW (line 16). In order to protect cookies, secret sources are defined by labeling document.cookie as HIGH (line 19). Lines 20 and 21 define the sinks that correspond to setting the source attributes of image and script HTML elements. These are labeled as HIGH for the same origin and LOW for the other origins. The intention is to prevent attacks that leak information about the cookie to third-party web sites (any sites other than the site of the web page origin).
Nevertheless, the code in the web page in Listing 2 leaks one bit of information about the cookie to the third-party web site attacker.com. Function getTime() of the object returns the number of milliseconds since the midnight of January 1, 1970. First, information about the cookie flows via document.cookie into variable (line 8). Depending on the value of , the program might take longer time to execute (line 10). As foreshadowed below, all we need to do is to get a time stamp at the beginning of execution (line 4) and after the high run has finished. The difference in time reveals whether was zero. In order to bypass FlowFox’s multi-execution, we simply create a low handler (line 5) to perform the final time measurement (line 15). Running this page in FlowFox results in a request for an image with URL http://attacker.com?v=496 (repetitive runs show slight fluctuation around the value of 496). Running the code with line 7 uncommented and line 6 commented out, results in a request for an image with URL http://attacker.com?v=6 (repetitive runs fluctuate insignificantly around the value of 6). Hence, we can reliably leak one bit of secret information about the cookies. Clearly, the leak can be easily magnified to leak the entire cookie by walking through it bit-by-bit in a simple loop and sending the results for each bit to the attacker.
Note that changing the policy for getTime() to return HIGH result does not close the timing leak. The leak can be still achieved exploiting the difference in the internal timing behavior by a combination of low handlers [41].
While the leak outlined above is achieved by issuing a timeout event, other events (such as user-generated events and XMLHttpRequest) can be used to achieve the same effect.
The low-priority scheduler is both at the heart of the soundness results by Devriese and Piessens [20] and at the heart of FlowFox [18]. The experiment points to a fundamental problem with low-priority scheduling. The leak demonstrates that the low-priority scheduler breaks timing-sensitive security and motivates the need for (fair) interleaving of the runs at different levels, as pursued in this paper.
Projections
A projection applies as far left as possible (unless indicated otherwise with parentheses). For instance, means , not . For all projections, . Let $ range over ? and !. The projection functions used throughout the paper and appendix are then as given in Fig. 12.
Proofs
In the following lemma, iff .
Let behave like s except when s performs input on a declassification channel; that input is then drawn from e. In effect, B binds declassification channels internally. Let .
References
1.
J.Agat, Transforming out timing leaks, in: Proc. ACM Symp. on Principles of Programming Languages, 2000, pp. 40–53.
2.
A.Askarov and A.Sabelfeld, Gradual release: Unifying declassification, encryption and key release policies, in: Proc. IEEE Symp. on Security and Privacy, 2007, pp. 207–221.
3.
A.Askarov and A.Sabelfeld, Tight enforcement of information-release policies for dynamic languages, in: Proc. IEEE Computer Security Foundations Symposium, 2009.
4.
A.Askarov, D.Zhang and A.C.Myers, Predictive black-box mitigation of timing channels, in: CCS, 2010.
5.
T.H.Austin and C.Flanagan, Efficient purely-dynamic information flow analysis, in: Proc. ACM Workshop on Programming Languages and Analysis for Security (PLAS), 2009.
6.
T.H.Austin and C.Flanagan, Permissive dynamic information flow analysis, in: Proc. ACM Workshop on Programming Languages and Analysis for Security (PLAS), 2010.
7.
T.H.Austin and C.Flanagan, Multiple facets for dynamic information flow, in: Proc. ACM Symp. on Principles of Programming Languages, 2012, pp. 165–178.
8.
T.H.Austin, J.Yang, C.Flanagan and A.Solar-Lezama, Faceted execution of policy-agnostic programs, in: Proc. ACM Workshop on Programming Languages and Analysis for Security (PLAS), ACM, New York, NY, USA, 2013, pp. 15–26.
9.
A.Banerjee, D.Naumann and S.Rosenberg, Expressive declassification policies and modular static enforcement, in: Proc. IEEE Symp. on Security and Privacy, 2008.
10.
J.Barnes, High Integrity Software: The SPARK Approach to Safety and Security, Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA, 2003.
11.
G.Barthe, J.M.Crespo, D.Devriese, F.Piessens and E.Rivas, Secure multi-execution through static program transformation, in: Formal Techniques for Distributed Systems (FMOODS/FORTE 2012), LNCS, Vol. 7273, 2012, pp. 186–202.
12.
N.Bielova, D.Devriese, F.Massacci and F.Piessens, Reactive non-interference for a browser model, in: Proc. 5th International Conference on Network and System Security (NSS), 2011.
13.
N.Bielova, D.Devriese, F.Massacci and F.Piessens, Reactive non-interference for the browser: Extended version, Technical Report CW602, CS Dept., K.U. Leuven, 2011.
14.
A.Bohannon and B.C.Pierce, Featherweight Firefox: Formalizing the core of a web browser, in: Proc. USENIX Conference on Web Application Development, 2010.
15.
A.Bohannon, B.C.Pierce, V.Sjöberg, S.Weirich and S.Zdancewic, Reactive noninterference, in: ACM Conference on Computer and Communications Security, 2009, pp. 79–90.
16.
R.Capizzi, A.Longo, V.N.Venkatakrishnan and A.Prasad Sistla, Preventing information leaks through shadow executions, in: Annual Computer Security Applications Conference (ACSAC), 2008, pp. 322–331.
17.
D.Clark and S.Hunt, Noninterference for deterministic interactive programs, in: Workshop on Formal Aspects in Security and Trust (FAST’08), 2008.
18.
W.De Groef, D.Devriese, N.Nikiforakis and F.Piessens, FlowFox: A web browser with flexible and precise information flow control, in: ACM Conference on Computer and Communications Security, 2012.
19.
D.E.Denning, A lattice model of secure information flow, Comm. of the ACM19(5) (1976), 236–243.
20.
D.Devriese and F.Piessens, Non-interference through secure multi-execution, in: Proc. IEEE Symp. on Security and Privacy, 2010.
21.
C.Dima, C.Enea and R.Gramatovici, Nondeterministic nointerference and deducible information flow, Technical Report 2006-01, LACL, University of Paris 12, 2006.
22.
J.A.Goguen and J.Meseguer, Security policies and security models, in: Proc. IEEE Symp. on Security and Privacy, 1982, pp. 11–20.
23.
D.Hedin and A.Sabelfeld, Information-flow security for a core of Javascript, in: Proc. IEEE Computer Security Foundations Symposium, 2012, pp. 3–18.
24.
M.Jaskelioff and A.Russo, Secure multi-execution in Haskell, in: Proc. Andrei Ershov International Conference on Perspectives of System Informatics, LNCS, Vol. 7162, Springer-Verlag, 2011, pp. 170–178.
25.
V.Kashyap, B.Wiedermann and B.Hardekopf, Timing- and termination-sensitive secure information flow: Exploring a new approach, in: Proc. IEEE Symp. on Security and Privacy, 2011.
26.
G.Le Guernic, Confidentiality enforcement using dynamic information flow analyses, PhD thesis, Kansas State University, 2007.
27.
G.Le Guernic, Automaton-based confidentiality monitoring of concurrent programs, in: Proc. IEEE Computer Security Foundations Symposium, 2007, pp. 218–232.
28.
G.Le Guernic, A.Banerjee, T.Jensen and D.Schmidt, Automata-based confidentiality monitoring, in: Proc. Asian Computing Science Conference (ASIAN’06), LNCS, Vol. 4435, Springer-Verlag, 2006.
29.
P.Li and S.Zdancewic, Downgrading policies and relaxed noninterference, in: Proc. ACM Symp. on Principles of Programming Languages, 2005, pp. 158–170.
30.
H.Mantel, Information flow control and applications – Bridging a gap, in: Proc. Formal Methods Europe, LNCS, Vol. 2021, Springer-Verlag, 2001, pp. 153–172.
31.
H.Mantel and D.Sands, Controlled downgrading based on intransitive (non)interference, in: Proc. Asian Symp. on Programming Languages and Systems, LNCS, Vol. 3302, Springer-Verlag, 2004, pp. 129–145.
32.
A.C.Myers, A.Sabelfeld and S.Zdancewic, Enforcing robust declassification, in: Proc. IEEE Computer Security Foundations Workshop, 2004, pp. 172–186.
33.
A.C.Myers, A.Sabelfeld and S.Zdancewic, Enforcing robust declassification and qualified robustness, J. Computer Security14(2) (2006), 157–196.
34.
A.C.Myers, L.Zheng, S.Zdancewic, S.Chong and N.Nystrom, Jif: Java information flow. Software release, 2001, available at: http://www.cs.cornell.edu/jif.
35.
N.Nikiforakis, L.Invernizzi, A.Kapravelos, S.Van Acker, W.Joosen, C.Kruegel, F.Piessens and G.Vigna, You are what you include: Large-scale evaluation of remote Javascript inclusions, in: ACM Conference on Computer and Communications Security, 2012, pp. 736–747.
36.
K.O’Neill, M.Clarkson and S.Chong, Information-flow security for interactive programs, in: Proc. IEEE Computer Security Foundations Workshop, 2006, pp. 190–201.
37.
W.Rafnsson, D.Hedin and A.Sabelfeld, Securing interactive programs, in: Proc. IEEE Computer Security Foundations Symposium, 2012.
38.
W.Rafnsson and A.Sabelfeld, Limiting information leakage in event-based communication, in: Proc. ACM Workshop on Programming Languages and Analysis for Security (PLAS), 2011.
39.
W.Rafnsson and A.Sabelfeld, Secure multi-execution: Fine-grained, declassification-aware, and transparent, in: Proc. IEEE Computer Security Foundations Symposium, 2013, pp. 3–18.
40.
A.Russo, J.Hughes, D.Naumann and A.Sabelfeld, Closing internal timing channels by transformation, in: Proc. Asian Computing Science Conference (ASIAN’06), LNCS, Vol. 4435, Springer-Verlag, 2007.
41.
A.Russo and A.Sabelfeld, Securing timeout instructions in web applications, in: Proc. IEEE Computer Security Foundations Symposium, 2009.
42.
A.Russo and A.Sabelfeld, Dynamic vs. static flow-sensitive security analysis, in: Proc. IEEE Computer Security Foundations Symposium, 2010.
43.
A.Sabelfeld and A.C.Myers, Language-based information-flow security, IEEE J. Selected Areas in Communications21(1) (2003), 5–19.
44.
A.Sabelfeld and A.C.Myers, A model for delimited information release, in: Proc. International Symp. on Software Security (ISSS’03), LNCS, Vol. 3233, Springer-Verlag, 2004, pp. 174–191.
45.
A.Sabelfeld and A.Russo, From dynamic to static and back: Riding the roller coaster of information-flow control research, in: Proc. Andrei Ershov International Conference on Perspectives of System Informatics, LNCS, Vol. 5947, Springer-Verlag, 2009.
46.
A.Sabelfeld and D.Sands, Declassification: Dimensions and principles, J. Computer Security17(5) (2009), 517–548.
47.
P.Shroff, S.Smith and M.Thober, Dynamic dependency monitoring to secure information flow, in: Proc. IEEE Computer Security Foundations Symposium, 2007, pp. 203–217.
48.
V.Simonet, The Flow Caml system. Software release, 2003, available at: http://cristal.inria.fr/~simonet/soft/flowcaml.
H.Unno, N.Kobayashi and A.Yonezawa, Combining type-based analysis and model checking for finding counterexamples against non-interference, in: Proc. ACM Workshop on Programming Languages and Analysis for Security (PLAS), 2006, pp. 17–26.
52.
M.Vanhoef, W.De Groef, D.Devriese, F.Piessens and T.Rezk, Stateful declassification policies for event-driven programs, in: CSF, 2014.
53.
D.Volpano, G.Smith and C.Irvine, A sound type system for secure flow analysis, J. Computer Security4(3) (1996), 167–187.
54.
J.Yang, K.Yessenov and A.Solar-Lezama, A language for automatically enforcing privacy policies, in: POPL, 2012, pp. 85–96.
55.
D.Zanarini, M.Jaskelioff and A.Russo, Precise enforcement of confidentiality for reactive system, in: Proc. IEEE Computer Security Foundations Symposium, 2013.
56.
S.Zdancewic and A.C.Myers, Robust declassification, in: Proc. IEEE Computer Security Foundations Workshop, 2001, pp. 15–23.