Pyronia: Redesigning Least Privilege and Isolation for the Age of IoT

03/05/2019
by   Marcela S. Melara, et al.
0

Third-party modules play a critical role in IoT applications, which generate and analyze highly privacy-sensitive data. Unlike traditional desktop and server settings, IoT devices are mostly single-purpose running a dedicated, single application. As a result, vulnerabilities in third-party libraries within a process pose a much bigger threat than on traditional platforms. Yet the only practical data protection mechanisms available today for IoT developers are ad-hoc tools that are not designed to prevent data leaks from malicious or vulnerable third-party code imported into an application. We present Pyronia, a privilege separation system for IoT applications written in high-level languages. Pyronia exploits developers' coarse-grained expectations about how imported third-party code operates to restrict access to files and devices, specific network destinations, and even in-memory data objects, at the level of individual library functions. To efficiently protect data as it flows through the application, Pyronia combines three access control techniques: system call interposition, call stack inspection, and memory protection domains. This design obviates the need for prior unintuitive or error-prone data flow analysis or application re-architecting, while enforcing the developer's access policy at run time. Our Pyronia prototype implementation for Python runs on a custom Linux kernel, and incurs low performance overhead on completely unmodified Python applications.

READ FULL TEXT VIEW PDF
03/05/2019

Pyronia: Intra-Process Access Control for IoT Applications

Third-party code plays a critical role in IoT applications, which genera...
07/30/2019

EnclaveDom: Privilege Separation for Large-TCB Applications in Trusted Execution Environments

Trusted executions environments (TEEs) such as Intel(R) SGX provide hard...
10/31/2018

Securing IoT Apps with Fine-grained Control of Information Flows

Internet of Things is growing rapidly, with many connected devices now a...
07/08/2019

StackVault: Protection from Untrusted Functions

Data exfiltration attacks have led to huge data breaches. Recently, the ...
05/12/2020

Towards Memory Safe Python Enclave for Security Sensitive Computation

Intel SGX Guard eXtensions (SGX), a hardware-supported trusted execution...
07/13/2021

On the Analysis of MUD-Files' Interactions, Conflicts, and Configuration Requirements Before Deployment

Manufacturer Usage Description (MUD) is an Internet Engineering Task For...
09/08/2020

SGX-MR: Regulating Dataflows for Protecting Access Patterns of Data-Intensive SGX Applications

Intel SGX has been a popular trusted execution environment (TEE) for pro...

1 Introduction

Concerns about data security in the Internet of Things (IoT) have been mounting in the wake of private data leaks in safety-critical technologies (e.g., [24, 26, 71]) and large-scale malware attacks exploiting vulnerable devices [55, 22, 14]. These concerns have driven device manufacturers and application developers to deploy measures that secure data in-transit to cloud platforms [6, 41], or that prevent attackers from running unauthorized code on devices [47, 33]. Yet, these ad-hoc safeguards do not prevent vulnerable and malicious third-party code within an application from leaking sensitive information.

Myriad prior proposals have sought to restrict untrusted third-party code and enforce least privilege [46] with two main techniques. The first traditional approach seeks to partition a monolithic application into multiple processes in order to strongly isolate libraries and control their access to OS resources (e.g., [12, 59, 11, 67, 66, 51]). However, process isolation imposes significant development and run-time overheads. Developers may have difficulty cleanly separate components into processes, and inter-component interactions require expensive inter-process communication. More recent work in this area has introduced intra-process abstractions to create private memory compartments within a single process address space [38, 30, 16, 62], yet these proposals lack built-in access control for sensitive OS resources, and still require major developer effort for deployment.

The second traditional technique attaches policy labels to individual sensitive data objects, and tracks these objects at the level of programming language primitives as they propagate through the application. Such language-level information flow control (IFC) systems (e.g., [68, 23, 21, 52, 17, 40]) are capable of controlling access to sensitive data at granularities as fine as individual bytes.111IFC systems that operate at other software layers, such as OS-level IFC systems, are generally not expressly designed for in-application privilege separation. We discuss such systems in §8. Yet, much like process isolation, language-level IFC systems introduce a considerable amount of cost and complexity: Developers must manually annotate their source code to specify their decentralized policy labels around sensitive data sources and sinks. Additionally, propagating new labels at run time incurs significant memory and performance overheads.

Given the rapid proliferation of IoT devices and the high sensitivity of the data they handle, we believe it is crucial to make least privilege and isolation practical. To this end, we present Pyronia,222Pyronia being a gatekeeper for third-party libraries, is named after the genus of butterflies known as gatekeeper butterflies. a privilege separation system that protects applications against exploits and vulnerabilities in untrusted third-party code with unmodified source code and minimal developer effort.

In Pyronia, we retain the goals of controlling how an application may obtain data from files and devices, how in-memory data is propagated within an application, specifically between third-party library functions, and to which remote network destinations an application may export data. By combining three access control techniques, Pyronia overcomes the limitations of prior approaches to achieve both fine-grained privilege separation and strong isolation without losing flexibility.

Our design hinges on one important observation: libraries are not monolithic. The median Python library used in IoT applications, for instance, has a dependency graph (i.e., number of nested library dependencies) 25 levels deep (see §2). Thus, while propagating data labels dynamically through the application based on a decentralized access policy enables finer-grained data leak protection, reasoning a priori about all sensitive data paths within an application to prevent any data leaks proves to be a cumbersome and error-prone task.

In contrast, as an access control-based system, Pyronia enforces a central policy that specifies function-level access rules for directly imported third-party library functions and the specific OS resources they may access. For example, to ensure that a sensitive image pic.jpg

can only be accessed by a third-party facial recognition library function

imgproc.recognize_face(), the developer specifies a read rule for the input pic.jpg in her policy. Pyronia then blocks all attempts by any other library functions to access the image file. Thus, developers need not reason about third-party code that may be unavailable or unfamilar to them, and application or library source code can remain unmodified.

To enforce such function-granular access control, Pyronia leverages the following three techniques.

  1. [label=0)]

  2. System call interposition4.1) guarantees that access to OS resources by all application components can be controlled, even for native libraries integrated via a high-level native interface such as the Java JNI or the Python C API. However, system call interposition has traditionally only been realized as a process-level technique, and thus cannot handle intra-process access checks.

  3. Stack inspection4.1) allows Pyronia to identify all library functions involved in the call chain that led to a given system call. Specifically, borrowing ideas from fine-grained privilege separation proposals in the mobile space such as [50] and [63], Pyronia checks the language runtime call stack to determine whether to grant access to a requested resource based on the full provenance of the intercepted system call.

  4. Memory domains4.2) enable userspace processes to control access to specific memory regions within their own address space. Pyronia uses this technique to prevent native code, which resides in the same address space as the language runtime, from tampering with the call stack in an attempt to bypass Pyronia’s resource access control checks.

    We also leverage memory domains to control access to sensitive in-memory data, i.e., function inputs and outputs, as they flow within the application. For example, to protect imgproc.recognize_face()’s sensitive output, the developer can mark it with a label (e.g., face_image). During runtime, Pyronia automatically maps labeled data objects to separate memory domains. We detail our data object isolation mechanism in  §4.3.

We implement Pyronia for Python and Linux (§5). However, we believe our approach can be applied to other language runtimes. Our prototype Pyronia system acts as a drop-in replacement for the cPython runtime, and includes a custom Linux kernel with support for memory domains. Our stack-inspection-based system call interposition component is a kernel module built on top of the AppArmor [8] Linux MAC system. To facilitate integration into a language runtime, we have implemented a Pyronia user-space library, which provides an API for automatically loading a developer-supplied resource access policy, as well as a memory domain management API.

