• No results found

Solving the Challenges for Secure Large-Scale Trusted Executions

In this thesis, we embrace these challenges and provide solutions for secure, efficient, scalable and available outsourced services. We show how to deliver these features for real world services that are composed of large code bases and use large data sets. Our contributions consist of three main complementary techniques: fresh integrity guarantees and performance for outsourced services with a large code base (Chapter 3); scalability to large amounts of data (Chapter 4); availability through cost-effective service replication (Chapter5). An additional contribution is an abstraction for Trusted Computing on which the above techniques are built (Chapter2).

Next we briefly provide the insights and an overview of our abstraction for trusted execu- tions (Section 1.5.1) and of the techniques that, combined, enable to identify just the actively executed code (Section1.5.2) for large-scale data processing (Section1.5.3) with availability guar- antees (Section1.5.4).

1.5.1 An Abstraction for Trusted Executions

As Trusted Computing architectures are very diverse, it is natural to ask whether it is at all possible to define a single interface for a generic Trusted Computing Component (TCC). The key insight is that ultimately, all Trusted Computing architectures are used to implement a similar set of services needed to support a trusted execution. The TCC interface that we describe pro- vides an abstraction for these services, rather than architectural features, allowing us to hide the differences between Trusted Computing architectures from application developers.

The abstraction for trusted code executions that we present is defined by a small set of prim- itives. These are our building blocks for the rest of the contributions. The primitives derive immediately from fundamental Trusted Computing concepts such as isolated execution, sealed storage, attestation, etc. They enable developers to build (or port) services on top of an abstract trusted component, to optimize the implementation, and require minimal effort and no knowl- edge of the details of the underlying trusted hardware architecture. In addition, the abstraction enables cloud providers to upgrade the trusted hardware (and/or the system built on top of it) as new architectures are released, or to compare these architectures with minimal effort. We discuss two implementations on two different Trusted Computing architectures.

1.5.2 Verifying an Application by Identifying just the Necessary Code

In order to avoid the TCC effort for loading and identifying unnecessary parts of a large sensitive service code, an obvious solution is to implement the service as a set of modules and to only load and identify the modules that are executed. However, a more significant challenge is how to efficiently verify that the control flow is respected, i.e., the intended modules are executed in the intended order.

The insight is to leverage mutually-authenticated sealed storage to chain the modules together and to let the client infer from a single attestation that the intended necessary set of modules were executed in the intended order. One attestation verification allows to establish trust in a trusted module. Since all modules are securely chained together pair-wise to exchange data, the verified module could only have exchanged data with another trusted module in the order defined by the secure chain.

The solution [67] that we present in Chapter3works as follows. First we split the code base into suitable code modules that can be composed together to implement the original code base logic. This can be achieved for example with known techniques such as program slicing [68] or program partitioning [69]. We then design a protocol that lets the Trusted Computing architec- ture load, identify and run only modules of the code base that are actually required during the execution. This allows us to reduce the active TCB and to save resources since the trusted com- ponent does not have to load and identify unneeded modules into the secure environment. The correct execution sequence of code modules is guaranteed by a robust and verifiable execution chain. Specifically, each module secures the application data using a secret key that depends on its own identity and the identity of the next module in the correct sequence. The protocol eventually allows the client to verify the execution chain efficiently by simply verifying a chain end-point to bootstrap trust in the whole chain. An interesting consequence of this construction is that the client does not require any knowledge of the exact execution order of the code mod- ules, because the end-point verification ensures the correctness of the whole chain, whatever it may be for a specific execution.

1.5.3 Feeding Code with Large-Scale Data using Secure Virtual Memory Maps

Two insights are at the core of the contribution. In particular, (i) data I/O can be performed with no additional interface calls by simply handling page faults; (ii) memory constraints can be overcome by organizing the state into hierarchical components which can be mapped in memory efficiently and independently. Next, we elaborate on these insights.

First, by providing to the service code the entire view of the state in memory (i.e., code can access any data by simply walking the memory), we can reduce the data I/O problem to a vir- tual memory management problem. This can be solved without interface calls to the untrusted environment and without including OS code or peripherals in the TCB. Moreover, since we only assume the existence of virtual memory, which is a common feature in today’s systems, the tech- nique is applicable to different TCCs.

