As real-time cyber-physical systems (CPS) become increasingly prevalent and interconnected, ensuring their security becomes essential. Yet, integrating runtime security mechanisms into real-time systems is challenging due to non-uniform performance overheads that may differ significantly under average-and worst-case behaviors. This paper systematically examines how commonly used runtime memory-safety defenses affect worst-case task performance in real-world CPS applications. The experiments reveal that security mechanisms vary markedly in their computational impact, providing practical guidance for their deployment. They also highlight the opportunity to selectively combine defenses to enhance overall protection. The paper further presents an optimization framework, QUASARRT, and a case study on ArduPilot demonstrating how system designers can apply these findings to maximize their defense coverage while maintaining real-time schedulability. Results indicate that QUASARRT is effective at finding the most secure feasible task configurations, even under complex schedulability analysis.
The recently mandated software bill of materials (SBOM) is intended to help mitigate software supply-chain risk. We discuss extensions that would enable an SBOM to serve as a basis for making trust assessments thus also serving as a proactive defense.
Software security defenses are routinely broken by the persistence of both security researchers and attackers. Hardware solutions based on tagging are emerging as a promising technique that provides strong security guarantees (e.g., memory safety) while incurring minimal runtime overheads and maintaining compatibility with existing codebases. Such schemes extend every word in memory with a tag and enforce security policies across them. This paper provides a survey of existing work on tagged architectures and describe the types of attacks such architectures aim to prevent as well as the guarantees they provide. It highlights the main distinguishing factors among tagged architectures and presents the diversity of designs and implementations that have been proposed. The survey reveals several real-world challenges have been neglected relating to both security and practical deployment. The challenges relate to the provisioning and enforcement phases of tagged architectures, and various overheads they incur. This work identifies these challenges as open research problems and provides suggestions for improving their security and practicality.
Reverse engineering unknown binaries is a difficult, resource intensive process due to information loss and optimizations performed by compilers that introduce significant binary diversity.Existing binary similarity approaches do not scale or are inaccurate.In this paper, we introduce IOVec Function Identification (IOVFI), which assesses similarity based on program state transformations, which compilers largely guarantee even across compilation environments and architectures.IOVFI executes functions with initial predetermined program states, measures the resulting program state changes, and uses the sets of input and output state vectors as unique semantic fingerprints.Since IOVFI relies on state vectors, and not code measurements, it withstands broad changes in compilers and optimizations used to generate a binary.Evaluating our IOVFI implementation as a semantic function identifier for coreutils-8.32,we achieve a high .773average F-Score, indicating high precision and recall.When identifying functions generated from differing compilation environments, IOVFI achieves a 100% accuracy improvement over BinDiff 6, outperforms asm2vec in cross-compilation environment accuracy, and, when compared to dynamic frameworks, BLEX and IMF-SIM, IOVFI is 25%-53% more accurate.
Commodity operating system kernels remain monolithic for practical and historical reasons.All kernel code shares a single address space, executes with elevated processor privileges, and has largely unhindered access to all data, including data irrelevant to the completion of a specific task.Applying the principle of least privilege, which limits available resources only to those needed to perform a particular task, to compartmentalize the kernel would realize major security gains, similar to microkernels yet without the major redesign effort.Here, we introduce a compartmentalization design, called a Hardware-Assisted Kernel Compartmentalization (HAKC), that approximates least privilege separation, while minimizing both developer effort and performance overhead.HAKC divides code and data into separate partitions, and specifies an access policy for each partition.Data is owned by a single partition, and a partition's access-control policy is enforced at runtime, preventing unauthorized data access.When a partition needs to transfer control flow to outside itself, data ownership is transferred to the target, and transferred back upon return.The HAKC design allows for isolating code and data from the rest of the kernel, without utilizing any additional Trusted Computing Base while compartmentalized code is executing.Instead, HAKC relies on hardware for enforcement.Loadable kernel modules (LKMs), which dynamically load kernel code and data providing specialized functionality, are the single largest part of the Linux source base.Unfortunately, their collective size and complexity makes LKMs the cause of the majority of CVEs issued for the Linux kernel.The combination of a large attack surface in kernel modules, and the monolithic design of the Linux kernel, make LKMs ideal candidates for compartmentalization.To demonstrate the effectiveness of our approach, we implement HAKC in Linux v5.10 using extensions to the Arm v8.5-A ISA, and compartmentalize the ipv6.koLKM, which consists of over 55k LOC.The average overhead measured in Apachebench tests was just 1.6%-24%.Additionally, we compartmentalize the nf_tables.kopacket filtering LKM, and measure the combined impact of using both LKMs.We find a reasonable linear growth in overhead when both compartmentalized LKMs are used.Finally, we measure no significant difference in performance when using the compartmentalized ipv6.koLKM over the unmodified LKM during real-world web browsing experiments on the Alexa Top 50 websites.
Memory corruption attacks against unsafe programming languages like C/C++ have been a major threat to computer systems for multiple decades.Various sanitizers and runtime exploit mitigation techniques have been shown to only provide partial protection at best.Recently developed 'safe' programming languages such as Rust and Go hold the promise to change this paradigm by preventing memory corruption bugs using a strong type system and proper compile-time and runtime checks.Gradual deployment of these languages has been touted as a way of improving the security of existing applications before entire applications can be developed in safe languages.This is notable in popular applications such as Firefox and Tor.In this paper, we systematically analyze the security of multi-language applications.We show that because language safety checks in safe languages and exploit mitigation techniques applied to unsafe languages (e.g., Control-Flow Integrity) break different stages of an exploit to prevent control hijacking attacks, an attacker can carefully maneuver between the languages to mount a successful attack.In essence, we illustrate that the incompatible set of assumptions made in various languages enables attacks that are not possible in each language alone.We study different variants of these attacks and analyze Firefox to illustrate the feasibility and extent of this problem.Our findings show that gradual deployment of safe programming languages, if not done with extreme care, can indeed be detrimental to security.
Modern software (both programs and libraries) provides large amounts of functionality, vastly exceeding what is needed for a single given task. This additional functionality results in an increased attack surface: first, an attacker can use bugs in the unnecessary functionality to compromise the software, and second, defenses such as control-flow integrity (CFI) rely on conservative analyses that gradually lose precision with growing code size. Removing unnecessary functionality is challenging as the debloating mechanism must remove as much code as possible, while keeping code required for the program to function. Unfortunately, most software does not come with a formal description of the functionality that it provides, or even a mapping between functionality and code. We therefore require a mechanism that-given a set of representable inputs and configuration parameters-automatically infers the underlying functionality, and discovers all reachable code corresponding to this functionality. We propose Ancile, a code specialization technique that leverages fuzzing (based on user provided seeds) to discover the code necessary to perform the functionality required by the user. From this, we remove all unnecessary code and tailor indirect control-flow transfers to the minimum necessary for each location, vastly reducing the attack surface. We evaluate Ancile using real-world software known to have a large attack surface, including image libraries and network daemons like nginx. For example, our evaluation shows that Ancile can remove up to 93.66% of indirect call transfer targets and up to 78% of functions in libtiff's tiffcrop utility, while still maintaining its original functionality.
Rust is a programming language that simultaneously offers high performance and strong security guarantees. Safe Rust (i.e., Rust code that does not use the unsafe keyword) is memory and type safe. However, these guarantees are violated when safe Rust interacts with unsafe code, most notably code written in other programming languages, including in legacy C/C++ applications that are incrementally deploying Rust. This is a significant problem as major applications such as Firefox, Chrome, AWS, Windows, and Linux have either deployed Rust or are exploring doing so. It is important to emphasize that unsafe code is not only unsafe itself, but also it breaks the safety guarantees of ‘safe’ Rust; e.g., a dangling pointer in a linked C/C++ library can access and overwrite memory allocated to Rust even when the Rust code is fully safe. This paper presents Galeed, a technique to keep safe Rust safe from interference from unsafe code. Galeed has two components: a runtime defense to prevent unintended interactions between safe Rust and unsafe code and a sanitizer to secure intended interactions. The runtime component works by isolating Rust’s heap from any external access and is enforced using Intel Memory Protection Key (MPK) technology. The sanitizer uses a smart data structure that we call pseudo-pointer along with automated code transformation to avoid passing raw pointers across safe/unsafe boundaries during intended interactions (e.g., when Rust and C++ code exchange data). We implement and evaluate the effectiveness and performance of Galeed via micro- and macro-benchmarking, and use it to secure a widely used component of Firefox.
Software transactional memory (STM) is a synchronization paradigm originally proposed for throughput-oriented computing to facilitate producing performant concurrent code that is free of synchronization bugs. With STM, programmers merely annotate code sections requiring synchronization; the underlying STM framework automatically resolves how synchronization is done. Today, the programming issues that motivated STM are becoming a concern in embedded computing, where ever more sophisticated systems are being produced that require highly parallel implementations. These implementations are often produced by engineers and control experts who may not be well versed in concurrency-related issues. In this context, a real-time STM framework would be useful in ensuring that the synchronization aspects of a system pass real-time certification. However, all prior STM approaches fundamentally rely on retries to resolve conflicts, and such retries can yield high worst-case synchronization costs compared to lock-based approaches. This paper presents a new STM class called Retry-Free Real-Time STM (R 2 STM), which is designed for worst-case real-time performance. The benefit of a retry-free approach for use in a real-time system is demonstrated by a schedulability study, in which it improved overall schedulability across all considered task systems by an average of 95.3% over a retry-based approach. This paper also presents TORTIS, the first R 2 STM implementation for real-time systems. Throughput-oriented benchmarks are presented to highlight the tradeoffs between throughput and schedulability for TORTIS.
New software security threats are constantly arising, including new classes of attacks such as the recent spate of micro-architectural vulnerabilities, from side-channels and speculative execution to attacks like Rowhammer that alter the physical state of memory. At the same time, new defensive technologies are proposed and adopted, including advancements in programming languages and novel hardware architectures with a focus on security. Moving target defenses were developed to provide performant, incremental security to programs written in unsafe languages running on processors designed solely for performance. Here we examine the challenges and opportunities for moving target defenses in the evolving security landscape, and in new applications domains such as cloud computing and real-time systems.
Hardware fault injection, or glitching, attacks can compromise the security of devices even when no software vulnerabilities exist. Attempts to analyze the hardware effects of glitching are subject to the Heisenberg effect and there is typically a disconnect between what people “think” is possible and what is actually possible with respect to these attacks. In this work, we attempt to provide some clarity to the impacts of attacks and defenses for control-flow modification through glitching. First, we introduce a glitching emulation framework, which provides a scalable playground to test the effects of bit flips on specific instruction set architectures (ISAs) (i.e., the fault tolerance of the instruction encoding). Next, we examine real glitching experiments using the ChipWhisperer, a popular microcontroller using open-source glitching hardware. These real-world experiments provide novel insights into how glitching attacks are realized and might be defended against in practice. Finally, we present GLITCHRESISTOR, an open-source, software-based glitching defense tool that can automatically insert glitching defenses into any existing source code, in an architecture-independent way. We evaluated GLITCHRESISTOR, which integrates numerous software-only defenses against powerful and real-world glitching attacks. Our findings indicate that software-only defenses can be implemented with acceptable run-time and size overheads, while completely mitigating some single-glitch attacks, minimizing the likelihood of a successful multi-glitch attack (i.e., a success rate of 0.000306%), and detecting failed glitching attempts at a high rate (between 79.2% and 100%).
Moving-target defenses (MTDs) have been widely studied for common general-purpose and enterprise-computing applications. Indeed, such work has produced highly effective, low-overhead defenses that are now commonly deployed in many systems today. One application space that has seen comparatively little focus is that of safety- and mission-critical systems, which are often real-time systems (RTS) with temporal requirements. Furthermore, such systems are increasingly being targeted by attackers, such as in industrial control systems (ICS), including power grids. The strict timing requirements of these systems presents a different design objective than is common in general-purpose applications -- systems should be designed around the worst-case performance, rather than the average case. Perhaps in part due to these alternative design considerations, many real-time systems have not benefited from much of the work on software security that common general-purpose and enterprise applications have, despite the ubiquity of real-time systems that actively control so many applications we as a society have come to rely on, from power generation and distribution, to automotive and avionic applications, and many others. This paper explores the application of moving-target defenses in the context of real-time systems. In particular, the worst-case performance of several address-space randomization defenses are evaluated to study the implications of such designs in real-time applications. These results suggest that current moving-target defenses, while performant in the average case, can exhibit significant tail latencies, which can be problematic in real-time applications, especially if such overheads are not considered in the design and analysis of the system. These results inform future research directions for moving-target defenses in real-time applications.
Fuzzing is one of the most popular and effective techniques for finding software bugs. To detect triggered bugs, fuzzers leverage a variety of sanitizers in practice. Unfortunately, sanitizers target long running experiments--e.g., developer test suites--not fuzzing, where execution time is highly variable ranging from extremely short to long. Design decisions made for developer test suites introduce high overhead on short lived fuzzing executions, decreasing the fuzzer's throughput and thereby reducing effectiveness. The root cause of this sanitization overhead is the heavyweight metadata structure that is optimized for frequent metadata operations over long executions. To address this, we design new metadata structures for sanitizers, and propose FuZZan to automatically select the optimal metadata structure without any user configuration. Our new metadata structures have the same bug detection capabilities as the ones they replace. We implement and apply these ideas to Address Sanitizer (ASan), which is the most popular sanitizer. Our evaluation shows that on the Google fuzzer test suite, FuZZan improves fuzzing throughput over ASan by 48% starting with Google's provided seeds (52%when starting with empty seeds on the same applications). Due to this improved throughput, FuZZan discovers 13% more unique paths given the same 24 hours and finds bugs 42% faster. Furthermore, FuZZan catches all bugs ASan does; i.e., we have not traded precision for performance. Our findings show that sanitizer performance overhead is avoidable when metadata structures are designed for fuzzing, and that the performance difference will have a meaningful difference in squashing software bugs.
Analyzing the security of closed source binaries is currently impractical for end-users, or even developers who rely on third-party libraries. Such analysis relies on automatic vulnerability discovery techniques, most notably fuzzing with sanitizers enabled. The current state of the art for applying fuzzing or sanitization to binaries is dynamic binary translation, which has prohibitive performance overhead. The alternate technique, static binary rewriting, cannot fully recover symbolization information and hence has difficulty modifying binaries to track code coverage for fuzzing or to add security checks for sanitizers.The ideal solution for binary security analysis would be a static rewriter that can intelligently add the required instrumentation as if it were inserted at compile time. Such instrumentation requires an analysis to statically disambiguate between references and scalars, a problem known to be undecidable in the general case. We show that recovering this information is possible in practice for the most common class of software and libraries: 64-bit, position independent code. Based on this observation, we develop RetroWrite, a binary-rewriting instrumentation to support American Fuzzy Lop (AFL) and Address Sanitizer (ASan), and show that it can achieve compiler-level performance while retaining precision. Binaries rewritten for coverage-guided fuzzing using RetroWrite are identical in performance to compiler-instrumented binaries and outperform the default QEMU-based instrumentation by 4.5x while triggering more bugs. Our implementation of binary-only Address Sanitizer is 3x faster than Valgrind’s memcheck, the state-of-the-art binary-only memory checker, and detects 80% more bugs in our evaluation.
Today's computer systems trace their roots to an era of trusted users and highly constrained hardware; thus, their designs fundamentally emphasize performance and discount security. This article presents a vision for how small steps using existing technologies can be combined into one giant leap for computer security.
Cyber-physical systems (CPSs) are increasingly targeted in highprofile cyber attacks. Examples of such attacks include Stuxnet, which targeted nuclear centrifuges; Crashoverride, and Triton, which targeted power grids; and the Mirai botnet, which targeted internet-of-things (IoT) devices such as cameras to carry out a large-scale distributed denial-of-service (DDoS) attack. Such attacks demonstrate the importance of securing current and future cyber-physical systems. Therefore, next-generation operating systems (OSes) for CPS need to be designed to provide security features necessary, as well as be secure in and of themselves. CPSs are designed with one of three broad classes of OSes: (a) bare-metal applications with effectively no operating system, (b) embedded systems executing on impoverished platforms running an embedded or real-time operating system (RTOS) such as FreeRTOS, or (c) more performant platforms running generalpurpose OSes such as Linux, sometimes tuned for real-time performance such as through the PREEMPT_RT patch. In cases (a) and (b), the OS, if any, is very minimal to facilitate improved resource utilization in real-time or latency-sensitive applications, especially running on impoverished hardware platforms. In such OSes, security is often overlooked, and many important security features (e.g. process/kernel memory isolation) are notably absent. In case (c), the general-purpose OS inherits many of the security-related features that are critical in enterprise and generalpurpose applications, such as virtual memory and address-space layout randomization (ASLR). However, the highly complex nature of general-purpose OSes can be problematic in the development of CPSs, as they are highly non-deterministic and difficult to formally reason about for cyber-physical applications, which often have real-time constraints. These issues motivate the need for a next generation OS that is highly capable, predictable and deterministic for real-time performance, but also secure in the face of many of the next generation of cyber threats. In order to design such a next-generation OS, it is necessary to first reflect on the types of threats that CPSs face, including the attacker intentions and types of effects that can be achieved, as well as the type of access that attackers have. While threat models are not the same for all CPSs, it is important to understand how the threat models for CPSs compare to general-purpose or enterprise computing environments. We discuss these issues next (Sec. 2),
Control-Flow Hijacking attacks are the dominant attack vector against C/C++ programs. Control-Flow Integrity (CFI) solutions mitigate these attacks on the forward edge, i.e., indirect calls through function pointers and virtual calls. Protecting the backward edge is left to stack canaries, which are easily bypassed through information leaks. Shadow Stacks are a fully precise mechanism for protecting backwards edges, and should be deployed with CFI mitigations. We present a comprehensive analysis of all possible shadow stack mechanisms along three axes: performance, compatibility, and security. For performance comparisons we use SPEC CPU2006, while security and compatibility are qualitatively analyzed. Based on our study, we renew calls for a shadow stack design that leverages a dedicated register, resulting in low performance overhead, and minimal memory overhead, but sacrifices compatibility. We present case studies of our implementation of such a design, Shadesmar, on Phoronix and Apache to demonstrate the feasibility of dedicating a general purpose register to a security monitor on modern architectures, and Shadesmar's deployability. Our comprehensive analysis, including detailed case studies for our novel design, allows compiler designers and practitioners to select the correct shadow stack design for different usage scenarios. Shadow stacks belong to the class of defense mechanisms that require metadata about the program's state to enforce their defense policies. Protecting this metadata for deployed mitigations requires in-process isolation of a segment of the virtual address space. Prior work on defenses in this class has relied on information hiding to protect metadata. We show that stronger guarantees are possible by repurposing two new Intel x86 extensions for memory protection (MPX), and page table control (MPK). Building on our isolation efforts with MPX and MPK, we present the design requirements for a dedicated hardware mechanism to support intra-process memory isolation, and discuss how such a mechanism can empower the next wave of highly precise software security mitigations that rely on partially isolated information in a process.
When reverse engineering a binary, the analyst must first understand the semantics of the binary's functions through either manual or automatic analysis. Manual semantic analysis is time-consuming, because abstractions provided by high level languages, such as type information, variable scope, or comments are lost, and past analyses cannot apply to the current analysis task. Existing automated binary analysis tools currently suffer from low accuracy in determining semantic function identification in the presence of diverse compilation environments. We introduce Software Ethology, a binary analysis approach for determining the semantic similarity of functions. Software Ethology abstracts semantic behavior as classification vectors of program state changes resulting from a function executing with a specified input state, and uses these vectors as a unique fingerprint for identification. All existing semantic identifiers determine function similarity via code measurements, and suffer from high inaccuracy when classifying functions from compilation environments different from their ground truth source. Since Software Ethology does not rely on code measurements, its accuracy is resilient to changes in compiler, compiler version, optimization level, or even different source implementing equivalent functionality. Tinbergen, our prototype Software Ethology implementation, leverages a virtual execution environment and a fuzzer to generate the classification vectors. In evaluating Tinbergen's feasibility as a semantic function identifier by identifying functions in coreutils-8.30, we achieve a high .805 average accuracy. Compared to the state-of-the-art, Tinbergen is 1.5 orders of magnitude faster when training, 50% faster in answering queries, and, when identifying functions in binaries generated from differing compilation environments, is 30%-61% more accurate.
C++ relies on object type information for dynamic dispatch and casting. The association of type information to an object is implemented via the virtual table pointer, which is stored in the object itself. As C++ has neither memory nor type safety, adversaries may therefore overwrite an object’s type. If the corrupted type is used for dynamic dispatch, the attacker has hijacked the application’s control flow. This vulnerability is widespread and commonly exploited. Firefox, Chrome, and other major C++ applications are network facing, commonly attacked, and make significant use of dynamic dispatch. ControlFlow Integrity (CFI) is the state of the art policy for efficient mitigation of control-flow hijacking attacks. CFI mechanisms determine statically (i.e., at compile time) the set of functions that are valid at a given call site, based on C++ semantics. We propose an orthogonal policy, Object Type Integrity (OTI), that dynamically tracks object types. Consequently, instead of allowing a set of targets for each dynamic dispatch on an object, only the single, correct target for the object’s type is allowed. To show the efficacy of OTI, we present CFIXX, which enforces OTI. CFIXX enforces OTI by dynamically tracking the type of each object and enforcing its integrity against arbitrary writes. CFIXX has minimal overhead on CPU bound applications such as SPEC CPU2006 — 4.98%. On key applications like Chromium, CFIXX has negligible overhead on JavaScript benchmarks: 2.03% on Octane, 1.99% on Kraken, and 2.80% on JetStream. We show that CFIXX can be deployed in conjunction with CFI, providing a significant security improvement.