We evaluated Pyronia’s effectiveness and performance by running three open-source IoT applications (§6). We demonstrate that Pyronia provides least privilege enforcement with moderate execution time and memory overhead. In particular, while the mean execution time overhead is not trivial, we find that it would remain imperceptible for IoT applications that only passively collect data without much user interaction. We attribute, these overheads mostly to the cost of dynamic access privilege adjustments to Pyronia’s memory domains to enable Python’s garbage collection. Maintaining the call stack and per-data object memory domains requires only 0.33 kB of additional RAM per domain page (see §4.2), and a maximum of 28.1% additional memory for the entire application.

2 IoT Application Development Today

Before designing Pyronia, we first sought to understand the landscape of IoT application development. To do so, we conducted an in-depth study of 85 open-source IoT applications and their libraries written in Python, as well as a brief analysis of reported vulnerable third-party Python libraries. Our analyses focus on Python because it is one of the most popular IoT development languages [10].

2.1 Library Vulnerabilities

Our survey of reported Python library vulnerabilities covers 47 reports created between February 2012 and June 2017 in the Common Vulnerabilities and Exposures (CVE) List [56]. We identify 34 distinct vulnerable Python libraries, and 7 main attack classes (see Table 1). We include information leaks resulting from unverified SSL server certificates as part of data leaks, and shell injections under arbitrary code execution. A symlink attack allows an adversary to gain unauthorized access to a resource via a specially crafted symbolic link.

Attack Class Number of Reports
Data leak 15
Arbitrary code execution 12
Symlink attack 5
Weak crypto 5
Privilege escalation 4
Memory attack 4
Data spoofing 3
Table 1: Reported Python library vulnerabilities by attack class, from 2012-2017.

We also find that creating a malicious library is fairly straightforward. In our lab setting, we built a Python module and a native library that exploit dynamic language features of Python to replace function pointers at runtime with malicious functions, leak data at import time, and are able to perform various modifications to the Python runtime’s call stack. Importantly, these attacks are possible because Python exposes the exploited APIs and features to provide programmers with more flexibility, visibility, and control over a module’s functionality.

While we have not identified such attacks in the wild, our experiments demonstrate that these dynamic features and open APIs place too much trust in third-party library developers, and can be misused for nefarious purposes. Thus, both dynamic language features and the capabilities of native libraries pose threats to the integrity of the application itself and the privacy of user data.

min median mean max # direct imports 1 8 13 253 # direct 3rd-party imports 0 3 6 186 # dependency graph depth 1 25 22 37 # per-lib dependency graph depth 0 27 24 34
Table 2: Analysis of direct imports and dependency graph depth in a set of 85 Python IoT applications and in the top 50 third-party libraries imported by these applications. Unless noted otherwise, results of per-application analyses are shown.
Library Frequency RPi.GPIO 47.1% requests 23.5% picamera 21.2% serial 12.9% alsaaudio 11.8%
Table 3: Five most popular Python IoT libraries, and the percentage of the 85 surveyed apps which included them.
Library feature % of top 50 libs
Written in Python 12.0%
Have Native Deps 82.0%
Run external binaries 40.0%
Use ctypes 40.0%
Table 4: Characteristics of the Top 50 Python IoT Libraries. These statistics include the 40% of the top 50 libraries that exhibit multiple of these characteristics.

2.2 Application Analysis

To better understand the impact of third-party libraries and how their use affects the design of today’s IoT applications, we analyzed 85 open-source IoT applications written in Python. We obtained these applications primarily from popular open-source IoT development platforms such as instructables.com and hackster.io; our search focused on three broad categories of applications—visual, audio, and environment sensing—which we believe are representative of today’s most privacy-sensitive IoT applications. Our analysis answers four questions.

1. To what extent are third-party libraries used in IoT applications? All but one of our sampled applications (98.8%) import at least one third-party library, with a mean of about 6 direct third-party imports per application. The maximum number of direct imports we found in a single application was 186 (see Table 3).333It is worth noting that imported libraries are typically not inspected by package managers (e.g., PyPI) for security.

2. How diverse is the third-party library landscape? Given that the Raspberry Pi single-chip computer is a very popular development platform for IoT, our sampled applications heavily target this platform. For instance, two of the top 3 most imported third-party libraries (RPi.GPIO and picamera) are Raspberry Pi-specific Python libraries (see Table 3). Nonetheless, overall we found 331 distinct third-party Python libraries among the 418 total imports in our sampled set of applications.

3. How heavily do IoT applications rely on native code? All of the third-party libraries in our study are Python libraries, i.e., they provide a Python API. However, because the cPython runtime provides seamless integration with native code, gaining insight into the distribution of libraries with native dependencies versus libraries implemented purely in Python would reveal how exposed the Python runtime is to threats in native code. Table 4 shows that among the top 50 third-party libraries in our study—based on the number of times they were included in our surveyed applications—only 12% are implemented purely in Python.

In contrast, 82% of the top 50 libraries include a component written in C/C++, among which we identified 68 distinct native dependencies. The remaining 6% of libraries only load a native shared library via the ctypes Python foreign function interface. Furthermore, about 46% of the sampled applications, and 40% of the top 50 third-party libraries, execute external native binaries (including a Python sub-process).

4. How deep is the dependency graph of the average IoT application? Finally, we analyzed the depth of the dependency graph (i.e., the longest chain of nested libraries) of each application and top-50 library in our sample, and use the depth as an indicator of application or library complexity. Across the 85 sampled applications, the median dependency graph depth is 25 levels, while the median library has a dependency graph 27 levels deep (see Table 3). These numbers highlight the great effort that would be required of developers to identify the sensitive data flows within a single application to prevent all data leaks.

In summary, third-party libraries present a serious threat to IoT security. The single-purpose nature of most IoT devices means that attacks from imported libraries within an application’s process space are more realistic than those across process boundaries, as seen in traditional desktop and server settings. A system is needed to provide isolation and least privilege at the intra-process level to meet this new threat model. Crucially, this system must include defenses against native code to provide complete protection.

3 Threat Model and Security Goals

We seek to provide an in-application privilege separation framework, which allows developers to prevent third-party code included in their IoT applications from leaking data. In particular, Pyronia aims to provide the comprehensive yet efficient protection of two categories of sensitive data, OS resources and in-memory data objects, as well as restrict access to remote network destinations.

3.1 Threat Model

We assume that IoT device providers, who are usually also the application developers, are trusted. As such, we also trust the underlying device hardware, the operating system, and any language runtime executing the IoT application. Yet, imported third-party code poses a risk to developers: library code is rarely inspected or readily accessible (e.g., obfuscated), so bugs or dynamic language features that leak sensitive data may go unnoticed. We do, however, assume that application developers do not intentionally include such vulnerable or malicious third-party code into their products.

While these threats are not IoT-specific, other compute settings (i.e., mobile, desktop, cloud) face more complex security challenges. Mobile devices and desktops (and also IoT hubs) run multiple mutually distrusting applications that need to be isolated. Further, desktops and cloud servers run in multi-user/multi-tenant settings that require additional separation between the different principals. In contrast, the majority of IoT devices are single-purpose running only a single application, with the primary threat stemming from untrusted third-party libraries. Pyronia’s threat model thus applies most directly to IoT, so we focus on applying our approach in this setting.

3.2 Security Properties

Pyronia provides four main security properties.

P1: Least privilege. A third-party library function may only access those OS resources (i.e., files, devices, network) that are necessary to provide the expected functionality. Attempts by a third-party function to access resources that are not relevant to its functionality must be blocked. Pyronia achieves this goal by conservatively enforcing a default-deny policy on a library function’s access to OS resources, and requiring developers to explicitly grant specific library functions access.

P2: Data isolation. Sensitive in-memory data objects may only be accessed within the scope of those third-party library functions which are expected to operate on them. That is, a third-party function cannot read or modify any protected data objects unless it is called by an authorized library function. Pyronia enforces this property by placing sensitive in-memory objects (including the language runtime call stack), into strongly isolated memory domains. Access to these memory domains is only granted by the language runtime upon entry to an authorized third-party function, and is revoked after the function returns.