Second, mapping large-scale data in memory raises issues when the address space is small (e.g., 32-bit) or a limited set of addresses is a available (e.g., if the application can only access a small range of memory, say 1GB). When dealing with a terabyte of data, even the associated hash tree organized in an array may end up consuming lots of addresses. These issues can be solved by organizing the data, and the authentication metadata, into small components orga- nized hierarchically and each one having its own authentication metadata. These components can be efficiently mapped in memory when required, and the data can be authenticated effi- ciently through the hierarchical data structure. Most importantly, components that are no longer needed in memory can be unloaded in order to allow reusing memory and addresses.

These insights led to the design and implementation of LaStGT [41] which we describe in Chapter 4. LaStGT can handle a Large State on a Generic Trusted component using a small TCB. The small TCB is the result of offloading many operations that are not security sensitive to untrusted code, thereby avoiding implementing and running them within the trusted execution environment. We specifically refer to data I/O to/from mass storage supports or through the network. As a result, LaStGTdoes not include disks and network cards within the trust bound- aries. LaStGTsimply lets untrusted code manage data I/O between the storage medium and the main memory and organize data into memory maps. Then, trusted code leverages paged virtual memory and memory maps to incrementally load the data that the service needs to process. The data is validated through a scalable authentication data structure before the service uses it, so to ensure that it does not process unintended data.

Interestingly, besides the trusted execution interface, LaStGTdoes not require any additional system call or interface between the service application and the virtual memory management code. Our solution is purely based on virtual memory and thus generic and portable.

We point out however that there are two important differences with respect to VC3 [39]. First, the current design of LaStGT does not target MapReduce applications but rather self-contained x86 applications, which are not supported in VC3. As an example, we will show how the SQLite database engine application [188] performs on LaStGTfor handling terabyte-scale databases. Sec-

ond, LaStGTcurrently does not focus on data/code confidentiality but only data integrity.

1.5.4 Improving Availability through Secure Replication

Passive replication is not robust because the execution at the primary is not replicated (only the state is replicated). The obvious insight is to leverage Trusted Computing to secure the pri- mary execution, and to build a passive replication system inside the trusted environment of the replicas. This however comes with significant challenges such as reducing the TCB (e.g., storage and network peripherals) while preventing rollback attacks, and ensuring efficient operations for instance avoiding repeated attestation and verification steps.

These issues can be solved by leveraging trusted counters and sealed storage, which are com- mon features provided by Trusted Computing architectures. Trusted counters prevent rollback attacks, as they can only be updated in a monotonically increasing fashion. Sealed storage allows a service to protect data so that it can be stored in untrusted storage. These mechanisms can be combined to implement a secure protocol, since the protocol’s state can be securely stored while messages are exchanged among the replicas through the network.

This insight led to the concept of Verified Passive Replication (V-PR) [37] that we describe in Chapter5. By leveraging a client’s ability of verifying a trusted execution, V-PR avoids service re-executions and simply replicates the state of the primary replica to the backup replicas—i.e., any data modification performed by the primary replica is mirrored on the backup replicas (this is also known as Passive Replication, PR). Hence, V-PR faithfully follows the PR scheme rather than AR, but crucially enriches it with trusted executions to provide stronger security guarantees. V-PR is particularly attractive for computationally intensive services, since it does not require re-executions, and for the same reason it natively supports non-deterministic implementations. V-PR is also designed on our generic trusted execution primitives (Section2.3) thereby inheriting all the benefits that such abstraction provides.

We conclude by emphasizing three interesting aspects of V-PR. First, it helps to provide low- cost replication for outsourced services. Second, it can benefits from our previous techniques (Section1.5.2, Section 1.5.3) since it heavily leverages trusted executions, but it is not directly concerned with code identification or large-scale data processing. Third, V-PR is relevant to the Dependability community as it provides a novel hardware-based approach to secure and efficient replication that radically departs from the usual practice (i.e., AR).