P3: Verified network destinations. A third-party library function may only transmit data to developer-approved remote network destinations, e.g., cloud servers or other IoT devices. Thus, a third-party library cannot leak legitimately collected data to an untrusted remote server or device. Pyronia prevents such data exfiltration by intercepting all outgoing network connections. Then, before allowing an application to proceed, Pyronia verifies that all involved functions have sufficient privileges to transmit data to the requested network destination.

P4: No confused deputies. All resource access control decisions are made based on the full provenance of the access request. This prevents confused deputy attacks [27], in which an underprivileged library function attempts to gain unauthorized access to a sensitive resource via another function that does have sufficient privilege. To detect such attempts to bypass access control checks, Pyronia leverages the language runtime call stack to check all functions involved in a request for a privileged OS resource.

Non-goals. While Pyronia automates access control and data isolation at the level of in-application components, our design does not seek to provide automated execution isolation of these components (e.g., [59, 12, 11]). We also do not guarantee the correctness of the sensitive data they output. Automated compartmentalization is complementary to our approach, and could be added to Pyronia to allow developers to prevent certain cross-library function calls. Ensuring the correctness of sensitive outputs, on the other hand, could provide additional data leak protection for cases in which a buggy or vulnerable library designed to process sensitive data simply returns the unmodified input, or embeds other sensitive information as part of its output. However, verifying the functionality of untrusted code is beyond the scope of Pyronia, and could be performed as an additional step prior to application deployment.

4 System Design

1:procedure InspectCallstack(, )
2:     
3:     if  nil then return false      
4:     
5:     while  true do
6:         
7:         
8:         if  nil then
9:              continue          
10:               return
Algorithm 1 Call stack inspection

At its core, Pyronia enforces end-to-end intra-process least privilege without partitioning an application into multiple processes (e.g., [11, 12, 51, 67]) or tracking fine-grained data flows (e.g., [21, 23, 68]).

Figure 1: Overview of Pyronia, which enables the enforcement of a developer-supplied access control policy via runtime core and kernel modifications (striped boxes). New features are represented by gray boxes. The arrows show the components involved in an access request to a file such as a certificate.

Developers understand the purpose of imported libraries and can provide high-level descriptions of their expected data access behaviors. Pyronia thus relies on developers to specify all access rules in a single, central policy file. At run time, Pyronia loads this file into an application-specific access control list (ACL) that contains an entry for each developer-specified library function and its associated data access privileges. Pyronia imposes default-deny access control semantics, meaning that a third-party library function may only access those files and devices, in-memory data objects, or remote network destinations to which the developer has granted explicit access.

To enforce this policy, we modify the underlying language runtime core to load developer-supplied access control policies, and add an Access Control module and a Memory Domain manager inside the kernel. Figure 1 provides an overview of the Pyronia system architecture, and shows the main steps involved in a resource access request (see §4.1).

4.1 Function-granular MAC

At first glance, performing library function-granular access control for files and devices in the language runtime may seem like a sufficient solution. The runtime can directly inspect the call stack when a third-party library function uses the language’s high-level interface to access a sensor or file. If the runtime identifies a function not permitted to access the resource, it can block the request and throw an error to notify the system.

However, language runtimes also provide an interface to native code native, such as Java’s JNI or Python’s C API; indeed, our analysis in  §2.2 shows that use of this interface in Python is very common-place. This ability to include native code in otherwise memory-safe languages exposes applications to vulnerabilities in native code: as this code runs outside the purview of the language runtime, this code could bypass any runtime-level file/device access interposition via direct system calls.

Pyronia addresses these issues via an improved system call interposition technique that incorporates function provenance. Many mandatory access control (MAC) systems in deployment use system call interposition (e.g., SELinux [49], AppArmor [8], Windows MIC [39]). Their limitation, however, is that the security policy is only enforced at the process level. We extend this mechanism to the intra-process level by adding runtime call stack inspection (e.g., as in [50, 18, 61]) when a system call is intercepted so that Pyronia can check the full provenance of the system call.

Thus, Pyronia employs these two techniques to provide function-granular MAC and enforce least privilege (P1). As we show in Fig. 1, when the application attempts to access a privileged device or file (e.g., an SSL certificate), the Pyronia Access Control module in the kernel intercepts the associated system call (step 1). This kernel module then sends a request to the language runtime via the trusted stack inspector thread, which pauses the runtime. After collecting the interpreter’s function call stack in its current state, the stack inspector sends the stack back to the kernel (step 2).

The Access Control module maintains the access control list (ACL) for the developer-supplied policy. To determine whether access to the requested file/device should be granted, the kernel inspects the call stack to obtain the full provenance of the system call. Only if all developer-specified functions identified in the call stack have sufficient privileges may the application obtain data from the requested file/device (step 3). That is, to determine whether to grant a function call access to a requested file/device, Pyronia dynamically computes the intersection of the privileges of each function in the call stack using algorithm 1. This algorithm prevents confused deputies (P4), much like in [50, 18, 20].

4.2 Runtime Call Stack Protection

While Pyronia’s MAC system effectively enforces fine-grained least privilege for sensors and files, untrusted native libraries still reside in the runtime’s address space, giving them unfettered access to the call stack’s memory region. A malicious native library may tamper with the runtime call stack in an attempt to bypass Pyronia’s security checks.

This challenge is not unique to Pyronia; indeed, prior work in the mobile space [50, 63] recognized the need to protect the Dalvik call stack against native third-party code in the trusted host app’s address space. To address this issue, these proposals either rely on special hardware support [50] to separate the runtime address space from the native library address space, or they forgo memory protection altogether [63].

Pyronia, in contrast, aims to provide a more generally applicable single-address space memory isolation mechanism, since IoT software runs on a very diverse range of hardware platforms. We overcome this challenge with kernel-level memory domains, strongly isolated memory regions within a process’ address space. Prior work in this space (e.g., [62, 30, 38]) has introduced new primitives for intra-process execution compartments with strong isolation akin to that of process isolation. Our design for Pyronia’s memory domains, on the other hand, focuses on data isolation.

Memory domains in Pyronia must meet two requirements: (1) the size of a domain must be flexible, and (2) the access privileges must be dynamic. The first requirement is important for ensuring that Pyronia can support arbitrarily complex applications that make many nested function calls. The second requirement allows Pyronia to restrict an application’s access to a memory domain at run time based on the currently executing code (e.g., interpreter versus third-party library), while still enabling data sharing between application components that may need access to the protected data at different times.

The Pyronia Memory Domain manager in the kernel (see Fig. 1) maintains a per-process table of domain-protected memory pages with their associated current accessibility. Upon an access to a memory address, the Pyronia kernel performs all regular memory access checks; if the requested address is domain-protected, the Domain manager additionally verifies that the process has sufficient privileges to access the requested memory domain. Any attempt by an application to access unauthorized domain-protected data results in a kernel memory fault, enforcing strong data isolation (P2).

To ensure the integrity of the runtime call stack, Pyronia transparently allocates all call stack data into a memory domain, the interpreter domain. During stack frame creation and deletion events, the Pyronia runtime makes an access privilege adjustment call to the Domain manager, enabling the runtime to allocate or modify interpreter domain data. Beyond these events, the language runtime still provides read access to its call stack to allow untrusted third-party code to make use of shared functions, but prohibits write access to protect this security-critical data.

4.3 Data Object Isolation

Because Pyronia aims to provide comprehensive privilege separation, our design not only controls access to sensitive files/devices, but also ensures in-memory data is protected as it flows through an application. To this end, Pyronia leverages the same memory domains technique used to secure the language runtime call stack to isolate sensitive in-memory data objects.

Pyronia’s data object protection shares some aspects of language-level information flow control (IFC), while addressing this approach’s main limitations. Much like language-level IFC, developers may assign labels to sensitive function inputs and outputs. However, labels in Pyronia do not express the access policy for an associated data object. Instead, Pyronia uses labels as human-readable identifiers for sensitive in-memory data objects. For example, to identify the sensitive output object of the library function imgproc.recognize_face(), the developer could use the label face_image in her policy, and use this label in any rules granting functions access to this same object. The Pyronia runtime then automatically maps each labeled object to a separate data object memory domain at run time, and allocates any data generated by a privileged function in the corresponding data object domain.

Thus, Pyronia’s data object isolation improves upon IFC in two key ways. In terms of policy specification, labels in Pyronia only need to be specified as part of the central data access policy, avoiding source code annotation. Performance-wise, Pyronia has a smaller memory footprint because label-to-domain mappings are static, only needing to store labels in a single place within the entirety of the application’s memory. As such, Pyronia can avoid expensive label propagation between function calls.

4.4 Network Destination Verification

To prevent data leaks end-to-end, Pyronia must ensure that only developer-specified third-party library functions may transmit data to whitelisted network destinations. That is, when an application attempts to export data to a remote network destination, Pyronia’s Access Control module intercepts all outward-facing socket system calls (e.g., bind() and connect()) for all socket types, i.e., TCP, UDP, and raw. Pyronia then treats these system calls like file/devices accesses requesting and inspecting the runtime call stack.

However, network access privileges alone do not immediately allow a third-party function to transmit data. Pyronia also verifies the remote endpoint for the requested socket. Thus, only if the domain name or IP address of the requested remote network destination is included in the access rules for the given third-party function, does Pyronia grant access to the requested socket (P3).

5 Implementation

To demonstrate the practicality of Pyronia, and how it interacts with existing open-source IoT applications, we implemented the Pyronia kernel based on Linux Kernel version 4.8.0+, and the Pyronia runtime as a modified version of Python 2.7.14. We have released all components of our prototype on Github.444https://github.com/pyronia-sys

5.1 Policy Specification

Rule type Format
OS resource <Python module>.<function name> <path to resource> <access privileges>
Data object <Python module>.<function name>:<object label> <access privileges>
Network destination <Python module>.<function name> network <domain name or IP address>
Table 5: Pyronia data access rule specification formats. Supported access privileges are read-only , and read-write .

Developers in Pyronia specify all library function-level data access rules for their application in a single policy file. These rules are specified for the three different types of data that Pyronia protects: OS resources, in-memory data objects, and network destinations. Table 5 details Pyronia’s policy rule specification format. In the case of network access rules specifically, Pyronia allows developers to specify domain name or IP address prefixes, as the specific address of a remote destination in a cloud service may not be known a priori.

Nevertheless, a challenge that arises from having limited knowledge about a library’s implementation is that it may legitimately require access to resources of which the developer is unaware or that may be unexpected. For example, a library function may need access to system fonts, or may write an intermediate result to the file system. Similarly, developers are unlikely to have a good sense of the system libraries or other file system locations a language runtime requires to operate properly. Thus, Pyronia’s default-deny access control semantics alone are too restrictive to maintain the functionality of the application, since they would prevent the runtime from performing necessary background operations.

Thus, our solution is to identify sane defaults that preserve the functionality of the Pyronia runtime and most applications, in the face of such execution “side-effects”. In particular, based on three open-source IoT applications we evaluated (see §6.1), we identified a set of default system files and libraries (e.g., the hosts file, or libdl.so). These system files are required for the Python runtime itself, and hence may not be accessed as part of Python code execution. In other words, a runtime call stack may not exist at the time of access. To allow the interpreter to access these system files at any point, Pyronia supports a special default access rule declaration, which grants application-wide access to a specified resource. While default access rules bypass Pyronia’s function-level access control, they still provide a baseline level of security as Pyronia also applies default-deny access control semantics at the application-level.

Our current Pyronia prototype requires that all default access rules be individually specified in the developer’s policy. However, we facilitate policy specification for developers by providing a policy generation tool that creates a policy template file that already includes all identified Python runtime default system files. A future iteration of Pyronia could maintain a list of the most critical default rules within the runtime or even the kernel, allowing developers to remain agnostic to the runtime defaults.

5.2 Pyronia Kernel

Our Access Control Module extends the AppArmor [8] kernel module version 2.11.0. AppArmor interposes on all system calls enforcing a process-level access policy. To add support for Pyronia’s stack inspection, we introduce a function-level access control list (ACL) to the process-level AppArmor policy data structure. This ACL is populated at application initialization (see §5.3), and contains an entry for each developer-specified library function. After verifying that the process has access to a requested OS resource using vanilla AppArmor, Pyronia performs our stack inspection mechanism based on the function-level ACL as detailed in §4.1. If the requested resource is covered by a default rule, Pyronia grants access without inspecting the call stack.

For Pyronia’s memory domains, we modify the SMV [30] memory module, an intra-process privilege separation proposal which adds support for enforcing per-page thread-level access control policies via thread-local page tables. While the main goal of SMV is to provide intra-process isolation for multi-threaded applications, this system still offers the appropriate abstractions to implement Pyronia memory domains. Our Memory Domain manager leverages the SMV kernel API for maintaining a list of protected 4kB domain pages and their corresponding access rules based on the currently executing thread (in Pyronia, the main and stack inspector threads).

To enable communication between the kernel and the runtime in userspace, Pyronia uses two generic Netlink sockets to allow communication with the Domain manager, and the Access Control module, respectively. Netlink sockets offer two advantages: (1) they allow bi-directional communication between kernelspace and userspace obviating the need to implement additional ioctls() or system calls, and (2) userspace applications can use the same API for Netlink communication as for regular socket-based communication.

5.3 Pyronia Python Runtime

To allow developers to run completely unmodified applications, the Pyronia runtime acts as a drop-in replacement for Python. We integrate our Pyronia userspace library, which provides an API for automatically loading the developer’s access policy, as well as a memory domain management API.

Policy initialization. The runtime core uses our policy parser API to read the developer’s policy file during interpreter initialization. All parsed OS resource and network access rules are sent to the Access Control module initializing the function-level ACL for the application. The in-memory object access rules, as well as the object label-to-domain mappings, are stored as part of the runtime’s Pyronia security context.

Loading the policy at this step before the runtime has loaded any third-party code also has the advantage of preventing an adversary from “front-running” the interpreter by initializing the application’s in-kernel Pyronia ACL before the legitimate developer-supplied policy can be loaded. For this reason, the Pyronia runtime also spawns the stack inspector thread and registers it with the kernel during the initialization phase.

Memory domain allocation. The userspace Pyronia memory domain management API acts as a drop-in replacement for malloc. To allocate the runtime call stack in the interpreter domain, we instrumented the Python stack frame allocator. Because write access to the interpreter domain is disabled by default, the runtime temporarily obtains write access to this domain during frame creation and deletion operations.

When adding support for data object domains in the runtime, one major question arises. How do we allocate sensitive in-memory objects in their corresponding domain without a detailed understanding of a third-party function’s implementation? We address this challenge using a simple rule: whenever the Pyronia runtime is executing within the scope of a privileged function, we conservatively treat all data allocations as data object domain allocations.

As a first step, we instrument the main Python object allocator PyObject_Malloc, and redirect all allocations to the Pyronia allocator whenever the application is within the scope of a privileged function. However, because Python maintains a free list of reclaimed memory blocks for each object type, not every new object allocation actually uses PyObject_Malloc. Thus, to guarantee that sensitive data objects are always allocated in their respective memory domains when the runtime is executing a privileged function, we instrumented the the allocators for Python lists, dictionaries, and classes, since they are mutable. That is, Python does not create a separate copy when these objects are passed as function parameters, allowing them to be modified in-place. While Python provides other mutable types, including custom types defined in native libraries, we believe that our modifications to these three basic albeit commonly used types already provide strong protections. Adding support for object domains to more Python types remains as future work.

To control how in-memory objects are propagated between third-party functions, the Pyronia runtime checks every function the interpreter is about to execute. If the next function to be executed matches an entry in the runtime’s data object ACL, the runtime grants access to the associated object domains before entering the function in question. Upon returning from this function, the runtime revokes access to those data object domains.

Garbage collection. Another feature of Python that poses a challenge is the object reference counting used for Python’s garbage collection. Specifically, we found that Python increments or decrements several objects’ reference counts, including those of call stack frames, for each Python instruction.

To maintain the functionality of the Pyronia runtime without unduly weakening data isolation, we added interpreter and object domain write access adjustment calls around those blocks of the Python runtime code that operate on domain-protected data. Yet, simply granting write access to an entire memory domain is inefficient, especially for the interpreter domain, which may contain hundreds of protected pages, each of whose page table entries would need to be modified (requiring TLB flushes at high rates).

Pyronia’s memory domain implementation provides us with an opportunity to optimize these frequent domain access adjustments. Because memory domains enforce per-page access control, we can limit each adjustment to a single page given the address of the stack frame or in-memory object that the interpreter needs to access. To this enable this optimization, the Pyronia runtime thus keeps a mapping of page addresses to memory domains, and only modifies the access privileges to a specific page.

6 Performance Evaluation

To evaluate the performance of Pyronia, we ran three applications in vanilla Python and Pyronia Python, measuring the execution time and memory overheads. We also took microbenchmarks of the most common system calls used in IoT applications with and without Pyronia enabled to analyze the impact of Pyronia’s call stack inspection-based access control.

Our testing system is an Ubuntu 18.04 LTS virtual machine running our instrumented Pyronia Linux Kernel on a single Intel Core i7-3770 CPU clocked at 3.40 GHz, with 1.95 GB of RAM.

6.1 Tested Applications

In order to understand Pyronia’s performance in real applications, we evaluate three open-source Python IoT applications that represent the main categories of applications we studied: visual, audio, and environmental sensing. Each of these applications communicates with a cloud service for data processing or storage, which required that we register an account to obtain authentication credentials.

To ensure that the results of our evaluation are consistent, we make minor modifications to these applications replacing their real-time data collection (e.g., reading an image from a camera) with a static data source (e.g., an image file), and remove the infinite loop that keeps the applications running continuously when deployed on an IoT device. We emphasize that none of these modifications were necessary to specify a library function-level data access policy, or to add support for Pyronia’s security mechanisms.

(1) twitterPhoto takes an image from a connected camera every 15 minutes, and sends the picture along with a short message as a tweet to a specified Twitter account. Before sending the tweet, the application authenticates itself to Twitter via OAuth. We obtained this application from the set of 85 applications described in §2.2.

(2) alexa aims to provide an open-source Python implementation of an Amazon Echo smart speaker. This application records audio via a microphone while a button is pressed, and sends the recorded audio (along with the required authentication credentials) to the Alexa Voice Service (AVS) [7] for processing. The AVS sends an audio response, if the recorded data is one of the commands recognized by the service, for the alexa application to play back. Otherwise, the AVS responds with an empty message acknowledging the receipt of the recording, in which case the application does not play back any audio. To facilitate our performance tests, we have removed the need for the button press for audio recording, and instead open a static pre-recorded audio file that does not receive an audio response from the AVS. As above, we have also removed the infinite loop in this application. This application is also among the 85 applications we analyze in §2.2.

(3) plant_watering records moisture sensor readings once a minute, and sends them to the Amazon AWS IoT [4] service via MQTT [2], a widely used IoT messaging protocol. MQTT also handles client authentication with the AWS IoT service via TLS. As above, we have disabled the infinite loop in this application, and replace sensor readings with a randomly generated value. We adapted this application from an AWS IoT SDK tutorial [5]; because our Pyronia prototype does not currently support multi-threading, our plant_watering application uses the Python Paho MQTT library [3], which supports single-threaded network communications, in place of the original application’s use of the AWS IoT Python SDK [1], which only supports a multi-threaded MQTT client.

Policy specification. Building comprehensive policies for our tested applications proved to be fairly straight-forward, especially with the policy template generator that pre-populates the policy file with the runtime default rules. Protecting the main required OS resources/network destinations and in-memory objects in twitterPhoto and alexa required only 8 and 14 function-level access rules, respectively. Because reading the random number generator is a default access rule, the plant_watering application, we only needed to specify an additional 7 function-level network access rules. These numbers could be further reduced by adding support for combining the same types of rules for the same library function, thereby avoiding having to declare multiple rules for a function that requires access to more than one resource or sensitive data object.

6.2 Execution Time Overhead

Figure 2: Mean total and module-only execution time in seconds for each application with and without Pyronia enabled.
Figure 3: Mean execution time in microseconds for the Python file open call with varying call stack depths.
Figure 4: Mean latency in microseconds for the Python socket connect call with varying call stack depths.

To analyze the impact of Pyronia on application execution time, we measured the total application execution time, as well as the time spent only executing the main application Python module. The total execution time measurement includes the Python interpreter’s initialization and teardown, which in Pyronia perform additional operations such as access policy parsing, data object domain initialization, and memory domain cleanup at the end. Measuring module-only execution time, on the other hand, gives an estimate of the overhead due to Pyronia’s run-time security checks, i.e., call stack inspection and function sandboxing.

As a baseline for Pyronia’s execution time overhead, we ran a set of measurements with a default access policy that does not restrict access to sensitive system resources to specific library function calls. In this setup, Pyronia still interposes on all system calls, but skips stack inspection entirely. In the full Pyronia experiment with library function-specific access rules, we measure the worst case execution time, in which the entire call stack must be inspected upon a system call.

Figure 2 plots the mean execution times over 25 runs of our tested applications, and a basic hello application, which only prints “Hello, world”, and does not import any third-party code, as a baseline. While Pyronia’s total execution time overhead of 0.1-2.8 seconds (or 7-14x) is significant, these overheads would remain largely imperceptible to end users in real-world deployments because most of the IoT devices only passively collect data with little to no user involvement. Further, these overheads could be counteracted by adjusting the loop interval (i.e., the sleep time) of these applications based on the overhead imposed by Pyronia.

Nonetheless, for an application that requires active user involvement, such as the alexa smart speaker in particular, Pyronia’s total execution time overhead of 1.5 seconds, compared to an original execution time of about 140 ms, is likely to be unacceptable in a real-world deployment. Performance improvements for such interactive IoT devices remain as future work.

Access control overhead. Our analysis of total execution time versus module-only execution time shows that the main module execution dominates the total execution time. To further characterize the performance costs due to Pyronia’s access control checks, we ran microbenchmarks of the file open and socket connect Python standard library calls, which in turn make the corresponding system calls. We choose these two widely used operations as we expect them to be highly impacted by Pyronia.

Figures 3 and 4 show the mean execution time over 25 runs of 10,000 iterations for varying call stack depths for open() and connect(), respectively. For the open() microbenchmarks, we additionally took measurements for varying file sizes ranging from 1KB to 10MB, in 10x increments. However, we find that the file size does not significantly affect the execution time, so Fig. 3 shows the mean open() execution times for all file sizes for each call stack depth.

Our results show that execution time scales linearly with the inspected call stack depth. Further, we find that Pyronia’s system call interposition alone already imposes approximately a 10x slowdown on vanilla Python. Inspecting the call stack increases the execution time further by another 10x. Nonetheless, in absolute terms, the overhead is reasonable: the time to open a file or connect to a socket only reaches 1ms (still a modest number) when the call stack is 50 levels and 100 levels deep, respectively. And (per §2.2 and our benchmarks), the median library call stack depth for the top-50 Python libraries is under 30 levels, and no greater than 14 levels for our tested applications.

Summary. Pyronia’s execution time overhead is not trivial, despite modest performance optimizations (see §5.3). While some additional time is spent during the initialization and cleanup phase of the Python interpreter, the main slowdown occurs during module execution. We attribute this to two factors: (1) Pyronia’s access checks, and (2) memory domain access privilege adjustments to support Python’s garbage collection. Nonetheless, because the majority of IoT applications run on devices only passively collecting and transmitting data, we expect these execution time overheads would go largely unnoticed by end-users. We plan to investigate further performance optimizations, especially for interactive IoT applications, as part of future work.

total # dom pages # interpreter dom pages min median mean mode max
hello 16 16 264 336.0 339.0 336.0 408
twitterPhoto 125 120 240 336.0 360.4 336.0 1080
alexa 92 85 168 336.0 345.1 336.0 816
plant_watering 42 42 240 336.0 336.0 336.0 408
Table 6: Memory domain metadata allocations in bytes under Pyronia for each application. The number of interpreter domain pages includes the domain pages reserved for the stack inspector thread.
peak usage (in MB) overhead
twitterPhoto 52.7 2.2%
alexa 23.5 11.0%
plant_watering 18.8 28.1%
Table 7: Peak memory overhead under Pyronia for each application.

6.3 Memory Overhead

In addition to execution time overhead, Pyronia imposes memory overhead as the language runtime maintains memory domains for the security-critical interpreter state (i.e., call stack and stack inspector), and for data object isolation. To evaluate the impact memory domains alone have on memory consumption, we first measure how much additional memory Pyronia uses to maintain each domain.

For a more accurate estimate of Pyronia’s memory overhead due to memory domains, we focus our measurements on the userspace per-domain page metadata allocations, i.e., the memory required for the Pyronia runtime to maintain each domain page and the associated memory management data structures for individual allocated blocks within a page.555We do not evaluate the actual data allocation overhead per domain page as Pyronia does not change the amount of data the runtime allocates, only where in the runtime’s address space this data is placed. Table 6 shows the mean per-domain page memory consumption in bytes over 25 runs of each tested application.

As expected, the interpreter domain pages dominate the Pyronia per-domain memory consumption with a median of 0.33 kB additional RAM per page. The fact that the mode of the page metadata allocations is the same across all tested applications (Table 6), demonstrates that the majority of domain pages containing stack frames contain a similar number of allocated blocks, regardless of the total number of allocated domain pages. This result is a strong indication that Pyronia’s domain memory consumption scales linearly with the number of allocated domain pages.

Pyronia’s memory domains also have a small impact on the overall memory consumption of our tested applications. Table 7 shows the mean peak memory usage and overhead in MB over 25 runs. Even for the twitterPhoto application with a maximum memory usage of over 50 MB, Pyronia’s memory overhead is only 2.2%, even with the largest number of data object domains.

Summary. Pyronia incurs low memory overhead, even for IoT applications that allocate hundreds of domain pages. For instance, domain metadata only consumes a total of 44 kB for the twitterPhoto application with 125 allocated domain pages. For applications with a greater number of domain pages, our results indicate that the metadata memory overhead would grow linearly. While the increase to application-wide memory usage is the highest for the plant_watering application at 28.1%, a peak memory consumption of under 20 MB is still rather modest. Therefore, Pyronia’s memory overhead would not place an excessive burden on IoT devices with more constrained resource requirements than our testing system.

7 Discussion

Multi-threading. While our current Pyronia design targets single-process, single-threaded IoT applications, as we discovered in §2.2 as well as during our experiments, IoT applications and libraries very commonly spawn sub-processes and multiple threads. These two application design patterns introduce one key security challenge: they break the continuity of the runtime call stack because both sub-processes and threads execute independently of the main thread. In other words, a bug or vulnerability could still cause a confused deputy attack (breaking security property P4).

To address this issue, whenever Pyronia detects such continuity breaks (e.g., by interposing on exec*() or thread_start() calls), Pyronia could automatically inspect the state of the runtime call stack at that time, and save this “parent” call stack to provide the Access Control Module with the full provenance when the child makes a system call. Nonetheless, ensuring that the Access Control Module can properly map “parent” stacks to child stacks, especially in the scenario of nested execs or multi-threading, would be an additional design challenge.

Preventing Pyronia API misuse. Pyronia currently gives the language runtime full authority over security-sensitive operations (e.g., memory domain allocations and privilege adjustments, or call stack generation), and trusts that only the runtime is making such Pyronia API calls. However, a resourceful adversary could use the API to bypass Pyronia’s protections, or otherwise do harm, for instance by freeing domain-protected memory.

To prevent such misuses of the Pyronia API, we we envision two potential approaches. In the style of [18], Pyronia could use cryptographic mechanisms to authenticate the Netlink messages the runtime (including the stack inspector thread) sends to the kernel. Another approach would be use static analysis to identify rogue Pyronia API calls in third-party code prior to launching the runtime. Further investigation is required to determine which method is more suitable.

Improving policy specification. Our very basic policy specification format and policy template generation tool aim to reduce the burden of defining fine-grained access policies with sane defaults. Nevertheless, Pyronia currently expects path-based access rules for OS resources in particular; having to determine the paths to the file system interface of resources such as sensors, likely still places an undue burden on developers. Designing a more developer-friendly and rigorous policy specification model is beyond the scope of Pyronia. One interesting approach may be to support simple mobile-style resource access capabilities (e.g., READ_CAM), which the Pyronia could then automatically map to the corresponding low-level system resources.

While we believe that the risks of completely automated policy generation (e.g., as in [43, 12]) outweigh the benefits, we see an opportunity for the library developer community to ease the policy specification process further. For instance, library developers could contribute resource “manifests”, i.e., a list of required files and network destinations, and package these manifests along with their source code or binaries. With support from Pyronia, application developers could then automatically load these manifests as part of their application-specific access policy, allowing application developers to focus on their high-level policy.

8 Related Work

Information Flow Control. Decentralized information flow control (IFC) systems explicitly label data and track how they flow through the system, such as an OS [19, 70, 36, 69], or a language runtime [17, 52, 23, 40, 68]. Principals (e.g., processes or functions) raise their labels when reading labeled data and invoke declassifiers when outputing sensitive information. Usually, restrictions are applied at write time (e.g., filesystem write or network transmission) while no restrictions are imposed at read time. For example, Asbestos [19] allows any process to create new labels and raise the security clearance of other processes to facilitate reading of secret information. Pyronia’s goal differs from that of IFC systems. Pyronia focuses on preventing security violations at the time of access, rather than only restricting where data may flow after writes.

Additionally, IFC systems often face the problem of taint explosion and incur significant memory and computation overhead. Pyronia, on the other hand, addresses these shortcomings by protecting sensitive in-memory data objects in memory domains, which provide fine-grained access control semantics to specific memory regions while avoiding the resource- intensive propagation of labels throughout the system.

Memory Isolation. In addition to memory domains, a wide variety of alternative intra-process memory isolation techniques have been proposed. SFI [60], for instance, partitions a process’ address space into fine-grained fault domains for different code blocks and data by modifying the program’s binary. Mondriaan memory protection (MMP) [64, 65] is a memory isolation system that enforces word-level access policies in the kernel.

Recent CPUs have introduced a number of hardware-assisted memory protection techniques that enable efficient in-application memory isolation. For example, shreds [16] leverages ARM memory domains [9] to create sub-thread-level isolated execution units. Intel SGX [32] allows developers to partition an application into a trusted and untrusted component, where the trusted component resides inside a cryptographically protected memory region within the application’s address space. Despite their efficiency and ability to reduce the TCB size, these techniques require specialized hardware that is unavailable on most IoT devices. Pyronia, in contrast, aims to be more generally applicable.

Android-specific privilege separation. Several studies [13, 25, 53] showed how Android libraries, such as in-app advertising, collect private information by abusing permissions granted to their host app. Much work has been done to mitigate this privacy threat. Most prior approaches [42, 51, 54, 35, 29, 72, 31] separate third-party libraries by running them in isolated processes with different (usually lower) privileges from the host app. However, such process-based isolation suffers from high performance overheads imposed by additional IPC. In contrast, Pyronia does not rely on process-based isolation. We leverage stack inspection and memory domains to enforce least privilege and isolation within a process, avoiding additional IPC. Furthermore, our approach of intra-process isolation fits better with existing hardware in the IoT ecosystem. Most IoT devices lack the hardware capability (e.g., a MMU) to support traditional process-based isolation. Instead, they often provide memory protection units (MPU) that allow simple access control configurations for regions of memory addresses. Pyronia’s memory domain mechanism can be implemented on devices with only MPUs where process-based isolation is fundamentally infeasible.

The FlexDroid [50] project is closest to our approach. FlexDroid also provides privilege separation by leveraing stack inspection and memory domain. However, FlexDroid’s access control is built into Android’s Permission Monitor service and its memory separation mechanism relies on special ARM architecture support.

IoT-specific Access Control. A number of recent works in the IoT space propose novel access control systems to protect sensitive user data against potentially vulnerable or malicious IoT applications. However, the majority of these systems focuses on enabling developers and end-users to define and enforce more suitable data access policies based on external factors such as usage context or risk  [34, 48, 28, 45, 58]. Pyronia, in contrast, focuses on allowing developers to contain third-party code decoupling end-user application usage policy enforcement from a developer’s implementation policy.

The FACT system [37] provides functionality-granular access control by allowing developers to execute different IoT device functions in separate Linux containers, but does not protect in-memory data shared between different functions as Pyronia does. FlowFence [21] shares the same goals as Pyronia providing a framework for in-application privilege separation and data isolation. However, unlike our approach, FlowFence still relies on process isolation and does not support unmodified applications.

Python Isolation. Unfortunately, in the case of Python specifically, little has been done to restrict untrusted third-party modules.666According to the official Wiki on Sandboxed Python [44], all of the proposals for incorporating sandboxing capabilities have been rejected; instead a variety of ad-hoc mechanisms, some of which we discuss above, are recommended. A small number of projects has focused on securing Python against vulnerabilities and untrusted code via techniques such as information flow control [68], restricting Python’s interfaces to privileged operations and introspection [15, 73], or process-based isolation [57]. However, unlike Pyronia, these works provide only coarse-grained protection remaining vulnerable to malicious libraries, do not control access to system resources, or rely on heavyweight process-level isolation.

9 Conclusion

We have presented Pyronia, an in-application privilege separation system for language runtimes capable of integration into IoT applications. Pyronia protects sensitive data against untrusted third-party libraries by leveraging three access control techniques —system call interposition, runtime call stack inspection, and memory domains. This design avoids the need for expensive process isolation or dynamic data flow tracking to enforce least privilege and provide strong data isolation at the granularity of individual library functions.

Further, unlike prior approaches, Pyronia runs unmodified applications, and does not require unintuitive or cumbersome policy specification. We implement a Pyronia kernel and Pyronia Python runtime. Our evaluation of three open-source Python IoT applications demonstrates that Pyronia’s performance overheads are acceptable for the most common types of IoT applications.

References

  • [1] AWS IoT Device SDK for Python. https://github.com/aws/aws-iot-device-sdk-python.
  • [2] MQTT.org. Retrieved Feb. 9, 2019, from https://mqtt.org.
  • [3] paho-mqtt. Python Package Index (PyPI), https://pypi.org/project/paho-mqtt/.
  • [4] Amazon Web Services, Inc. AWS IoT. Retrieved Feb. 9, 2019, from https://aws.amazon.com/iot/.
  • [5] Amazon Web Services, Inc. AWS IoT Plant Watering Sample. Retrieved Feb. 9, 2019, from https://docs.aws.amazon.com/iot/latest/developerguide/iot-plant-watering.html.
  • [6] Amazon Web Services, Inc. Security and identity for AWS IoT. AWS IoT Devloper Guide.
  • [7] Amazon.com, Inc. Alexa Voice Service. Retrieved Feb. 9, 2019, from https://developer.amazon.com/alexa-voice-service.
  • [8] AppArmor maintainers. AppArmor security project wiki. Accessed Dec. 30, 2018, https://gitlab.com/apparmor/apparmor/wikis/home/.
  • [9] ARM Limited. Domains. Retrieved Feb. 12, 2019, from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211k/Babjdffh.html.
  • [10] Benjamin Cabé. IoT Developer Survey Results 2018. https://www.slideshare.net/kartben/iot-developer-survey-2018, 2018. Accessed 21 Dec 2018.
  • [11] A. Bittau, P. Marchenko, M. Handley, and B. Karp. Wedge: Splitting Applications into Reduced-Privilege Compartments. In NSDI, 2008.
  • [12] A. Blankstein and M. J. Freedman. Automating Isolation and Least Privilege in Web Services. In IEEE Symposium on Security and Privacy, 2014.
  • [13] T. Book, A. Pridgen, and D. S. Wallach. Longitudinal Analysis of Android Ad Library Permissions. arXiv e-prints, page arXiv:1303.0857, Mar. 2013.
  • [14] J. Bort. For The First Time, Hackers Have Used A Refrigerator To Attack Businesses. Business Insider, Jan. 2014.
  • [15] J. Cappos, A. Dadgar, J. Rasley, J. Samuel, I. Beschastnikh, C. Barsan, A. Krishnamurthy, and T. Anderson. Retaining Sandbox Containment Despite Bugs in Privileged Memory-safe Code. In 17th ACM Conference on Computer and Communications Security (CCS), 2010.
  • [16] Y. Chen, S. Reymondjohnson, Z. Sun, and L. Lu. Shreds: Fine-Grained Execution Units with Private Memory. In IEEE Symposium on Security and Privacy (S&P), 2016.
  • [17] W. Cheng, D. R. K. Ports, D. Schultz, V. Popic, A. Blankstein, J. Cowling, D. Curtis, L. Shrira, and B. Liskov. Abstractions for usable information flow control in aeolus. In ATC, 2012.
  • [18] M. Dietz, S. Shekhar, Y. Pisetsky, A. Shu, and D. S. Wallach. Quire: Lightweight Provenance for Smart Phone Operating Systems. In USENIX Security Symposium, 2011.
  • [19] P. Efstathopoulos, M. Krohn, S. VanDeBogart, C. Frey, D. Ziegler, E. Kohler, D. Mazières, F. Kaashoek, and R. Morris. Labels and event processes in the asbestos operating system. In SOSP, 2005.
  • [20] A. P. Felt, H. J. Wang, A. Moshchuk, S. Hanna, and E. Chin. Permission re-delegation: Attacks and defenses. In USENIX Security Symposium, 2011.
  • [21] E. Fernandes, J. Paupore, A. Rahmati, D. Simionato, M. Conti, and A. Prakash. FlowFence: Practical Data Protection for Emerging IoT Application Frameworks. In USENIX Security Symposium. USENIX Association, 2016.
  • [22] S. Gallagher. How one rent-a-botnet army of cameras, DVRs caused Internet chaos. Ars Technica, Oct. 2016.
  • [23] D. B. Giffin, A. Levy, D. Stefan, A. Russo, D. Terei, D. Mazières, and J. C. Mitchell. Hails: Protecting data privacy in untrusted web applications. In OSDI, 2012.
  • [24] D. Goodin.

    9 baby monitors wide open to hacks that expose users’ most private moments.

    Ars Technica, Sep. 2015.
  • [25] M. C. Grace, W. Zhou, X. Jiang, and A.-R. Sadeghi. Unsafe exposure analysis of mobile in-app advertisements. In Proc. ACM Conference on Security and Privacy in Wireless and Mobile Networks, 2012.
  • [26] A. Greenberg. Hackers Remotely Kill a Jeep on the Highway – With Me in It. Wired, Jul. 2015.
  • [27] N. Hardy. The confused deputy: (or why capabilities might have been invented). ACM Operating Systems Review, 22(4), 1988.
  • [28] W. He, M. Golla, R. Padhi, J. Ofek, M. Dürmuth, E. Fernandes, and B. Ur. Rethinking access control and authentication for the home internet of things (iot). In Proc. USENIX Security Symposium, 2018.
  • [29] Y.-Y. Hong, Y.-P. Wang, and J. Yin. NativeProtector: Protecting android applications by isolating and intercepting third-party native libraries. In ICT Systems Security and Privacy Protection, 2016.
  • [30] T. C.-H. Hsu, K. Hoffman, P. Eugster, and M. Payer. Enforcing Least Privilege Memory Views for Multithreaded Applications. In CCS, 2016.
  • [31] J. Huang, O. Schranz, S. Bugiel, and M. Backes. The ART of App Compartmentalization: Compiler-based Library Privilege Separation on Stock Android. In CCS, 2017.
  • [32] Intel Corp. Intel Software Guard Extensions (Intel SGX). Retrieved Feb. 12, 2019, from https://software.intel.com/en-us/sgx.
  • [33] Intel Corporation. Intel IoT platform reference architecture white paper.
  • [34] Y. J. Jia, Q. A. Chen, S. Wang, A. Rahmati, E. Fernandes, Z. M. Mao, and A. Prakash. Contexlot: Towards providing contextual integrity to appified iot platforms. In NDSS. Internet Society, 2017.
  • [35] H. Kawabata, T. Isohara, K. Takemori, A. Kubota, J. Kani, H. Agematsu, and M. Nishigaki. Sanadbox: Sandboxing third party advertising libraries in a mobile application. In International Conference on Communications (ICC), 2013.
  • [36] M. Krohn, A. Yip, M. Brodsky, N. Cliffer, M. F. Kaashoek, E. Kohler, and R. Morris. Information flow control for standard os abstractions. In SOSP, 2007.
  • [37] S. Lee, J. Choi, J. Kim, B. Cho, S. Lee, H. Kim, and J. Kim. FACT: Functionality-centric Access Control System for IoT Programming Frameworks. In Proc. ACM Symposium on Access Control Models and Technologies, 2017.
  • [38] J. Litton, A. Vahldiek-Oberwagner, E. Elnikety, D. Garg, B. Bhattacharjee, and P. Druschel. Light-Weight Contexts: An OS Abstraction for Safety and Performance. In OSDI, 2016.
  • [39] Microsoft Windows Dev Center. Mandatory Integrity Control. Accessed Feb. 11, 2019, https://docs.microsoft.com/en-us/windows/desktop/SecAuthZ/mandatory-integrity-control.
  • [40] A. C. Myers and B. Liskov. Protecting privacy using the decentralized label model. ACM Transactions on Software Engineering and Methodology, 9(4), 2000.
  • [41] Nest Labs. Keeping data safe at Nest.
  • [42] P. Pearce, A. P. Felt, G. Nunez, and D. Wagner. AdDroid: Privilege separation for applications and advertisers in android. In ACM Symposium on Information, Computer and Communications Security (ASIACCS), 2012.
  • [43] N. Provos. Improving host security with system call policies. In USENIX Security Symposium, 2003.
  • [44] Python Software Foundation. Sandboxed Python. Retrieved Feb. 7, 2018, from https://wiki.python.org/moin/SandboxedPython.
  • [45] A. Rahmati, E. Fernandes, K. Eykholt, and A. Prakash. Tyche: A Risk-Based Permission Model for Smart Homes. In IEEE Cybersecurity Development (SecDev), 2018.
  • [46] J. H. Saltzer and M. D. Schroeder. The protection of information in computer systems. Proceedings of the IEEE, 63(9), 1975.
  • [47] SAMSUNG. Device Protection and Trusted Code Execution.
  • [48] R. Schuster, V. Shmatikov, and E. Tromer. Situational access control in the internet of things. In Proc. ACM SIGSAC Conference on Computer and Communications Security, 2018.
  • [49] SELinux maintainers. SELinux Project wiki. Accessed Feb. 11, 2019, https://selinuxproject.org/page/Main_Page.
  • [50] J. Seo, D. Kim, D. Cho, T. Kim, I. Shin, and X. Jiang. FlexDroid: Enforcing In-App Privilege Separation in Android. In NDSS, Feb. 2016.
  • [51] S. Shekhar, M. Dietz, and D. S. Wallach. AdSplit: Separating smartphone advertising from applications. In USENIX Security Symposium. USENIX Association, 2012.
  • [52] D. Stefan, E. Z. Yang, P. Marchenko, A. Russo, D. Herman, B. Karp, and D. Mazières. Protecting users by confining javascript with cowl. In OSDI, 2014.
  • [53] R. Stevens, C. Gibler, J. Crussell, J. Erickson, and H. Chen. Investigating user privacy in android ad libraries. 02 2019.
  • [54] M. Sun and G. Tan. NativeGuard: Protecting android applications from third-party native libraries. In Security and Privacy in Wireless and Mobile Networks (WiSec), 2014.
  • [55] Symantec Security Response. IoT devices being increasingly used for DDoS attacks. Symantec Official Blog, Sep. 2016.
  • [56] The MITRE Corporation. Common Vulnerabilities and Exposures (CVE) List. Retrieved Sep. 25, 2017, from https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=python.
  • [57] The PyPy Project. PyPy’s sandboxing features. Retrieved Feb. 7, 2018, from http://pypy.readthedocs.io/en/latest/sandbox.html.
  • [58] Y. Tian, N. Zhang, Y.-H. Lin, X. Wang, B. Ur, X. Guo, and P. Tague. SmartAuth: User-centered Authorization for the Internet of Things. In Proc. USENIX Security Symposium, 2017.
  • [59] N. Vasilakis, B. Karel, N. Roessler, N. Dautenhahn, A. Dehon, and J. Smith. BreakApp: Automated, Flexible Application Compartmentalization. In NDSS, 2018.
  • [60] R. Wahbe, S. Lucco, T. E. Anderson, and S. L. Graham. Efficient Software-based Fault Isolation. In Proc. ACM Symposium on Operating Systems Principles, 1993.
  • [61] D. S. Wallach and E. W. Felten. Understanding Java Stack Inspection. In IEEE S&P, 1998.
  • [62] J. Wang, X. Xiong, and P. Liu. Between Mutual Trust and Mutual Distrust: Practical Fine-grained Privilege Separation in Multithreaded Applications. In USENIX ATC), 2015.
  • [63] Y. Wang, S. Hariharan, C. Zhao, J. Liu, and W. Du. Compac: Enforce component-level access control in android. In Conference on Data and Application Security and Privacy (CODASPY), 2014.
  • [64] E. Witchel, J. Cates, and K. Asanović. Mondrian Memory Protection. In Proc. International Conference on Architectural Support for Programming Languages and Operating Systems, 2002.
  • [65] E. Witchel, J. Rhee, and K. Asanović. Mondrix: Memory Isolation for Linux Using Mondriaan Memory Protection. In Proc. ACM Symposium on Operating Systems Principles, 2005.
  • [66] Y. Wu, S. Sathyanarayan, R. H. Yap, and Z. Liang. Codejail: Application-transparent Isolation of Libraries with Tight Program Interactions. In ESORICS, 2012.
  • [67] Y. Xu, A. M. Dunn, O. S. Hofmann, M. Z. Lee, S. A. Mehdi, and E. Witchel. Application-Defined Decentralized Access Control. In USENIX ATC, 2014.
  • [68] A. Yip, X. W. andNickolai Zeldovich, and M. F. Kaashoek. Improving application security with data flow assertions. In SOSP, 2009.
  • [69] A. R. Yumerefendi, B. Mickle, and L. P. Cox. Tightlip: Keeping applications from spilling the beans. In NSDI, 2007.
  • [70] N. Zeldovich, S. Boyd-Wickizer, E. Kohler, and D. Mazières. Making information flow explicit in histar. In OSDI, 2006.
  • [71] K. Zetter. It’s Insanely Easy to Hack Hospital Equipment. Wired, Apr. 2014.
  • [72] X. Zhang, A. Ahlawat, and W. Du. AFrame: Isolating advertisements from mobile applications in android. In 29th Annual Computer Security Applications Conference (ACSAC), 2013.
  • [73] Zope Foundation. Welcome to RestrictedPython’s documentation! Retrieved Feb. 7, 2018, from http://restrictedpython.readthedocs.io/en/latest/.